diff --git a/Makefile b/Makefile index fbac8db..3158861 100755 --- a/Makefile +++ b/Makefile @@ -79,8 +79,6 @@ else endif CPPFLAGS += -DHAVE_CEIL -DCP_USE_CGTYPES=0 -DCP_USE_DOUBLES=0 -DHAVE_FLOOR -DHAVE_FMOD -DHAVE_LRINT -DHAVE_LRINTF $(includeflag) -MD $(WARNING_FLAGS) -I. -DVER=\"$(SEM)\" -DCOM=\"$(COM)\" -DINFO=\"$(INFO)\" #-DENABLE_SINC_MEDIUM_CONVERTER -DENABLE_SINC_FAST_CONVERTER -DCP_COLLISION_TYPE_TYPE=uintptr_t -DCP_BITMASK_TYPE=uintptr_t - -CPPFLAGS += -D_FILE_OFFSET_BITS=64 # for tinycdb CPPFLAGS += -DCONFIG_VERSION=\"2024-02-14\" -DCONFIG_BIGNUM #for quickjs # ENABLE_SINC_[BEST|FAST|MEDIUM]_CONVERTER @@ -149,14 +147,17 @@ endif OBJS != find source -type f -name '*.c' | grep -vE 'test|tool|example|fuzz|main' | grep -vE 'quickjs' CPPOBJS != find source -type f -name '*.cpp' | grep -vE 'test|tool|example|fuzz|main' OBJS += $(CPPOBJS) +OBJS += source/engine/yugine.c OBJS += $(shell find source/engine -type f -name '*.m') +QUICKJS := source/engine/thirdparty/quickjs +OBJS += $(addprefix $(QUICKJS)/, libregexp.c quickjs.c libunicode.c cutils.c libbf.c) OBJS := $(patsubst %.cpp, %$(INFO).o, $(OBJS)) OBJS := $(patsubst %.c, %$(INFO).o,$(OBJS)) OBJS := $(patsubst %.m, %$(INFO).o, $(OBJS)) engineincs != find source/engine -maxdepth 1 -type d includeflag != find source -type d -name include -includeflag += $(engineincs) source/engine/thirdparty/tinycdb source/shaders source/engine/thirdparty/sokol source/engine/thirdparty/stb source/engine/thirdparty/cgltf source/engine/thirdparty/TinySoundFont source/engine/thirdparty/dr_libs +includeflag += $(engineincs) source/shaders source/engine/thirdparty/sokol source/engine/thirdparty/stb source/engine/thirdparty/cgltf source/engine/thirdparty/TinySoundFont source/engine/thirdparty/dr_libs includeflag += $(STEAM)/public includeflag += source includeflag := $(addprefix -I, $(includeflag)) @@ -188,20 +189,12 @@ install: $(NAME) @echo Copying to destination cp -f $(NAME) $(DESTDIR)/$(APP) -$(NAME): libengine$(INFO).a libquickjs$(INFO).a $(DEPS) +$(NAME): $(OBJS) $(DEPS) @echo Linking $(NAME) $(CROSSWIN)$(LD) $^ $(CPPFLAGS) $(LDFLAGS) -L. $(LDPATHS) $(LDLIBS) -o $@ @echo Finished build -libengine$(INFO).a: $(OBJS) - @echo Archiving $@ - $(CROSSWIN)$(AR) rcs $@ $(OBJS) - -QUICKJS := source/engine/thirdparty/quickjs -libquickjs$(INFO).a: $(QUICKJS)/libregexp$(INFO).o $(QUICKJS)/quickjs$(INFO).o $(QUICKJS)/libunicode$(INFO).o $(QUICKJS)/cutils$(INFO).o $(QUICKJS)/libbf$(INFO).o - $(CROSSWIN)$(AR) rcs $@ $^ - -%$(INFO).o: %.c $(SHADERS) +%$(INFO).o: %.c source/engine/core.cdb.h $(SHADERS) @echo Making C object $@ $(CROSSWIN)$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ @@ -224,38 +217,18 @@ SCRIPTS := $(shell ls scripts/*.js*) CORE != (ls icons/* fonts/*) CORE := $(CORE) $(SCRIPTS) -CDB = source/engine/thirdparty/tinycdb -CDB_C != find $(CDB) -name *.c -CDB_O := $(patsubst %.c, %.o, $(CDB_C)) -CDB_O := $(notdir $(CDB_O)) -tools/libcdb.a: $(CDB_C) - cc -c $^ - $(CROSSWIN)$(AR) rcs $@ $(CDB_O) - -cdb: tools/cdb.c tools/libcdb.a - @echo Making cdb - cc $^ -I$(CDB) -o cdb - -packer: tools/packer.c tools/libcdb.a +packer$(EXT): tools/packer.c source/engine/miniz.c @echo Making packer - cc $^ -I$(CDB) -o packer + $(CC) -O2 $^ -Isource/engine -o packer -core.cdb: packer $(CORE) +core.cdb: packer$(EXT) $(CORE) @echo Packing core.cdb - ./packer $(CORE) - chmod 644 out.cdb - mv out.cdb core.cdb + ./packer$(EXT) $@ $(CORE) source/engine/core.cdb.h: core.cdb @echo Making $@ xxd -i $< > $@ -jsc: tools/jso.c tools/libquickjs.a - $(CC) $^ -lm -Iquickjs -o $@ - -tools/libquickjs.a: $(BIN)/libquickjs.a - cp -f $(BIN)/libquickjs.a tools - ICNSIZE = 16 32 128 256 512 1024 ICNNAME := $(addsuffix .png, $(ICNSIZE)) ICON = icons/moon.gif diff --git a/scripts/engine.js b/scripts/engine.js index c7ee874..256a1f5 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -115,8 +115,6 @@ console.trace = console.stack; var say = console.say; var print = console.print; -console.warn("GOT HERE"); - console.doc = { level: "Set level to output logging to console.", info: "Output info level message.", @@ -143,7 +141,7 @@ function use(file, env, script) console.info(`CACHE eval ${file} in ${profile.best_t(profile.now()-st)}`); return; } - + console.info(`slurping ${file}`); script ??= io.slurp(file); script = `(function() { ${script}; })`; var fn = os.eval(file,script); @@ -208,6 +206,7 @@ var timescale = 1; var gggstart = game.engine_start; game.engine_start = function(s) { + game.startengine = 1; gggstart(function() { world_start(); go_init(); @@ -216,6 +215,8 @@ game.engine_start = function(s) { }, process); } +game.startengine = 0; + function process() { var dt = profile.secs(profile.now()) - frame_t; diff --git a/scripts/std.js b/scripts/std.js index 6e05414..f25ac55 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -278,7 +278,6 @@ Cmdline.register_order("play", function(argv) { console.info(`Starting game with window size ${window.size} and render ${window.rendersize}.`); game.engine_start(function() { - console.info(`eng start`); global.mixin("scripts/sound.js"); global.app = actor.spawn("game.js"); if (project.icon) window.set_icon(project.icon); @@ -297,7 +296,7 @@ Cmdline.register_order("pack", function(str) { say(`Packing into ${packname}`); - io.pack_engine(packname); +// io.pack_engine(packname); io.chmod(packname, 666); }, "Pack the game into the given name.", "NAME"); @@ -477,8 +476,10 @@ function cmd_args(cmdargs) console.warn(`Command ${cmds[0]} not found.`); return; } - + Cmdline.orders[cmds[0]](cmds.slice(1)); + if (!game.startengine) + os.exit(0); } Cmdline.register_order("clean", function(argv) { diff --git a/source/engine/config.c b/source/engine/config.c index c420ab9..665da42 100644 --- a/source/engine/config.c +++ b/source/engine/config.c @@ -2,7 +2,6 @@ #define SOKOL_TRACE_HOOKS #define SOKOL_IMPL -#define SOKOL_NO_ENTRY #include "sokol/sokol_audio.h" #include "sokol/sokol_time.h" #include "sokol/sokol_args.h" diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index d3e7adb..f4559b1 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -644,6 +644,7 @@ JSValue js_os_sys(JSContext *js, JSValue this, int argc, JSValue *argv) } JSC_CCALL(os_quit, quit();) +JSC_CCALL(os_exit, exit(js2number(argv[0]));) JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space)); JSC_CCALL(os_gc, script_gc()); JSC_SSCALL(os_eval, ret = script_eval(str, str2)) @@ -712,6 +713,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, sys, 0), MIST_FUNC_DEF(os, system, 1), MIST_FUNC_DEF(os, quit, 0), + MIST_FUNC_DEF(os, exit, 1), MIST_FUNC_DEF(os, reindex_static, 0), MIST_FUNC_DEF(os, gc, 0), MIST_FUNC_DEF(os, capture, 5), @@ -1007,8 +1009,6 @@ JSValue js_io_chmod(JSContext *js, JSValue this, int argc, JSValue *argv) JSC_SCALL(io_save_qoa, save_qoa(str)) -JSC_SCALL(io_pack_engine, pack_engine(str)) - static const JSCFunctionListEntry js_io_funcs[] = { MIST_FUNC_DEF(io, exists,1), MIST_FUNC_DEF(io, ls, 0), @@ -1022,7 +1022,6 @@ static const JSCFunctionListEntry js_io_funcs[] = { MIST_FUNC_DEF(io, slurpbytes, 1), MIST_FUNC_DEF(io, slurpwrite, 2), MIST_FUNC_DEF(io, save_qoa,1), - MIST_FUNC_DEF(io, pack_engine, 1), }; JSC_CCALL(debug_draw_gameobject, gameobject_draw_debug(js2gameobject(argv[0]));) diff --git a/source/engine/miniz.c b/source/engine/miniz.c new file mode 100644 index 0000000..8d0032f --- /dev/null +++ b/source/engine/miniz.c @@ -0,0 +1,7833 @@ +#include "miniz.h" +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT HOLDERS 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. + * + **************************************************************************/ + + + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API's */ + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +#if 0 + mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) + { + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) + return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) + { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; + } +#elif defined(USE_EXTERNAL_MZCRC) +/* If USE_EXTERNAL_CRC is defined, an external module will export the + * mz_crc32() symbol for us to use, e.g. an SSE-accelerated version. + * Depending on the impl, it may be necessary to ~ the input/output crc values. + */ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len); +#else +/* Faster, but larger CPU cache footprint. + */ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, + 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, + 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, + 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, + 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, + 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, + 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, + 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, + 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, + 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, + 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, + 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, + 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, + 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, + 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, + 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, + 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, + 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; + const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; + + while (buf_len >= 4) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; + pByte_buf += 4; + buf_len -= 4; + } + + while (buf_len) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + ++pByte_buf; + --buf_len; + } + + return ~crc32; +} +#endif + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) +{ + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} +MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +{ + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); +} + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +#ifndef MINIZ_NO_DEFLATE_APIS + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; /* Can't make forward progress without some input. + */ + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) + return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + +#ifndef MINIZ_NO_INFLATE_APIS + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflateReset(mz_streamp pStream) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + + pDecomp = (inflate_state *)pStream->state; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + /* pDecomp->m_window_bits = window_bits */; + + return MZ_OK; +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for (;;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} +int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong *pSource_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)*pSource_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + *pSource_len = *pSource_len - stream.avail_in; + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_uncompress2(pDest, pDest_len, pSource, &source_len); +} + +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +const char *mz_error(int err) +{ + static struct + { + int m_err; + const char *m_pDesc; + } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) + return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif /*MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + +/* + 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. + + For more information, please refer to +*/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT HOLDERS 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. + * + **************************************************************************/ + + + +#ifndef MINIZ_NO_DEFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Compression (independent from all decompression API's) */ + +/* Purposely making these tables static for faster init and thread safety. */ +static const mz_uint16 s_tdefl_len_sym[256] = + { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + +static const mz_uint8 s_tdefl_len_extra[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = + { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = + { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + +/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_ARR(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +/* Limits canonical Huffman code table's max code size. */ +enum +{ + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 +}; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_ARR(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_ARR(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do \ + { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) \ + { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) \ + { \ + if (rle_repeat_count < 3) \ + { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } \ + else \ + { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) \ + { \ + if (rle_z_count < 3) \ + { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } \ + else if (rle_z_count <= 10) \ + { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } \ + else \ + { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0]; + mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64)); + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static const mz_uint s_tdefl_num_probes[11]; + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + const mz_uint8 cmf = 0x78; + mz_uint8 flg, flevel = 3; + mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint); + + /* Determine compression level by reversing the process in tdefl_create_comp_flags_from_zip_params() */ + for (i = 0; i < mz_un; i++) + if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF)) break; + + if (i < 2) + flevel = 0; + else if (i < 6) + flevel = 1; + else if (i == 6) + flevel = 2; + + header = cmf << 8 | (flevel << 6); + header += 31 - (header % 31); + flg = header & 0xFF; + + TDEFL_PUT_BITS(cmf, 8); + TDEFL_PUT_BITS(flg, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) + { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) +#endif +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) + continue; + p = s; + probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p) +{ + mz_uint32 ret; + memcpy(&ret, p, sizeof(mz_uint32)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) +#endif +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +#ifdef MINIZ_UNALIGNED_USE_MEMCPY + memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); +#else + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +#endif + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + /* Simple lazy/greedy parsing state machine. */ + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + /* Move the lookahead forward by len_to_move bytes. */ + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + /* Check if it's time to flush the current LZ codes to the internal output buffer. */ + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_ARR(d->m_hash); + MZ_CLEAR_ARR(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_ARR(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + *d->m_pLZ_flags = 0; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_ARR(d->m_dict); + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) + return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) + return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) + return MZ_FALSE; + do + { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) + return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) + return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ +#endif + +/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +{ + /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ + static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) + return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) + { + MZ_FREE(pComp); + return NULL; + } + /* write dummy header */ + for (z = 41; z; --z) + tdefl_output_buffer_putter(&z, 1, &out_buf); + /* compress image data */ + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) + { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) + { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + /* write real header */ + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; + mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, + 0x0a, 0x1a, 0x0a, 0x00, 0x00, + 0x00, 0x0d, 0x49, 0x48, 0x44, + 0x52, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x44, 0x41, + 0x54 }; + pnghdr[18] = (mz_uint8)(w >> 8); + pnghdr[19] = (mz_uint8)w; + pnghdr[22] = (mz_uint8)(h >> 8); + pnghdr[23] = (mz_uint8)h; + pnghdr[25] = chans[num_chans]; + pnghdr[33] = (mz_uint8)(*pLen_out >> 24); + pnghdr[34] = (mz_uint8)(*pLen_out >> 16); + pnghdr[35] = (mz_uint8)(*pLen_out >> 8); + pnghdr[36] = (mz_uint8)*pLen_out; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + /* write footer (IDAT CRC-32, followed by IEND chunk) */ + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) + { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + /* compute final size of file, grab compressed data buffer and return */ + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +} + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ +/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tdefl_compressor *tdefl_compressor_alloc(void) +{ + return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +} + +void tdefl_compressor_free(tdefl_compressor *pComp) +{ + MZ_FREE(pComp); +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + /************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT HOLDERS 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. + * + **************************************************************************/ + + + +#ifndef MINIZ_NO_INFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Decompression (completely independent from all compression API's) */ + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) \ + { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do \ + { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do \ + { \ + for (;;) \ + { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +#define TINFL_GET_BYTE(state_index, c) \ + do \ + { \ + while (pIn_buf_cur >= pIn_buf_end) \ + { \ + TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ + } \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do \ + { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree) \ + do \ + { \ + temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) \ + { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } \ + else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ +/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ +#define TINFL_HUFF_DECODE(state_index, sym, pLookUp, pTree) \ + do \ + { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) \ + { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) \ + { \ + TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree); \ + } \ + else \ + { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +static void tinfl_clear_tree(tinfl_decompressor *r) +{ + if (r->m_type == 0) + MZ_CLEAR_ARR(r->m_tree_0); + else if (r->m_type == 1) + MZ_CLEAR_ARR(r->m_tree_1); + else + MZ_CLEAR_ARR(r->m_tree_2); +} + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; + static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; + + mz_int16 *pTrees[3]; + mz_uint8 *pCode_sizes[3]; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next ? pOut_buf_next + *pOut_buf_size : NULL; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + pTrees[0] = r->m_tree_0; + pTrees[1] = r->m_tree_1; + pTrees[2] = r->m_tree_2; + pCode_sizes[0] = r->m_code_size_0; + pCode_sizes[1] = r->m_code_size_1; + pCode_sizes[2] = r->m_code_size_2; + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)((size_t)1 << (8U + (r->m_zhdr0 >> 4))))); + if (counter) + { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) + { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) + { + TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_code_size_0; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_code_size_1, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_ARR(r->m_code_size_2); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_code_size_2[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; + mz_int16 *pLookUp; + mz_int16 *pTree; + mz_uint8 *pCode_size; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pLookUp = r->m_look_up[r->m_type]; + pTree = pTrees[r->m_type]; + pCode_size = pCode_sizes[r->m_type]; + MZ_CLEAR_ARR(total_syms); + TINFL_MEMSET(pLookUp, 0, sizeof(r->m_look_up[0])); + tinfl_clear_tree(r); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pCode_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pCode_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pLookUp[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTree[-tree_cur - 1]) + { + pTree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else + tree_cur = pTree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, r->m_look_up[2], r->m_tree_2); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_code_size_0, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_code_size_1, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (;;) + { + mz_uint8 *pSrc; + for (;;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, r->m_look_up[0], r->m_tree_0); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) + break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, r->m_look_up[1], r->m_tree_1); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist == 0 || dist > dist_from_out_buf_start || dist_from_out_buf_start == 0) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { +#ifdef MINIZ_UNALIGNED_USE_MEMCPY + memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2); +#else + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; +#endif + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + while(counter>2) + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + counter -= 3; + } + if (counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + + /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ + TINFL_SKIP_BITS(32, num_bits & 7); + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits); + MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ + + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + + TINFL_CR_FINISH + +common_exit: + /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ + /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ + if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) + { + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + } + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf & ~(~(tinfl_bit_buf_t)0 << num_bits); + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Higher level helper functions. */ +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) + break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) + new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + memset(pDict,0,TINFL_LZ_DICT_SIZE); + tinfl_init(&decomp); + for (;;) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +#ifndef MINIZ_NO_MALLOC +tinfl_decompressor *tinfl_decompressor_alloc(void) +{ + tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); + if (pDecomp) + tinfl_init(pDecomp); + return pDecomp; +} + +void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +{ + MZ_FREE(pDecomp); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + /************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT HOLDERS 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. + * + **************************************************************************/ + + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- .ZIP archive reading */ + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) + +#define WIN32_LEAN_AND_MEAN +#include + +static WCHAR* mz_utf8z_to_widechar(const char* str) +{ + int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + WCHAR* wStr = (WCHAR*)malloc(reqChars * sizeof(WCHAR)); + MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, reqChars); + return wStr; +} + +static FILE *mz_fopen(const char *pFilename, const char *pMode) +{ + WCHAR* wFilename = mz_utf8z_to_widechar(pFilename); + WCHAR* wMode = mz_utf8z_to_widechar(pMode); + FILE* pFile = NULL; + errno_t err = _wfopen_s(&pFile, wFilename, wMode); + free(wFilename); + free(wMode); + return err ? NULL : pFile; +} + +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +{ + WCHAR* wPath = mz_utf8z_to_widechar(pPath); + WCHAR* wMode = mz_utf8z_to_widechar(pMode); + FILE* pFile = NULL; + errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream); + free(wPath); + free(wMode); + return err ? NULL : pFile; +} + +static int mz_stat64(const char *path, struct __stat64 *buffer) +{ + WCHAR* wPath = mz_utf8z_to_widechar(path); + int res = _wstat64(wPath, buffer); + free(wPath); + return res; +} + +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat64 +#define MZ_FILE_STAT mz_stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove + +#elif defined(__MINGW32__) || defined(__WATCOMC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove + +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove + +#elif defined(__USE_LARGEFILE64) /* gcc, clang */ +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove + +#elif defined(__APPLE__) || defined(__FreeBSD__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen(p, m, s) +#define MZ_DELETE_FILE remove + +#else +#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#ifdef __STRICT_ANSI__ +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#else +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#endif +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif /* #ifdef _MSC_VER */ +#endif /* #ifdef MINIZ_NO_STDIO */ + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +enum +{ + /* ZIP archive identifiers and record sizes */ + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + + /* ZIP64 archive identifier and record sizes */ + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, + MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, + MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, + MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, + MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, + + /* Central directory header record offsets */ + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + + /* Local directory header offsets */ + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, + + /* End of central directory offsets */ + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + + /* ZIP64 End of central directory locator offsets */ + MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ + + /* ZIP64 End of central directory header offsets */ + MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ + MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, + MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + + /* The flags passed in when the archive is initially opened. */ + mz_uint32 m_init_flags; + + /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ + mz_bool m_zip64; + + /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ + mz_bool m_zip64_has_extended_info_fields; + + /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ + MZ_FILE *m_pFile; + mz_uint64 m_file_archive_start_ofs; + + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +#if defined(DEBUG) || defined(_DEBUG) +static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +{ + MZ_ASSERT(index < pArray->m_size); + return index; +} +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +#else +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +#endif + +static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +{ + memset(pArray, 0, sizeof(mz_zip_array)); + pArray->m_element_size = element_size; +} + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) + return MZ_TRUE; + if (growing) + { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) + new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + if (n > 0) + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) + { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifndef MINIZ_NO_STDIO +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +{ + struct MZ_FILE_STAT_STRUCT file_stat; + + /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) + return MZ_FALSE; + + *pTime = file_stat.st_mtime; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +{ + struct utimbuf t; + + memset(&t, 0, sizeof(t)); + t.actime = access_time; + t.modtime = modified_time; + + return !utime(pFilename, &t); +} +#endif /* #ifndef MINIZ_NO_STDIO */ +#endif /* #ifndef MINIZ_NO_TIME */ + +static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + if (pZip) + pZip->m_last_error = err_num; + return MZ_FALSE; +} + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + pZip->m_last_error = MZ_ZIP_NO_ERROR; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + pZip->m_pState->m_init_flags = flags; + pZip->m_pState->m_zip64 = MZ_FALSE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do \ + { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices; + mz_uint32 start, end; + const mz_uint32 size = pZip->m_total_files; + + if (size <= 1U) + return; + + pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + + start = (size - 2U) >> 1U; + for (;;) + { + mz_uint64 child, root = start; + for (;;) + { + if ((child = (root << 1U) + 1U) >= size) + break; + child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + if (!start) + break; + start--; + } + + end = size - 1; + while (end > 0) + { + mz_uint64 child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) + { + if ((child = (root << 1U) + 1U) >= end) + break; + child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +{ + mz_int64 cur_file_ofs; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + + /* Basic sanity checks - reject files which are too small */ + if (pZip->m_archive_size < record_size) + return MZ_FALSE; + + /* Find the record by scanning the file from the end towards the beginning. */ + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + + for (i = n - 4; i >= 0; --i) + { + mz_uint s = MZ_READ_LE32(pBuf + i); + if (s == record_sig) + { + if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) + break; + } + } + + if (i >= 0) + { + cur_file_ofs += i; + break; + } + + /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) + return MZ_FALSE; + + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + + *pOfs = cur_file_ofs; + return MZ_TRUE; +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +{ + mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; + mz_uint64 cdir_ofs = 0; + mz_int64 cur_file_ofs = 0; + const mz_uint8 *p; + + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + + mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + + mz_uint64 zip64_end_of_central_dir_ofs = 0; + + /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) + return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + + /* Read and verify the end of central directory record. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + { + if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) + { + zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); + if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) + { + pZip->m_pState->m_zip64 = MZ_TRUE; + } + } + } + } + } + + pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); + cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + + if (pZip->m_pState->m_zip64) + { + mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); + mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); + mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); + mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + + if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (zip64_total_num_of_disks != 1U) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + /* Check for miniz's practical limits */ + if (zip64_cdir_total_entries > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + + if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + + /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ + if (zip64_size_of_central_directory > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + cdir_size = (mz_uint32)zip64_size_of_central_directory; + + num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + + cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + + cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); + } + + if (pZip->m_total_files != cdir_entries_on_this_disk) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (cdir_size < (mz_uint64)pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) + { + mz_uint i, n; + /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (sort_central_dir) + { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + /* Now create an index into the central directory file records, do some basic sanity checking on each record */ + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; + mz_uint64 comp_size, decomp_size, local_header_ofs; + + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && + (ext_data_size) && + (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = ext_data_size; + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data; + void* buf = NULL; + + if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n) + { + buf = MZ_MALLOC(ext_data_size); + if(buf==NULL) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (mz_uint8*)buf; + } + else + { + pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + } + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ + pZip->m_pState->m_zip64 = MZ_TRUE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + + MZ_FREE(buf); + } + } + + /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ + if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) + { + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (comp_size != MZ_UINT32_MAX) + { + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +void mz_zip_zero_struct(mz_zip_archive *pZip) +{ + if (pZip) + MZ_CLEAR_PTR(pZip); +} + +static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_bool status = MZ_TRUE; + + if (!pZip) + return MZ_FALSE; + + if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + + return MZ_FALSE; + } + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; + status = MZ_FALSE; + } + } + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return status; +} + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + return mz_zip_reader_end_internal(pZip, MZ_TRUE); +} +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_archive_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +{ + if (!pMem) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pNeeds_keepalive = NULL; + +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + + pZip->m_pState->m_mem_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +} + +mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +{ + mz_uint64 file_size; + MZ_FILE *pFile; + + if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + file_size = archive_size; + if (!file_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + } + + file_size = MZ_FTELL64(pFile); + } + + /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + + if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +{ + mz_uint64 cur_file_ofs; + + if ((!pZip) || (!pFile)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + cur_file_ofs = MZ_FTELL64(pFile); + + if (!archive_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + + archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + + if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = archive_size; + pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +} + +mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint bit_flag; + mz_uint method; + + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); + bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + + if ((method != 0) && (method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + return MZ_FALSE; + } + + if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + return MZ_FALSE; + } + + if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, attribute_mapping_id, external_attr; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ + attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; + (void)attribute_mapping_id; + + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) + { + return MZ_TRUE; + } + + return MZ_FALSE; +} + +static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +{ + mz_uint n; + const mz_uint8 *p = pCentral_dir_header; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_FALSE; + + if ((!p) || (!pStat)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Extract fields from the central directory record. */ + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + /* Copy as much of the filename and comment as possible. */ + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); + pStat->m_comment[n] = '\0'; + + /* Set some flags for convienance */ + pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); + pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); + pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); + + /* See if we need to read any zip64 extended information fields. */ + /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ + if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; + mz_uint32 field_data_remaining = field_data_size; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_TRUE; + + if (pStat->m_uncomp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_uncomp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_comp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_comp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_local_header_ofs == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + } + } + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const mz_uint32 size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + + if (pIndex) + *pIndex = 0; + + if (size) + { + /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ + /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ + mz_int64 l = 0, h = (mz_int64)size - 1; + + while (l <= h) + { + mz_int64 m = l + ((h - l) >> 1); + mz_uint32 file_index = pIndices[(mz_uint32)m]; + + int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint32 index; + if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) + return -1; + else + return (int)index; +} + +mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +{ + mz_uint file_index; + size_t name_len, comment_len; + + if (pIndex) + *pIndex = 0; + + if ((!pZip) || (!pZip->m_pState) || (!pName)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* See if we can use a binary search */ + if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && + (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && + ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + { + return mz_zip_locate_file_binary_search(pZip, pName, pIndex); + } + + /* Locate the entry by scanning the entire central directory */ + name_len = strlen(pName); + if (name_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +static +mz_bool mz_zip_reader_extract_to_mem_no_alloc1(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size, const mz_zip_archive_file_stat *st) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (st) { + file_stat = *st; + } else + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Ensure supplied output buffer is large enough. */ + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + + /* Read and parse the local directory entry. */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) + { + if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + } +#endif + + return MZ_TRUE; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + /* Read directly from the archive in memory. */ + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + /* Use a user provided read buffer. */ + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + else + { + /* Temporarily allocate a read buffer. */ + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size, NULL); +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size, NULL); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, NULL, 0, NULL); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + mz_uint64 alloc_size; + void *pBuf; + + if (pSize) + *pSize = 0; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return NULL; + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + return NULL; + } + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + if (!mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, (size_t)alloc_size, flags, NULL, 0, &file_stat)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) + *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + { + if (pSize) + *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint file_crc32 = MZ_CRC32_INIT; +#endif + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pState->m_pMem) + { + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + } + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +#endif + } + + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + } +#endif + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + status = TINFL_STATUS_FAILED; + } + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +#endif + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (file_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_reader_extract_iter_state *pState; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + /* Argument sanity check */ + if ((!pZip) || (!pZip->m_pState)) + return NULL; + + /* Allocate an iterator status structure */ + pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); + if (!pState) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + /* Fetch file details */ + if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Encryption and patch files are not supported. */ + if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Init state - save args */ + pState->pZip = pZip; + pState->flags = flags; + + /* Init state - reset variables to defaults */ + pState->status = TINFL_STATUS_DONE; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + pState->file_crc32 = MZ_CRC32_INIT; +#endif + pState->read_buf_ofs = 0; + pState->out_buf_ofs = 0; + pState->pRead_buf = NULL; + pState->pWrite_buf = NULL; + pState->out_blk_remain = 0; + + /* Read and parse the local directory entry. */ + pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; + pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + else + { + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, therefore intermediate read buffer required */ + pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + else + { + /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ + pState->read_buf_size = 0; + } + pState->read_buf_avail = 0; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, init decompressor */ + tinfl_init( &pState->inflator ); + + /* Allocate write buffer */ + if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + if (pState->pRead_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + + return pState; +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_uint32 file_index; + + /* Locate file index by name */ + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return NULL; + + /* Construct iterator */ + return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +} + +size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +{ + size_t copied_to_caller = 0; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) + return 0; + + if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data, calc amount to return. */ + copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining ); + + /* Zip is in memory....or requires reading from a file? */ + if (pState->pZip->m_pState->m_pMem) + { + /* Copy data to caller's buffer */ + memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); + pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; + } + else + { + /* Read directly into caller's buffer */ + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) + { + /* Failed to read all that was asked for, flag failure and alert user */ + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + copied_to_caller = 0; + } + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Compute CRC if not returning compressed data only */ + if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +#endif + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += copied_to_caller; + pState->out_buf_ofs += copied_to_caller; + pState->comp_remaining -= copied_to_caller; + } + else + { + do + { + /* Calc ptr to write buffer - given current output pos and block size */ + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + /* Calc max output size - given current output pos and block size */ + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + if (!pState->out_blk_remain) + { + /* Read more data from file if none available (and reading from file) */ + if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) + { + /* Calc read size */ + pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += pState->read_buf_avail; + pState->comp_remaining -= pState->read_buf_avail; + pState->read_buf_ofs = 0; + } + + /* Perform decompression */ + in_buf_size = (size_t)pState->read_buf_avail; + pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + pState->read_buf_avail -= in_buf_size; + pState->read_buf_ofs += in_buf_size; + + /* Update current output block size remaining */ + pState->out_blk_remain = out_buf_size; + } + + if (pState->out_blk_remain) + { + /* Calc amount to return. */ + size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + + /* Copy data to caller's buffer */ + memcpy( (mz_uint8*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Perform CRC */ + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +#endif + + /* Decrement data consumed from block */ + pState->out_blk_remain -= to_copy; + + /* Inc output offset, while performing sanity check */ + if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Increment counter of data copied to caller */ + copied_to_caller += to_copy; + } + } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); + } + + /* Return how many bytes were copied into user buffer */ + return copied_to_caller; +} + +mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +{ + int status; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) + return MZ_FALSE; + + /* Was decompression completed and requested? */ + if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + pState->status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (pState->file_crc32 != pState->file_stat.m_crc32) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + } +#endif + } + + /* Free buffers */ + if (!pState->pZip->m_pState->m_pMem) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); + if (pState->pWrite_buf) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + + /* Save status */ + status = pState->status; + + /* Free context */ + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + + return status == TINFL_STATUS_DONE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; + + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + + if (MZ_FCLOSE(pFile) == EOF) + { + if (status) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + + status = MZ_FALSE; + } + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + + return status; +} + +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} + +mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +} + +mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_uint32 *p = (mz_uint32 *)pOpaque; + (void)file_ofs; + *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); + return n; +} + +mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + mz_zip_internal_state *pState; + const mz_uint8 *pCentral_dir_header; + mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint64 local_header_ofs = 0; + mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; + mz_bool has_data_descriptor; + mz_uint32 local_header_bit_flags; + + mz_zip_array file_data_array; + mz_zip_array_init(&file_data_array, 1); + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (file_index > pZip->m_total_files) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); + + if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_is_encrypted) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports stored and deflate. */ + if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + if (!file_stat.m_is_supported) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + /* Read and parse the local directory entry. */ + local_header_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); + local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + has_data_descriptor = (local_header_bit_flags & 8) != 0; + + if (local_header_filename_len != strlen(file_stat.m_filename)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + goto handle_failure; + } + + if (local_header_filename_len) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ + if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_uint32 extra_size_remaining = local_header_extra_len; + const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ + /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ + if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) + { + mz_uint8 descriptor_buf[32]; + mz_bool has_id; + const mz_uint8 *pSrc; + mz_uint32 file_crc32; + mz_uint64 comp_size = 0, uncomp_size = 0; + + mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; + + file_crc32 = MZ_READ_LE32(pSrc); + + if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); + } + else + { + comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); + } + + if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + else + { + if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + mz_zip_array_clear(pZip, &file_data_array); + + if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) + { + if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) + return MZ_FALSE; + + /* 1 more check to be sure, although the extract checks too. */ + if (uncomp_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + return MZ_FALSE; + } + } + + return MZ_TRUE; + +handle_failure: + mz_zip_array_clear(pZip, &file_data_array); + return MZ_FALSE; +} + +mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) +{ + mz_zip_internal_state *pState; + mz_uint32 i; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Basic sanity checks */ + if (!pState->m_zip64) + { + if (pZip->m_total_files > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (pZip->m_archive_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + else + { + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + for (i = 0; i < pZip->m_total_files; i++) + { + if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) + { + mz_uint32 found_index; + mz_zip_archive_file_stat stat; + + if (!mz_zip_reader_file_stat(pZip, i, &stat)) + return MZ_FALSE; + + if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) + return MZ_FALSE; + + /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ + if (found_index != i) + return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + } + + if (!mz_zip_validate_file(pZip, i, flags)) + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if ((!pMem) || (!size)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if (!pFilename) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +/* ------------------- .ZIP archive writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +{ + mz_write_le32(p, (mz_uint32)v); + mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +} + +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + + if (!n) + return 0; + + /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ + if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + return 0; + } + + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + + while (new_capacity < new_size) + new_capacity *= 2; + + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return 0; + } + + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + status = MZ_FALSE; + } + } + + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +{ + mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + { + if (!pZip->m_pRead) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (pZip->m_file_offset_alignment) + { + /* Ensure user specified file offset alignment is a power of 2. */ + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + + pZip->m_pState->m_zip64 = zip64; + pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + return mz_zip_writer_init_v2(pZip, existing_size, 0); +} + +mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_mem_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + return 0; + } + + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +} + +mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +{ + MZ_FILE *pFile; + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + + pZip->m_pState->m_pFile = pFile; + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; + char buf[4096]; + + MZ_CLEAR_ARR(buf); + + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, 0, flags)) + return MZ_FALSE; + + pZip->m_pState->m_pFile = pFile; + pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_zip_internal_state *pState; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) + { + /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ + if (!pZip->m_pState->m_zip64) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* No sense in trying to write to an archive that's already at the support max size */ + if (pZip->m_pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + (void)pFilename; + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +#else + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (!pFilename) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + } + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; +#endif /* #ifdef MINIZ_NO_STDIO */ + } + else if (pState->m_pMem) + { + /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + } + /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ + else if (!pZip->m_pWrite) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Start writing new files at the archive's current central directory location. */ + /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_central_directory_file_ofs = 0; + + /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ + /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ + /* TODO: We could easily maintain the sorted central directory offsets. */ + mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +} + +/* TODO: pArchive_name is a terrible name here! */ +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +{ + mz_uint8 *pDst = pBuf; + mz_uint32 field_size = 0; + + MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + MZ_WRITE_LE16(pDst + 2, 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + MZ_WRITE_LE64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pComp_size) + { + MZ_WRITE_LE64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + MZ_WRITE_LE64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + MZ_WRITE_LE16(pBuf + 2, field_size); + + return (mz_uint32)(pDst - pBuf); +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, + mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes, + const char *user_extra_data, mz_uint user_extra_data_len) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + if (!pZip->m_pState->m_zip64) + { + if (local_header_ofs > 0xFFFFFFFF) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + /* Try to resize the central directory array back into its original state. */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ + if (*pArchive_name == '/') + return MZ_FALSE; + + /* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/ + + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +} + +mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_uint16 bit_flags = 0; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + if (((mz_uint64)buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +#ifndef MINIZ_NO_TIME + if (last_modified != NULL) + { + mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); + } + else + { + MZ_TIME_T cur_time; + time(&cur_time); + mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif /* #ifndef MINIZ_NO_TIME */ + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + /* Set DOS Subdirectory attribute bit. */ + ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + + /* Subdirectories cannot contain data. */ + if ((buf_size) || (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + cur_archive_file_ofs += num_alignment_padding_bytes; + + MZ_CLEAR_ARR(local_dir_header); + + if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + method = MZ_DEFLATED; + } + + if (pState->m_zip64) + { + if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + + if (pExtra_data != NULL) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + if (uncomp_size) + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 gen_flags; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_zip_internal_state *pState; + mz_uint64 file_ofs = 0, cur_archive_header_file_ofs; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) ? 0 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) + { + /* Source file is too large for non-zip64 */ + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + pState->m_zip64 = MZ_TRUE; + } + + /* We could support this, but why? */ + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + +#ifndef MINIZ_NO_TIME + if (pFile_time) + { + mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); + } +#endif + + if (max_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_archive_file_ofs; + + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + if (max_size && level) + { + method = MZ_DEFLATED; + } + + MZ_CLEAR_ARR(local_dir_header); + if (pState->m_zip64) + { + if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, + (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + else + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, NULL, + NULL, + (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (max_size) + { + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!level) + { + while (1) + { + size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); + if (n == 0) + break; + + if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + file_ofs += n; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + cur_archive_file_ofs += n; + } + uncomp_size = file_ofs; + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + } + + for (;;) + { + tdefl_status status; + tdefl_flush flush = TDEFL_NO_FLUSH; + + size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); + if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + break; + } + + file_ofs += n; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + + if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) + flush = TDEFL_FULL_FLUSH; + + if (n == 0) + flush = TDEFL_FINISH; + + status = tdefl_compress_buffer(pComp, pRead_buf, n, flush); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + { + mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + break; + } + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return MZ_FALSE; + } + + uncomp_size = file_ofs; + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + if (!(level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)) + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) + { + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, + (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), + (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size, + (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size, + uncomp_crc32, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + cur_archive_header_file_ofs = local_dir_header_ofs; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + if (pExtra_data != NULL) + { + cur_archive_header_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_header_file_ofs += archive_name_size; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_header_file_ofs += extra_size; + } + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO + +static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pSrc_file); + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pSrc_file); +} + +mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags, + user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); +} + +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + MZ_FILE *pSrc_file = NULL; + mz_uint64 uncomp_size = 0; + MZ_TIME_T file_modified_time; + MZ_TIME_T *pFile_time = NULL; + mz_bool status; + + memset(&file_modified_time, 0, sizeof(file_modified_time)); + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + pFile_time = &file_modified_time; + if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +#endif + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + + MZ_FCLOSE(pSrc_file); + + return status; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, mz_uint32 ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) +{ + /* + 64 should be enough for any new zip64 data */ + if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); + + if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) + { + mz_uint8 new_ext_block[64]; + mz_uint8 *pDst = new_ext_block; + mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + mz_write_le16(pDst + sizeof(mz_uint16), 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + mz_write_le64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + } + + if (pComp_size) + { + mz_write_le64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + mz_write_le64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + } + + if (pDisk_start) + { + mz_write_le32(pDst, *pDisk_start); + pDst += sizeof(mz_uint32); + } + + mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); + + if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if ((pExt) && (ext_len)) + { + mz_uint32 extra_size_remaining = ext_len; + const mz_uint8 *pExtra_data = pExt; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + return MZ_TRUE; +} + +/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; + mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + mz_zip_archive_file_stat src_file_stat; + mz_uint32 src_filename_len, src_comment_len, src_ext_len; + mz_uint32 local_header_filename_size, local_header_extra_len; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ + if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Get pointer to the source central dir header and crack it */ + if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); + src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); + src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; + + /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ + if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + if (!pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) + return MZ_FALSE; + + cur_src_file_ofs = src_file_stat.m_local_header_ofs; + cur_dst_file_ofs = pZip->m_archive_size; + + /* Read the source archive's local dir header */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Compute the total size we need to copy (filename+extra data+compressed data) */ + local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; + + /* Try to find a zip64 extended information field */ + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_zip_array file_data_array; + const mz_uint8 *pExtra_data; + mz_uint32 extra_size_remaining = local_header_extra_len; + + mz_zip_array_init(&file_data_array, 1); + if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + + mz_zip_array_clear(pZip, &file_data_array); + } + + if (!pState->m_zip64) + { + /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ + /* We also check when the archive is finalized so this doesn't need to be perfect. */ + mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; + + if (approx_new_archive_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + /* Write dest archive padding */ + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + + cur_dst_file_ofs += num_alignment_padding_bytes; + + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + while (src_archive_bytes_remaining) + { + n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_dst_file_ofs += n; + + src_archive_bytes_remaining -= n; + } + + /* Now deal with the optional data descriptor */ + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + /* Copy data descriptor */ + if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + /* src is zip64, dest must be zip64 */ + + /* name uint32_t's */ + /* id 1 (optional in zip64?) */ + /* crc 1 */ + /* comp_size 2 */ + /* uncomp_size 2 */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); + } + else + { + /* src is NOT zip64 */ + mz_bool has_id; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + + if (pZip->m_pState->m_zip64) + { + /* dest is zip64, so upgrade the data descriptor */ + const mz_uint8 *pSrc_descriptor = (const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0); + const mz_uint32 src_crc32 = MZ_READ_LE32(pSrc_descriptor); + const mz_uint64 src_comp_size = MZ_READ_LE32(pSrc_descriptor + sizeof(mz_uint32)); + const mz_uint64 src_uncomp_size = MZ_READ_LE32(pSrc_descriptor + 2*sizeof(mz_uint32)); + + mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); + mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); + + n = sizeof(mz_uint32) * 6; + } + else + { + /* dest is NOT zip64, just copy it as-is */ + n = sizeof(mz_uint32) * (has_id ? 4 : 3); + } + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + /* Finally, add the new central dir header */ + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + + if (pState->m_zip64) + { + /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ + const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; + mz_zip_array new_ext_block; + + mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); + + if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return MZ_FALSE; + } + + MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + mz_zip_array_clear(pZip, &new_ext_block); + } + else + { + /* sanity checks */ + if (cur_dst_file_ofs > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (local_dir_header_ofs >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + } + + /* This shouldn't trigger unless we screwed up during the initial sanity checks */ + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + { + /* TODO: Support central dirs >= 32-bits in size */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + } + + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[256]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if ((mz_uint64)pState->m_central_dir.m_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + /* Write central directory */ + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += central_dir_size; + } + + if (pState->m_zip64) + { + /* Write zip64 end of central directory header */ + mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + + MZ_CLEAR_ARR(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + + /* Write zip64 end of central directory locator */ + MZ_CLEAR_ARR(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; + } + + /* Write end of central directory record */ + MZ_CLEAR_ARR(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +{ + if ((!ppBuf) || (!pSize)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + *ppBuf = NULL; + *pSize = 0; + + if ((!pZip) || (!pZip->m_pState)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_pWrite != mz_zip_heap_write_func) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *ppBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + return mz_zip_writer_end_internal(pZip, MZ_TRUE); +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +} + +mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + mz_zip_zero_struct(&zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_FILENAME; + return MZ_FALSE; + } + + /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ + /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + /* Create a new archive. */ + if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + created_new_archive = MZ_TRUE; + } + else + { + /* Append to an existing archive. */ + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + + return MZ_FALSE; + } + } + + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + actual_err = zip_archive.m_last_error; + + /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ + if (!mz_zip_writer_finalize_archive(&zip_archive)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if (!mz_zip_writer_end_internal(&zip_archive, status)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if ((!status) && (created_new_archive)) + { + /* It's a new archive and something went wrong, so just delete it. */ + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + + if (pErr) + *pErr = actual_err; + + return status; +} + +void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +{ + mz_uint32 file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + + return NULL; + } + + mz_zip_zero_struct(&zip_archive); + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + return NULL; + } + + if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) + { + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + } + + mz_zip_reader_end_internal(&zip_archive, p != NULL); + + if (pErr) + *pErr = zip_archive.m_last_error; + + return p; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* ------------------- Misc utils */ + +mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +} + +mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +} + +mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = err_num; + return prev_err; +} + +mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + return pZip->m_last_error; +} + +mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +{ + return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +} + +mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = MZ_ZIP_NO_ERROR; + return prev_err; +} + +const char *mz_zip_get_error_string(mz_zip_error mz_err) +{ + switch (mz_err) + { + case MZ_ZIP_NO_ERROR: + return "no error"; + case MZ_ZIP_UNDEFINED_ERROR: + return "undefined error"; + case MZ_ZIP_TOO_MANY_FILES: + return "too many files"; + case MZ_ZIP_FILE_TOO_LARGE: + return "file too large"; + case MZ_ZIP_UNSUPPORTED_METHOD: + return "unsupported method"; + case MZ_ZIP_UNSUPPORTED_ENCRYPTION: + return "unsupported encryption"; + case MZ_ZIP_UNSUPPORTED_FEATURE: + return "unsupported feature"; + case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: + return "failed finding central directory"; + case MZ_ZIP_NOT_AN_ARCHIVE: + return "not a ZIP archive"; + case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: + return "invalid header or archive is corrupted"; + case MZ_ZIP_UNSUPPORTED_MULTIDISK: + return "unsupported multidisk archive"; + case MZ_ZIP_DECOMPRESSION_FAILED: + return "decompression failed or archive is corrupted"; + case MZ_ZIP_COMPRESSION_FAILED: + return "compression failed"; + case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: + return "unexpected decompressed size"; + case MZ_ZIP_CRC_CHECK_FAILED: + return "CRC-32 check failed"; + case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: + return "unsupported central directory size"; + case MZ_ZIP_ALLOC_FAILED: + return "allocation failed"; + case MZ_ZIP_FILE_OPEN_FAILED: + return "file open failed"; + case MZ_ZIP_FILE_CREATE_FAILED: + return "file create failed"; + case MZ_ZIP_FILE_WRITE_FAILED: + return "file write failed"; + case MZ_ZIP_FILE_READ_FAILED: + return "file read failed"; + case MZ_ZIP_FILE_CLOSE_FAILED: + return "file close failed"; + case MZ_ZIP_FILE_SEEK_FAILED: + return "file seek failed"; + case MZ_ZIP_FILE_STAT_FAILED: + return "file stat failed"; + case MZ_ZIP_INVALID_PARAMETER: + return "invalid parameter"; + case MZ_ZIP_INVALID_FILENAME: + return "invalid filename"; + case MZ_ZIP_BUF_TOO_SMALL: + return "buffer too small"; + case MZ_ZIP_INTERNAL_ERROR: + return "internal error"; + case MZ_ZIP_FILE_NOT_FOUND: + return "file not found"; + case MZ_ZIP_ARCHIVE_TOO_LARGE: + return "archive is too large"; + case MZ_ZIP_VALIDATION_FAILED: + return "validation failed"; + case MZ_ZIP_WRITE_CALLBACK_FAILED: + return "write callback failed"; + case MZ_ZIP_TOTAL_ERRORS: + return "total errors"; + default: + break; + } + + return "unknown error"; +} + +/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return MZ_FALSE; + + return pZip->m_pState->m_zip64; +} + +size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + + return pZip->m_pState->m_central_dir.m_size; +} + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +{ + if (!pZip) + return 0; + return pZip->m_archive_size; +} + +mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_file_archive_start_ofs; +} + +MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_pFile; +} + +size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + if (filename_buf_size) + pFilename[0] = '\0'; + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +} + +mz_bool mz_zip_end(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_FALSE; + + if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) + return mz_zip_reader_end(pZip); +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) + return mz_zip_writer_end(pZip); +#endif + + return MZ_FALSE; +} + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/source/engine/miniz.h b/source/engine/miniz.h new file mode 100644 index 0000000..9fcfffc --- /dev/null +++ b/source/engine/miniz.h @@ -0,0 +1,1422 @@ +#ifndef MINIZ_EXPORT +#define MINIZ_EXPORT +#endif +/* miniz.c 3.0.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateReset/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ +#pragma once + + + +/* Defines to completely disable specific portions of miniz.c: + If all macros here are defined the only functionality remaining will be CRC-32 and adler-32. */ + +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ +/*#define MINIZ_NO_STDIO */ + +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ +/*#define MINIZ_NO_TIME */ + +/* Define MINIZ_NO_DEFLATE_APIS to disable all compression API's. */ +/*#define MINIZ_NO_DEFLATE_APIS */ + +/* Define MINIZ_NO_INFLATE_APIS to disable all decompression API's. */ +/*#define MINIZ_NO_INFLATE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ +/*#define MINIZ_NO_ZLIB_APIS */ + +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ +/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ +/*#define MINIZ_NO_MALLOC */ + +#ifdef MINIZ_NO_INFLATE_APIS +#define MINIZ_NO_ARCHIVE_APIS +#endif + +#ifdef MINIZ_NO_DEFLATE_APIS +#define MINIZ_NO_ARCHIVE_WRITING_APIS +#endif + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ +#define MINIZ_NO_TIME +#endif + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ +#define MINIZ_X86_OR_X64_CPU 1 +#else +#define MINIZ_X86_OR_X64_CPU 0 +#endif + +/* Set MINIZ_LITTLE_ENDIAN only if not set */ +#if !defined(MINIZ_LITTLE_ENDIAN) +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +#else + +#if MINIZ_X86_OR_X64_CPU +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +#endif +#endif + +/* Using unaligned loads and stores causes errors when using UBSan */ +#if defined(__has_feature) +#if __has_feature(undefined_behavior_sanitizer) +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#endif +#endif + +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ +#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) +#if MINIZ_X86_OR_X64_CPU +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#define MINIZ_UNALIGNED_USE_MEMCPY +#else +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#endif +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#else +#define MINIZ_HAS_64BIT_REGISTERS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API Definitions. */ + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +typedef unsigned long mz_ulong; + +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ +MINIZ_EXPORT void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ +MINIZ_EXPORT mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +MINIZ_EXPORT mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +/* Compression strategies. */ +enum +{ + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +/* Method */ +#define MZ_DEFLATED 8 + +/* Heap allocation callbacks. +Note that mz_alloc_func parameter types purposely differ from zlib's: items/size is size_t, not unsigned long. */ +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +#define MZ_VERSION "11.0.2" +#define MZ_VERNUM 0xB002 +#define MZ_VER_MAJOR 11 +#define MZ_VER_MINOR 2 +#define MZ_VER_REVISION 0 +#define MZ_VER_SUBREVISION 0 + +#ifndef MINIZ_NO_ZLIB_APIS + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ +enum +{ + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + +/* Returns the version string of miniz.c. */ +MINIZ_EXPORT const char *mz_version(void); + +#ifndef MINIZ_NO_DEFLATE_APIS + +/* mz_deflateInit() initializes a compressor with default options: */ +/* Parameters: */ +/* pStream must point to an initialized mz_stream struct. */ +/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if the input parameters are bogus. */ +/* MZ_MEM_ERROR on out of memory. */ +MINIZ_EXPORT int mz_deflateInit(mz_streamp pStream, int level); + +/* mz_deflateInit2() is like mz_deflate(), except with more control: */ +/* Additional parameters: */ +/* method must be MZ_DEFLATED */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ +/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ +MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +MINIZ_EXPORT int mz_deflateReset(mz_streamp pStream); + +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ +/* Return values: */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ +MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush); + +/* mz_deflateEnd() deinitializes a compressor: */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +MINIZ_EXPORT int mz_deflateEnd(mz_streamp pStream); + +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +MINIZ_EXPORT mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +/* Single-call compression functions mz_compress() and mz_compress2(): */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +MINIZ_EXPORT int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +MINIZ_EXPORT int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +MINIZ_EXPORT mz_ulong mz_compressBound(mz_ulong source_len); + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + +#ifndef MINIZ_NO_INFLATE_APIS + +/* Initializes a decompressor. */ +MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream); + +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ +MINIZ_EXPORT int mz_inflateReset(mz_streamp pStream); + +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ +/* Return values: */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_DATA_ERROR if the deflate stream is invalid. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ +MINIZ_EXPORT int mz_inflate(mz_streamp pStream, int flush); + +/* Deinitializes a decompressor. */ +MINIZ_EXPORT int mz_inflateEnd(mz_streamp pStream); + +/* Single-call decompression. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ +MINIZ_EXPORT int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +MINIZ_EXPORT int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong *pSource_len); +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +MINIZ_EXPORT const char *mz_error(int err); + +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream + +#ifndef MINIZ_NO_DEFLATE_APIS +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + +#ifndef MINIZ_NO_INFLATE_APIS +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflateReset mz_inflateReset +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define uncompress2 mz_uncompress2 +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +#endif /* MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + + + + + +#pragma once +#include +#include +#include +#include + + + +/* ------------------- Types and macros */ +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef int64_t mz_int64; +typedef uint64_t mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#define MZ_FILE FILE +#endif /* #ifdef MINIZ_NO_STDIO */ + +#ifdef MINIZ_NO_TIME +typedef struct mz_dummy_time_t_tag +{ + mz_uint32 m_dummy1; + mz_uint32 m_dummy2; +} mz_dummy_time_t; +#define MZ_TIME_T mz_dummy_time_t +#else +#define MZ_TIME_T time_t +#endif + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) +#define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj)) +#define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); +extern MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address); +extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + +#define MZ_UINT16_MAX (0xFFFFU) +#define MZ_UINT32_MAX (0xFFFFFFFFU) + +#ifdef __cplusplus +} +#endif + #pragma once + + +#ifndef MINIZ_NO_DEFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------- Low-level Compression API Definitions */ + +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ +#define TDEFL_LESS_MEMORY 0 + +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ +enum +{ + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ +/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ +/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ +/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +/* High level compression functions: */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must free() the returned block when it's no longer needed. */ +MINIZ_EXPORT void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ +/* Returns 0 on failure. */ +MINIZ_EXPORT size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* Compresses an image to a compressed PNG file in memory. */ +/* On entry: */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pLen_out will be set to the size of the PNG image file. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +MINIZ_EXPORT mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ +#if TDEFL_LESS_MEMORY +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +/* tdefl's compression state structure. */ +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +/* Initializes the compressor. */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ +MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ +MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() always consumes the entire input buffer. */ +MINIZ_EXPORT tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +MINIZ_EXPORT tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +MINIZ_EXPORT mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +/* Create tdefl_compress() flags given zlib-style compression parameters. */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ +/* window_bits may be -15 (raw deflate) or 15 (zlib) */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ +MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tdefl_compressor structure in C so that */ +/* non-C language bindings to tdefl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +MINIZ_EXPORT tdefl_compressor *tdefl_compressor_alloc(void); +MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor *pComp); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + #pragma once + +/* ------------------- Low-level Decompression API Definitions */ + +#ifndef MINIZ_NO_INFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif +/* Decompression flags used by tinfl_decompress(). */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +/* High level decompression functions: */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ +/* On return: */ +/* Function returns a pointer to the decompressed data, or NULL on failure. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ +MINIZ_EXPORT void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +MINIZ_EXPORT size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ +/* Returns 1 on success or 0 on failure. */ +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +MINIZ_EXPORT int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tinfl_decompressor structure in C so that */ +/* non-C language bindings to tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +MINIZ_EXPORT tinfl_decompressor *tinfl_decompressor_alloc(void); +MINIZ_EXPORT void tinfl_decompressor_free(tinfl_decompressor *pDecomp); +#endif + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum { + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, + + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ + TINFL_STATUS_BAD_PARAM = -3, + + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ + TINFL_STATUS_ADLER32_MISMATCH = -2, + + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ + TINFL_STATUS_FAILED = -1, + + /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ + + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ + TINFL_STATUS_DONE = 0, + + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ + /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ + /* so I may need to add some code to address this. */ + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) \ + do \ + { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +MINIZ_EXPORT tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#else +#define TINFL_USE_64BIT_BITBUF 0 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE]; + mz_int16 m_tree_0[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; + mz_int16 m_tree_1[TINFL_MAX_HUFF_SYMBOLS_1 * 2]; + mz_int16 m_tree_2[TINFL_MAX_HUFF_SYMBOLS_2 * 2]; + mz_uint8 m_code_size_0[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_uint8 m_code_size_1[TINFL_MAX_HUFF_SYMBOLS_1]; + mz_uint8 m_code_size_2[TINFL_MAX_HUFF_SYMBOLS_2]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +#pragma once + + +/* ------------------- ZIP archive reading/writing */ + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +}; + +typedef struct +{ + /* Central directory file index. */ + mz_uint32 m_file_index; + + /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ + mz_uint64 m_central_dir_ofs; + + /* These fields are copied directly from the zip's central dir. */ + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; + + /* CRC-32 of uncompressed data. */ + mz_uint32 m_crc32; + + /* File's compressed size. */ + mz_uint64 m_comp_size; + + /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ + mz_uint64 m_uncomp_size; + + /* Zip internal and external file attributes. */ + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + + /* Entry's local header file offset in bytes. */ + mz_uint64 m_local_header_ofs; + + /* Size of comment in bytes. */ + mz_uint32 m_comment_size; + + /* MZ_TRUE if the entry appears to be a directory. */ + mz_bool m_is_directory; + + /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ + mz_bool m_is_encrypted; + + /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ + mz_bool m_is_supported; + + /* Filename. If string ends in '/' it's a subdirectory entry. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + + /* Comment field. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +#ifdef MINIZ_NO_TIME + MZ_TIME_T m_padding; +#else + MZ_TIME_T m_time; +#endif +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, + MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ + MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ + MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, + MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000, + /*After adding a compressed file, seek back + to local file header and set the correct sizes*/ + MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000 +} mz_zip_flags; + +typedef enum { + MZ_ZIP_TYPE_INVALID = 0, + MZ_ZIP_TYPE_USER, + MZ_ZIP_TYPE_MEMORY, + MZ_ZIP_TYPE_HEAP, + MZ_ZIP_TYPE_FILE, + MZ_ZIP_TYPE_CFILE, + MZ_ZIP_TOTAL_TYPES +} mz_zip_type; + +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +typedef enum { + MZ_ZIP_NO_ERROR = 0, + MZ_ZIP_UNDEFINED_ERROR, + MZ_ZIP_TOO_MANY_FILES, + MZ_ZIP_FILE_TOO_LARGE, + MZ_ZIP_UNSUPPORTED_METHOD, + MZ_ZIP_UNSUPPORTED_ENCRYPTION, + MZ_ZIP_UNSUPPORTED_FEATURE, + MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, + MZ_ZIP_NOT_AN_ARCHIVE, + MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, + MZ_ZIP_UNSUPPORTED_MULTIDISK, + MZ_ZIP_DECOMPRESSION_FAILED, + MZ_ZIP_COMPRESSION_FAILED, + MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, + MZ_ZIP_CRC_CHECK_FAILED, + MZ_ZIP_UNSUPPORTED_CDIR_SIZE, + MZ_ZIP_ALLOC_FAILED, + MZ_ZIP_FILE_OPEN_FAILED, + MZ_ZIP_FILE_CREATE_FAILED, + MZ_ZIP_FILE_WRITE_FAILED, + MZ_ZIP_FILE_READ_FAILED, + MZ_ZIP_FILE_CLOSE_FAILED, + MZ_ZIP_FILE_SEEK_FAILED, + MZ_ZIP_FILE_STAT_FAILED, + MZ_ZIP_INVALID_PARAMETER, + MZ_ZIP_INVALID_FILENAME, + MZ_ZIP_BUF_TOO_SMALL, + MZ_ZIP_INTERNAL_ERROR, + MZ_ZIP_FILE_NOT_FOUND, + MZ_ZIP_ARCHIVE_TOO_LARGE, + MZ_ZIP_VALIDATION_FAILED, + MZ_ZIP_WRITE_CALLBACK_FAILED, + MZ_ZIP_TOTAL_ERRORS +} mz_zip_error; + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + + /* We only support up to UINT32_MAX files in zip64 mode. */ + mz_uint32 m_total_files; + mz_zip_mode m_zip_mode; + mz_zip_type m_zip_type; + mz_zip_error m_last_error; + + mz_uint64 m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + mz_file_needs_keepalive m_pNeeds_keepalive; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef struct +{ + mz_zip_archive *pZip; + mz_uint flags; + + int status; + + mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + void *pWrite_buf; + + size_t out_blk_remain; + + tinfl_decompressor inflator; + +#ifdef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint padding; +#else + mz_uint file_crc32; +#endif + +} mz_zip_reader_extract_iter_state; + +/* -------- ZIP reading */ + +/* Inits a ZIP archive reader. */ +/* These functions read and validate the archive's central directory. */ +MINIZ_EXPORT mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +MINIZ_EXPORT mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +/* Read a archive from a disk file. */ +/* file_start_ofs is the file offset where the archive actually begins, or 0. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +MINIZ_EXPORT mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is 0, then the entire rest of the file is assumed to contain the archive. */ +/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +MINIZ_EXPORT mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +#endif + +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +MINIZ_EXPORT mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +/* -------- ZIP reading or writing */ + +/* Clears a mz_zip_archive struct to all zeros. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ +MINIZ_EXPORT void mz_zip_zero_struct(mz_zip_archive *pZip); + +MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +MINIZ_EXPORT mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + +/* Returns the total number of files in the archive. */ +MINIZ_EXPORT mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +MINIZ_EXPORT mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +MINIZ_EXPORT MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +MINIZ_EXPORT size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ +/* Note that the m_last_error functionality is not thread safe. */ +MINIZ_EXPORT mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +MINIZ_EXPORT mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +MINIZ_EXPORT mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +MINIZ_EXPORT mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +MINIZ_EXPORT const char *mz_zip_get_error_string(mz_zip_error mz_err); + +/* MZ_TRUE if the archive file entry is a directory entry. */ +MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the file is encrypted/strong encrypted. */ +MINIZ_EXPORT mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +MINIZ_EXPORT mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + +/* Retrieves the filename of an archive file entry. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +MINIZ_EXPORT int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + +/* Returns detailed information about an archive file entry. */ +MINIZ_EXPORT mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +/* MZ_TRUE if the file is in zip64 format. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + +/* Returns the total central directory size in bytes. */ +/* The current max supported size is <= MZ_UINT32_MAX. */ +MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + +/* Extracts a archive file to a memory buffer using no memory allocation. */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +/* Extracts a archive file to a memory buffer. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +/* Extracts a archive file to a dynamically allocated heap buffer. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ +/* Returns NULL and sets the last error on failure. */ +MINIZ_EXPORT void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +MINIZ_EXPORT void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +/* Extracts a archive file using a callback function to output the file's data. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +/* Extract a file iteratively */ +MINIZ_EXPORT mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +MINIZ_EXPORT mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +MINIZ_EXPORT size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +#ifndef MINIZ_NO_STDIO +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ +/* This function only extracts files, not archive directory records. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + +/* Extracts a archive file starting at the current position in the destination FILE stream. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +#endif + +#if 0 +/* TODO */ + typedef void *mz_zip_streaming_extract_state_ptr; + mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs); + size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); + mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); +#endif + +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +MINIZ_EXPORT mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ +MINIZ_EXPORT mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); + +/* Misc utils/helpers, valid for ZIP reading or writing */ +MINIZ_EXPORT mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); +#ifndef MINIZ_NO_STDIO +MINIZ_EXPORT mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); +#endif + +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive *pZip); + +/* -------- ZIP writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Inits a ZIP archive writer. */ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +MINIZ_EXPORT mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +MINIZ_EXPORT mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +MINIZ_EXPORT mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +MINIZ_EXPORT mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +MINIZ_EXPORT mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +MINIZ_EXPORT mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +#endif + +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ +/* the archive is finalized the file's central directory will be hosed. */ +MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */ +/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ +MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + + +#ifndef MINIZ_NO_STDIO +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); +#endif + +/* Adds a file to an archive by fully cloning the data from another archive. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); + +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ +MINIZ_EXPORT mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + +/* Finalizes a heap archive, returning a pointer to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +MINIZ_EXPORT mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +MINIZ_EXPORT mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +/* -------- Misc. high-level helper functions: */ + +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + +#ifndef MINIZ_NO_STDIO +/* Reads a single file from an archive into a heap block. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ +/* Returns NULL on failure. */ +MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); +#endif + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifdef __cplusplus +} +#endif + +#endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/source/engine/render.h b/source/engine/render.h index f0e2dfa..f22150b 100644 --- a/source/engine/render.h +++ b/source/engine/render.h @@ -7,7 +7,6 @@ #define SOKOL_GLES3 #elif __WIN32 #define SOKOL_D3D11 - #define SOKOL_WIN32_FORCE_MAIN #elif __APPLE__ #define SOKOL_METAL #endif diff --git a/source/engine/resources.c b/source/engine/resources.c index 33a6df0..ab81a18 100644 --- a/source/engine/resources.c +++ b/source/engine/resources.c @@ -15,7 +15,7 @@ #include "font.h" #include -#include "cdb.h" +#include "miniz.h" #ifndef __EMSCRIPTEN__ #include @@ -40,8 +40,8 @@ struct dirent *c_dirent = NULL; char pathbuf[MAXPATH + 1]; -static struct cdb corecdb; -static struct cdb game_cdb; +static mz_zip_archive corecdb; +static mz_zip_archive game_cdb; int LOADED_GAME = 0; uint8_t *gamebuf; @@ -49,7 +49,7 @@ uint8_t *gamebuf; static void response_cb(const sfetch_response_t *r) { if (r->fetched) { - cdb_initf(&game_cdb, r->data.ptr, r->data.size); + mz_zip_reader_init_mem(&game_cdb, r->data.ptr, r->data.size,0); LOADED_GAME = 1; } if (r->finished) { @@ -78,7 +78,7 @@ void resources_init() { } }); - cdb_initf(&corecdb, core_cdb, core_cdb_len); + mz_zip_reader_init_mem(&corecdb, core_cdb, core_cdb_len, 0); } char *get_filename_from_path(char *path, int extension) { @@ -160,6 +160,7 @@ char **ls(const char *path) #else void fill_extensions(char *paths, const char *path, const char *ext) {}; +char **ls(const char *path) { return NULL; } #endif char *str_replace_ext(const char *s, const char *newext) { @@ -172,32 +173,11 @@ char *str_replace_ext(const char *s, const char *newext) { return ret; } -FILE *path_open(const char *tag, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vsnprintf(pathbuf, MAXPATH+1, fmt, args); - va_end(args); - - FILE *f = fopen(pathbuf, tag); - return f; -} - -void *cdb_slurp(struct cdb *cdb, const char *file, size_t *size) -{ - unsigned vlen, vpos; - vpos = cdb_datapos(cdb); - vlen = cdb_datalen(cdb); - char *data = malloc(vlen+1); - cdb_read(cdb, data, vlen, vpos); - if (size) *size = vlen; - return data; -} - int fexists(const char *path) { int len = strlen(path); - if (cdb_find(&game_cdb, path, len)) return 1; - else if (cdb_find(&corecdb, path, len)) return 1; + if (mz_zip_reader_locate_file(&game_cdb, path, NULL, 0) != -1) return 1; + else if (mz_zip_reader_locate_file(&corecdb, path, NULL, 0) != -1) return 1; else if (!access(path, R_OK)) return 1; return 0; @@ -205,7 +185,6 @@ int fexists(const char *path) void *os_slurp(const char *file, size_t *size) { - YughInfo("Slurping %s from the OS.\n", file); FILE *f; jump: @@ -227,12 +206,13 @@ void *os_slurp(const char *file, size_t *size) void *slurp_file(const char *filename, size_t *size) { + void *ret; if (!access(filename, R_OK)) return os_slurp(filename, size); - else if (cdb_find(&game_cdb, filename, strlen(filename))) - return cdb_slurp(&game_cdb, filename, size); - else if (cdb_find(&corecdb, filename, strlen(filename))) - return cdb_slurp(&corecdb, filename, size); + else if (ret = mz_zip_reader_extract_file_to_heap(&game_cdb, filename, size, 0)) + return ret; + else if (ret = mz_zip_reader_extract_file_to_heap(&corecdb, filename, size, 0)) + return ret; return NULL; } @@ -311,58 +291,3 @@ int slurp_write(const char *txt, const char *filename, size_t len) { fclose(f); return 0; } - -#ifndef __EMSCRIPTEN__ -static struct cdb_make cdbm; - -static const char *pack_ext[] = {".qoi", ".qoa", ".js", ".wav", ".mp3", ".png", ".sf2", ".midi", ".lvl", ".glsl", ".ttf", ".json", ".jso"}; - -static int ftw_pack(const char *path, const struct stat *sb, int flag) -{ - if (flag != FTW_F) return 0; - int pack = 0; - char *ext = strrchr(path, '.'); - - if (!ext) - return 0; - - for (int i = 0; i < 13; i++) { - if (!strcmp(ext, pack_ext[i])) { - pack = 1; - break; - } - } - - if (!pack) return 0; - - size_t len; - void *file = slurp_file(path, &len); - cdb_make_add(&cdbm, &path[2], strlen(&path[2]), file, len); - - free(file); - - return 0; -} - -void pack_engine(const char *fname) -{ - int fd; - char *key, *va; - unsigned klen, vlen; - fd = creat(fname, O_RDWR); - if (fd == -1) { - YughError("Couldn't make file at %s.", fname); - return; - } - cdb_make_start(&cdbm, fd); - ftw(".", ftw_pack, 20); - cdb_make_finish(&cdbm); - close(fd); -} -#else -void pack_engine(const char *fname){ - YughError("Cannot pack engine on a web build."); -} - -char **ls(const char *path) { return NULL; } -#endif diff --git a/source/engine/resources.h b/source/engine/resources.h index b7cc893..a6dfba0 100644 --- a/source/engine/resources.h +++ b/source/engine/resources.h @@ -14,7 +14,6 @@ char *get_filename_from_path(char *path, int extension); char *get_directory_from_path(char *path); char *str_replace_ext(const char *s, const char *newext); FILE *res_open(char *path, const char *tag); -FILE *path_open(const char *tag, const char *fmt, ...); char **ls(const char *path); int cp(const char *p1, const char *p2); int fexists(const char *path); @@ -28,8 +27,6 @@ int slurp_write(const char *txt, const char *filename, size_t len); char *seprint(char *fmt, ...); -void pack_engine(const char *fname); - static inline void *stbarrdup(void *mem, size_t size, int len) { void *out = NULL; arrsetlen(out, len); diff --git a/source/engine/script.c b/source/engine/script.c index e8e5f01..9eb4ad4 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -73,11 +73,9 @@ JSValue script_eval(const char *file, const char *script) void script_call_sym(JSValue sym, int argc, JSValue *argv) { if (!JS_IsFunction(js, sym)) return; - JSValue g = JS_GetGlobalObject(js); - JSValue ret = JS_Call(js, sym, JS_GetGlobalObject(js), argc, argv); + JSValue ret = JS_Call(js, sym, JS_UNDEFINED, argc, argv); js_print_exception(ret); JS_FreeValue(js, ret); - JS_FreeValue(js,g); } void out_memusage(const char *file) diff --git a/source/engine/thirdparty/cgltf/.github/workflows/build.yml b/source/engine/thirdparty/cgltf/.github/workflows/build.yml deleted file mode 100644 index 6e0bd7f..0000000 --- a/source/engine/thirdparty/cgltf/.github/workflows/build.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: build - -on: [push, pull_request] - -jobs: - generic: - strategy: - matrix: - os: [windows, ubuntu, macos] - name: ${{matrix.os}} - runs-on: ${{matrix.os}}-latest - steps: - - uses: actions/checkout@v1 - - name: test - run: cd test && python test_all.py diff --git a/source/engine/thirdparty/cgltf/fuzz/data/BadBasisU.gltf b/source/engine/thirdparty/cgltf/fuzz/data/BadBasisU.gltf deleted file mode 100644 index e108e39..0000000 --- a/source/engine/thirdparty/cgltf/fuzz/data/BadBasisU.gltf +++ /dev/null @@ -1 +0,0 @@ -{"textures":[{"extensions":{"KHR_texture_basisu":{""}}:{""""},""}]} \ No newline at end of file diff --git a/source/engine/thirdparty/cgltf/fuzz/data/Box.glb b/source/engine/thirdparty/cgltf/fuzz/data/Box.glb deleted file mode 100644 index 95ec886..0000000 Binary files a/source/engine/thirdparty/cgltf/fuzz/data/Box.glb and /dev/null differ diff --git a/source/engine/thirdparty/cgltf/fuzz/data/TriangleWithoutIndices.gltf b/source/engine/thirdparty/cgltf/fuzz/data/TriangleWithoutIndices.gltf deleted file mode 100644 index 06632b5..0000000 --- a/source/engine/thirdparty/cgltf/fuzz/data/TriangleWithoutIndices.gltf +++ /dev/null @@ -1,53 +0,0 @@ -{ - "scenes" : [ - { - "nodes" : [ 0 ] - } - ], - - "nodes" : [ - { - "mesh" : 0 - } - ], - - "meshes" : [ - { - "primitives" : [ { - "attributes" : { - "POSITION" : 0 - } - } ] - } - ], - - "buffers" : [ - { - "uri" : "data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAA", - "byteLength" : 36 - } - ], - "bufferViews" : [ - { - "buffer" : 0, - "byteOffset" : 0, - "byteLength" : 36, - "target" : 34962 - } - ], - "accessors" : [ - { - "bufferView" : 0, - "byteOffset" : 0, - "componentType" : 5126, - "count" : 3, - "type" : "VEC3", - "max" : [ 1.0, 1.0, 0.0 ], - "min" : [ 0.0, 0.0, 0.0 ] - } - ], - - "asset" : { - "version" : "2.0" - } -} \ No newline at end of file diff --git a/source/engine/thirdparty/cgltf/fuzz/data/WaterBottle.gltf b/source/engine/thirdparty/cgltf/fuzz/data/WaterBottle.gltf deleted file mode 100644 index 9f23f3a..0000000 --- a/source/engine/thirdparty/cgltf/fuzz/data/WaterBottle.gltf +++ /dev/null @@ -1,172 +0,0 @@ -{ - "accessors": [ - { - "bufferView": 0, - "componentType": 5126, - "count": 2549, - "type": "VEC2" - }, - { - "bufferView": 1, - "componentType": 5126, - "count": 2549, - "type": "VEC3" - }, - { - "bufferView": 2, - "componentType": 5126, - "count": 2549, - "type": "VEC4" - }, - { - "bufferView": 3, - "componentType": 5126, - "count": 2549, - "type": "VEC3", - "max": [ - 0.05445001, - 0.130220339, - 0.0544500239 - ], - "min": [ - -0.05445001, - -0.130220339, - -0.0544500239 - ] - }, - { - "bufferView": 4, - "componentType": 5123, - "count": 13530, - "type": "SCALAR" - } - ], - "asset": { - "generator": "glTF Tools for Unity", - "version": "2.0" - }, - "bufferViews": [ - { - "buffer": 0, - "byteLength": 20392 - }, - { - "buffer": 0, - "byteOffset": 20392, - "byteLength": 30588 - }, - { - "buffer": 0, - "byteOffset": 50980, - "byteLength": 40784 - }, - { - "buffer": 0, - "byteOffset": 91764, - "byteLength": 30588 - }, - { - "buffer": 0, - "byteOffset": 122352, - "byteLength": 27060 - } - ], - "buffers": [ - { - "uri": "WaterBottle.bin", - "byteLength": 149412 - } - ], - "images": [ - { - "uri": "WaterBottle_baseColor.png" - }, - { - "uri": "WaterBottle_occlusionRoughnessMetallic.png" - }, - { - "uri": "WaterBottle_normal.png" - }, - { - "uri": "WaterBottle_emissive.png" - } - ], - "meshes": [ - { - "primitives": [ - { - "attributes": { - "TEXCOORD_0": 0, - "NORMAL": 1, - "TANGENT": 2, - "POSITION": 3 - }, - "indices": 4, - "material": 0 - } - ], - "name": "WaterBottle" - } - ], - "materials": [ - { - "pbrMetallicRoughness": { - "baseColorTexture": { - "index": 0 - }, - "metallicRoughnessTexture": { - "index": 1 - } - }, - "normalTexture": { - "index": 2 - }, - "occlusionTexture": { - "index": 1 - }, - "emissiveFactor": [ - 1.0, - 1.0, - 1.0 - ], - "emissiveTexture": { - "index": 3 - }, - "name": "BottleMat" - } - ], - "nodes": [ - { - "mesh": 0, - "rotation": [ - 0.0, - 1.0, - 0.0, - 0.0 - ], - "name": "WaterBottle" - } - ], - "scene": 0, - "scenes": [ - { - "nodes": [ - 0 - ] - } - ], - "textures": [ - { - "source": 0 - }, - { - "source": 1 - }, - { - "source": 2 - }, - { - "source": 3 - } - ] -} \ No newline at end of file diff --git a/source/engine/thirdparty/cgltf/fuzz/gltf.dict b/source/engine/thirdparty/cgltf/fuzz/gltf.dict deleted file mode 100644 index f923c46..0000000 --- a/source/engine/thirdparty/cgltf/fuzz/gltf.dict +++ /dev/null @@ -1,224 +0,0 @@ -# -# AFL dictionary for JSON -# ----------------------- -# -# Just the very basics. -# -# Inspired by a dictionary by Jakub Wilk -# - -"0" -",0" -":0" -"0:" -"-1.2e+3" - -"true" -"false" -"null" - -"\"\"" -",\"\"" -":\"\"" -"\"\":" - -"{}" -",{}" -":{}" -"{\"\":0}" -"{{}}" - -"[]" -",[]" -":[]" -"[0]" -"[[]]" - -"''" -"\\" -"\\b" -"\\f" -"\\n" -"\\r" -"\\t" -"\\u0000" -"\\x00" -"\\0" -"\\uD800\\uDC00" -"\\uDBFF\\uDFFF" - -"\"\":0" -"//" -"/**/" - -# -# AFL dictionary for GLTF core -# ----------------------- - -"5120" -"5121" -"5122" -"5123" -"5125" -"5126" -"\"BLEND\"" -"\"CUBICSPLINE\"" -"\"LINEAR\"" -"\"MASK\"" -"\"MAT2\"" -"\"MAT3\"" -"\"MAT4\"" -"\"OPAQUE\"" -"\"SCALAR\"" -"\"STEP\"" -"\"VEC2\"" -"\"VEC3\"" -"\"VEC4\"" -"\"accessor\"" -"\"accessors\"" -"\"alphaCutoff\"" -"\"alphaMode\"" -"\"animations\"" -"\"aspectRatio\"" -"\"asset\"" -"\"attributes\"" -"\"baseColorFactor\"" -"\"baseColorTexture\"" -"\"bufferView\"" -"\"bufferViews\"" -"\"buffer\"" -"\"buffers\"" -"\"byteLength\"" -"\"byteOffset\"" -"\"byteStride\"" -"\"camera\"" -"\"cameras\"" -"\"channel\"" -"\"channels\"" -"\"children\"" -"\"componentType\"" -"\"copyright\"" -"\"count\"" -"\"doubleSided\"" -"\"emissiveFactor\"" -"\"emissiveTexture\"" -"\"extensionsRequired\"" -"\"extensionsUsed\"" -"\"extensions\"" -"\"extras\"" -"\"generator\"" -"\"image\"" -"\"images\"" -"\"index\"" -"\"indices\"" -"\"input\"" -"\"interpolation\"" -"\"inverseBindMatrices\"" -"\"joints\"" -"\"magFilter\"" -"\"material\"" -"\"materials\"" -"\"matrix\"" -"\"max\"" -"\"mesh\"" -"\"meshes\"" -"\"metallicFactor\"" -"\"metallicRoughnessTexture\"" -"\"mimeType\"" -"\"minFilter\"" -"\"minVersion\"" -"\"min\"" -"\"mode\"" -"\"name\"" -"\"node\"" -"\"nodes\"" -"\"normalTextureInfo\"" -"\"normalTexture\"" -"\"normalized\"" -"\"occlusionTextureInfo\"" -"\"occlusionTexture\"" -"\"orthographic\"" -"\"output\"" -"\"path\"" -"\"pbrMetallicRoughness\"" -"\"perspective\"" -"\"primitive\"" -"\"primitives\"" -"\"rotation\"" -"\"roughnessFactor\"" -"\"sampler\"" -"\"samplers\"" -"\"scale\"" -"\"scene\"" -"\"scenes\"" -"\"skeleton\"" -"\"skin\"" -"\"skins\"" -"\"source\"" -"\"sparse\"" -"\"strength\"" -"\"target\"" -"\"targets\"" -"\"texCoord\"" -"\"textureInfo\"" -"\"texture\"" -"\"textures\"" -"\"translation\"" -"\"type\"" -"\"uri\"" -"\"values\"" -"\"version\"" -"\"weights\"" -"\"wrapS\"" -"\"wrapT\"" -"\"xmag\"" -"\"yfov\"" -"\"ymag\"" -"\"zfar\"" -"\"znear\"" - -# -# AFL dictionary for GLTF extensions -# ----------------------- -"\"KHR_materials_unlit\"" -"\"KHR_texture_basisu\"" - -"\"KHR_materials_pbrSpecularGlossiness\"" -"\"diffuseFactor\"" -"\"diffuseTexture\"" -"\"specularFactor\"" -"\"glossinessFactor\"" -"\"specularGlossinessTexture\"" - -"\"KHR_texture_transform\"" -"\"offset\"" -"\"rotation\"" -"\"scale\"" -"\"texCoord\"" - -"\"KHR_lights_punctual\"" -"\"color\"" -"\"intensity\"" -"\"type\"" -"\"range\"" -"\"innerConeAngle\"" -"\"outerConeAngle\"" - -"\"KHR_materials_transmission\"" -"\"transmissionFactor\"" -"\"transmissionTexture\"" - -"\"KHR_materials_volume\"" -"\"thicknessFactor\"" -"\"thicknessTexture\"" -"\"attenuationColor\"" -"\"attenuationDistance\"" - -"\"KHR_materials_sheen\"" -"\"sheenColorFactor\"" -"\"sheenColorTexture\"" -"\"sheenRoughnessFactor\"" -"\"sheenRoughnessTexture\"" - -"\"KHR_materials_emissive_strength\"" -"\"emissiveStrength"\"" diff --git a/source/engine/thirdparty/cgltf/fuzz/main.c b/source/engine/thirdparty/cgltf/fuzz/main.c deleted file mode 100644 index e3b75d1..0000000 --- a/source/engine/thirdparty/cgltf/fuzz/main.c +++ /dev/null @@ -1,22 +0,0 @@ -/* How to fuzz: - -clang main.c -O2 -g -fsanitize=address,fuzzer -o fuzz -cp -r data temp -./fuzz temp/ -dict=gltf.dict -jobs=12 -workers=12 - -*/ -#define CGLTF_IMPLEMENTATION -#include "../cgltf.h" - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) -{ - cgltf_options options = {cgltf_file_type_invalid}; - cgltf_data* data = NULL; - cgltf_result res = cgltf_parse(&options, Data, Size, &data); - if (res == cgltf_result_success) - { - cgltf_validate(data); - cgltf_free(data); - } - return 0; -} diff --git a/source/engine/thirdparty/cgltf/test/CMakeLists.txt b/source/engine/thirdparty/cgltf/test/CMakeLists.txt deleted file mode 100644 index aa31730..0000000 --- a/source/engine/thirdparty/cgltf/test/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -cmake_minimum_required( VERSION 2.8 ) - -include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) - -set( EXE_NAME cgltf_test ) -add_executable( ${EXE_NAME} main.c ) -set_property( TARGET ${EXE_NAME} PROPERTY C_STANDARD 99 ) -if(MSVC) - target_compile_options(${EXE_NAME} PRIVATE /W4 /WX) - add_definitions( -D_CRT_SECURE_NO_WARNINGS) -else() - target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) - target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address) - target_link_options(${EXE_NAME} PUBLIC -fsanitize=address) -endif() -install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin ) - -set( EXE_NAME test_conversion ) -add_executable( ${EXE_NAME} test_conversion.cpp ) -set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 ) -if(MSVC) - target_compile_options(${EXE_NAME} PRIVATE /W4 /WX) - add_definitions( -D_CRT_SECURE_NO_WARNINGS) -else() - target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) - target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address) - target_link_options(${EXE_NAME} PUBLIC -fsanitize=address) -endif() -install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin ) - -set( EXE_NAME test_write ) -add_executable( ${EXE_NAME} test_write.cpp ) -set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 ) -if(MSVC) - target_compile_options(${EXE_NAME} PRIVATE /W4 /WX) - add_definitions( -D_CRT_SECURE_NO_WARNINGS) -else() - target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) - target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address) - target_link_options(${EXE_NAME} PUBLIC -fsanitize=address) -endif() -install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin ) - -set( EXE_NAME test_math ) -add_executable( ${EXE_NAME} test_math.cpp ) -set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 ) -if(MSVC) - target_compile_options(${EXE_NAME} PRIVATE /W4 /WX) - add_definitions( -D_CRT_SECURE_NO_WARNINGS) -else() - target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) - target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address) - target_link_options(${EXE_NAME} PUBLIC -fsanitize=address) -endif() -install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin ) - -set( EXE_NAME test_strings ) -add_executable( ${EXE_NAME} test_strings.cpp ) -set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 ) -if(MSVC) - target_compile_options(${EXE_NAME} PRIVATE /W4 /WX) - add_definitions( -D_CRT_SECURE_NO_WARNINGS) -else() - target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) - target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address) - target_link_options(${EXE_NAME} PUBLIC -fsanitize=address) -endif() -install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin ) diff --git a/source/engine/thirdparty/cgltf/test/main.c b/source/engine/thirdparty/cgltf/test/main.c deleted file mode 100644 index 75543c1..0000000 --- a/source/engine/thirdparty/cgltf/test/main.c +++ /dev/null @@ -1,38 +0,0 @@ - - -#define CGLTF_IMPLEMENTATION -#include "../cgltf.h" - -#include - -int main(int argc, char** argv) -{ - if (argc < 2) - { - printf("err\n"); - return -1; - } - - cgltf_options options; - memset(&options, 0, sizeof(cgltf_options)); - cgltf_data* data = NULL; - cgltf_result result = cgltf_parse_file(&options, argv[1], &data); - - if (result == cgltf_result_success) - result = cgltf_load_buffers(&options, data, argv[1]); - - if (result == cgltf_result_success) - result = cgltf_validate(data); - - printf("Result: %d\n", result); - - if (result == cgltf_result_success) - { - printf("Type: %u\n", data->file_type); - printf("Meshes: %u\n", (unsigned)data->meshes_count); - } - - cgltf_free(data); - - return result; -} diff --git a/source/engine/thirdparty/cgltf/test/test_all.py b/source/engine/thirdparty/cgltf/test/test_all.py deleted file mode 100755 index ec9b9f0..0000000 --- a/source/engine/thirdparty/cgltf/test/test_all.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python - -import os, sys -from sys import platform - -num_tested = 0 -num_errors = 0 - -def get_executable_path(name): - if platform == "win32": - return "build\\Debug\\" + name - else: - return "build/" + name - -def is_ascii(s): - return all(ord(c) < 128 for c in s) - -def collect_files(path, type, name): - global num_tested - global num_errors - exe = get_executable_path(name) - for the_file in os.listdir(path): - file_path = os.path.join(os.path.normpath(path), the_file) - if os.path.isfile(file_path): - if the_file.endswith(type): - num_tested = num_tested +1 - if is_ascii(file_path): - print("### " + name + " " + file_path) - result = os.system("{0} \"{1}\"".format(exe, file_path)) - print("### Result: " + str(result) + "\n") - if result != 0: - num_errors = num_errors + 1 - print("Error.") - sys.exit(1) - elif os.path.isdir(file_path): - collect_files(file_path, type, name) - -if __name__ == "__main__": - if not os.path.exists("build/"): - os.makedirs("build/") - os.chdir("build/") - os.system("cmake ..") - if os.system("cmake --build .") != 0: - print("Unable to build.") - exit(1) - os.chdir("..") - if not os.path.exists("glTF-Sample-Models/"): - os.system("git init glTF-Sample-Models") - os.chdir("glTF-Sample-Models") - os.system("git remote add origin https://github.com/KhronosGroup/glTF-Sample-Models.git") - os.system("git config core.sparsecheckout true") - f = open(".git/info/sparse-checkout", "w+") - f.write("2.0/*\n") - f.close() - os.system("git pull --depth=1 origin master") - os.chdir("..") - collect_files("glTF-Sample-Models/2.0/", ".glb", "cgltf_test") - collect_files("glTF-Sample-Models/2.0/", ".gltf", "cgltf_test") - collect_files("glTF-Sample-Models/2.0/", ".glb", "test_conversion") - collect_files("glTF-Sample-Models/2.0/", ".gltf", "test_conversion") - collect_files("glTF-Sample-Models/2.0/", ".gltf", "test_write") - - result = os.system(get_executable_path("test_math")) - if result != 0: - num_errors = num_errors + 1 - print("Error.") - sys.exit(1) - - result = os.system(get_executable_path("test_strings")) - if result != 0: - num_errors = num_errors + 1 - print("Error.") - sys.exit(1) - - print("Tested files: " + str(num_tested)) - print("Errors: " + str(num_errors)) diff --git a/source/engine/thirdparty/cgltf/test/test_conversion.cpp b/source/engine/thirdparty/cgltf/test/test_conversion.cpp deleted file mode 100644 index e5217f3..0000000 --- a/source/engine/thirdparty/cgltf/test/test_conversion.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#define CGLTF_IMPLEMENTATION -#include "../cgltf.h" - -#include -#include -#include -#include - -static bool is_near(cgltf_float a, cgltf_float b) -{ - return std::abs(a - b) < 10 * std::numeric_limits::min(); -} - -int main(int argc, char** argv) -{ - if (argc < 2) - { - printf("err\n"); - return -1; - } - - cgltf_options options = {}; - cgltf_data* data = NULL; - cgltf_result result = cgltf_parse_file(&options, argv[1], &data); - - if (result == cgltf_result_success) - result = cgltf_load_buffers(&options, data, argv[1]); - - if (strstr(argv[1], "Draco")) - { - cgltf_free(data); - return 0; - } - - if (result != cgltf_result_success) - return result; - - //const cgltf_accessor* blobs = data->accessors; - cgltf_float element_float[16]; - cgltf_uint element_uint[4]; - for (cgltf_size blob_index = 0; blob_index < data->accessors_count; ++blob_index) - { - const cgltf_accessor* blob = data->accessors + blob_index; - if (blob->is_sparse) - { - cgltf_size nfloats = cgltf_num_components(blob->type) * blob->count; - cgltf_float* dense = (cgltf_float*) malloc(nfloats * sizeof(cgltf_float)); - if (cgltf_accessor_unpack_floats(blob, dense, nfloats) < nfloats) { - printf("Unable to completely unpack a sparse accessor.\n"); - return -1; - } - free(dense); - continue; - } - if (blob->has_max && blob->has_min) - { - cgltf_float min0 = std::numeric_limits::max(); - cgltf_float max0 = std::numeric_limits::lowest(); - for (cgltf_size index = 0; index < blob->count; index++) - { - cgltf_accessor_read_float(blob, index, element_float, 16); - min0 = std::min(min0, element_float[0]); - max0 = std::max(max0, element_float[0]); - } - if (!is_near(min0, blob->min[0]) || !is_near(max0, blob->max[0])) - { - printf("Computed [%f, %f] but expected [%f, %f]\n", min0, max0, blob->min[0], blob->max[0]); - return -1; - } - } - if (blob->has_max && blob->has_min && blob->component_type != cgltf_component_type_r_32f && blob->component_type != cgltf_component_type_invalid) - { - cgltf_uint min0 = std::numeric_limits::max(); - cgltf_uint max0 = std::numeric_limits::lowest(); - for ( cgltf_size index = 0; index < blob->count; index++ ) - { - cgltf_accessor_read_uint( blob, index, element_uint, 4 ); - min0 = std::min( min0, element_uint[0] ); - max0 = std::max( max0, element_uint[0] ); - } - if ( min0 != (unsigned int) blob->min[0] || max0 != (unsigned int) blob->max[0] ) - { - printf( "Computed [%u, %u] but expected [%u, %u]\n", min0, max0, (unsigned int) blob->min[0], (unsigned int) blob->max[0] ); - return -1; - } - } - } - - cgltf_free(data); - - return result; -} diff --git a/source/engine/thirdparty/cgltf/test/test_math.cpp b/source/engine/thirdparty/cgltf/test/test_math.cpp deleted file mode 100644 index 84f9305..0000000 --- a/source/engine/thirdparty/cgltf/test/test_math.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#define CGLTF_IMPLEMENTATION -#include "../cgltf.h" - -// Performs matrix-vector multiplication, as in (4x4) * (4x1) = (4x1) -static void transform(const cgltf_float matrix[16], const cgltf_float source[4], cgltf_float target[4]) { - target[0] = matrix[0] * source[0] + matrix[4] * source[1] + matrix[ 8] * source[2] + matrix[12] * source[3]; - target[1] = matrix[1] * source[0] + matrix[5] * source[1] + matrix[ 9] * source[2] + matrix[13] * source[3]; - target[2] = matrix[2] * source[0] + matrix[6] * source[1] + matrix[10] * source[2] + matrix[14] * source[3]; - target[3] = matrix[3] * source[0] + matrix[7] * source[1] + matrix[11] * source[2] + matrix[15] * source[3]; -} - -static void set(cgltf_float target[3], float x, float y, float z) { - target[0] = x; - target[1] = y; - target[2] = z; -} - -static void check(cgltf_float target[3], float x, float y, float z) { - if (target[0] != x || target[1] != y || target[2] != z) { - fprintf(stderr, "Mismatch detected.\n"); - exit(1); - } -} - -int main(int, char**) -{ - cgltf_node node = {}; - - cgltf_float matrix[16]; - cgltf_float source[4] = {1, 2, 3, 1}; - cgltf_float target[4]; - - set(node.scale, 1, 1, 1); - set(node.translation, 1, 0, 0); - cgltf_node_transform_local(&node, matrix); - transform(matrix, source, target); - check(target, 2, 2, 3); - - set(node.scale, 3, 1, 1); - set(node.translation, 0, 0, 0); - cgltf_node_transform_local(&node, matrix); - transform(matrix, source, target); - check(target, 3, 2, 3); - - set(node.scale, 1, 3, 1); - set(node.translation, 1, 0, 0); - cgltf_node_transform_local(&node, matrix); - transform(matrix, source, target); - check(target, 2, 6, 3); - - return 0; -} diff --git a/source/engine/thirdparty/cgltf/test/test_strings.cpp b/source/engine/thirdparty/cgltf/test/test_strings.cpp deleted file mode 100644 index 3d63efc..0000000 --- a/source/engine/thirdparty/cgltf/test/test_strings.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#define CGLTF_IMPLEMENTATION -#include "../cgltf.h" - -#include - -static void check(const char* a, const char* b, cgltf_size size) { - if (strcmp(a, b) != 0 || strlen(a) != size) { - fprintf(stderr, "Mismatch detected.\n"); - exit(1); - } -} - -int main(int, char**) -{ - char string[64]; - cgltf_size size; - - // cgltf_decode_string - strcpy(string, ""); - size = cgltf_decode_string(string); - check(string, "", size); - - strcpy(string, "nothing to replace"); - size = cgltf_decode_string(string); - check(string, "nothing to replace", size); - - strcpy(string, "\\\" \\/ \\\\ \\b \\f \\r \\n \\t \\u0030"); - size = cgltf_decode_string(string); - check(string, "\" / \\ \b \f \r \n \t 0", size); - - strcpy(string, "test \\u121b\\u130d\\u1294\\u1276\\u127d test"); - size = cgltf_decode_string(string); - check(string, "test ማግኔቶች test", size); - - // cgltf_decode_uri - strcpy(string, ""); - size = cgltf_decode_uri(string); - check(string, "", size); - - strcpy(string, "nothing to replace"); - size = cgltf_decode_uri(string); - check(string, "nothing to replace", size); - - strcpy(string, "%2F%D0%BA%D0%B8%D1%80%D0%B8%D0%BB%D0%BB%D0%B8%D1%86%D0%B0"); - size = cgltf_decode_uri(string); - check(string, "/кириллица", size); - - strcpy(string, "test%20%E1%88%9B%E1%8C%8D%E1%8A%94%E1%89%B6%E1%89%BD%20test"); - size = cgltf_decode_uri(string); - check(string, "test ማግኔቶች test", size); - - strcpy(string, "%%2F%X%AX%%2F%%"); - size = cgltf_decode_uri(string); - check(string, "%/%X%AX%/%%", size); - - return 0; -} diff --git a/source/engine/thirdparty/cgltf/test/test_write.cpp b/source/engine/thirdparty/cgltf/test/test_write.cpp deleted file mode 100644 index b7ee25d..0000000 --- a/source/engine/thirdparty/cgltf/test/test_write.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#define CGLTF_IMPLEMENTATION -#define CGLTF_WRITE_IMPLEMENTATION -#include "../cgltf_write.h" - -#include -#include -#include -#include - -int main(int argc, char** argv) -{ - if (argc < 2) - { - printf("err\n"); - return -1; - } - - cgltf_options options = {}; - cgltf_data* data0 = NULL; - cgltf_result result = cgltf_parse_file(&options, argv[1], &data0); - - // Silently skip over files that are unreadable since this is a writing test. - if (result != cgltf_result_success) - { - return cgltf_result_success; - } - - result = cgltf_write_file(&options, "out.gltf", data0); - if (result != cgltf_result_success) - { - return result; - } - cgltf_data* data1 = NULL; - result = cgltf_parse_file(&options, "out.gltf", &data1); - if (result != cgltf_result_success) - { - return result; - } - if (data0->meshes_count != data1->meshes_count) { - return -1; - } - cgltf_free(data1); - cgltf_free(data0); - return cgltf_result_success; -} diff --git a/source/engine/thirdparty/dr_libs/.github/FUNDING.yml b/source/engine/thirdparty/dr_libs/.github/FUNDING.yml deleted file mode 100644 index fb80301..0000000 --- a/source/engine/thirdparty/dr_libs/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: mackron diff --git a/source/engine/thirdparty/dr_libs/.gitignore b/source/engine/thirdparty/dr_libs/.gitignore deleted file mode 100644 index b31d733..0000000 --- a/source/engine/thirdparty/dr_libs/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -docs -tests/testvectors/opus/* -!tests/testvectors/opus/DO_NOT_DELETE.md -tests/bin/* -!tests/bin/DO_NOT_DELETE.md -tests/build -tests/flac/include -tests/flac/lib -tests/testvectors/flac/tests/* -!tests/testvectors/flac/tests/DO_NOT_DELETE.md -todo -_private \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/.gitmodules b/source/engine/thirdparty/dr_libs/.gitmodules deleted file mode 100644 index c4d4547..0000000 --- a/source/engine/thirdparty/dr_libs/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tests/external/miniaudio"] - path = tests/external/miniaudio - url = https://github.com/dr-soft/miniaudio.git diff --git a/source/engine/thirdparty/dr_libs/old/dr.h b/source/engine/thirdparty/dr_libs/old/dr.h deleted file mode 100644 index fb13f95..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr.h +++ /dev/null @@ -1,4755 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. - -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_IMPLEMENTATION -// #include "dr.h" -// -// You can then #include dr.h in other parts of the program as you would with any other header file. -// -// -// -// OPTIONS -// -// #define DR_UTIL_WIN32_USE_CRITICAL_SECTION_MUTEX -// - Use the Win32 CRITICAL_SECTION API for mutex objects. - -#ifndef dr_util_h -#define dr_util_h - -#ifdef __cplusplus -extern "C" { -#endif - - -// Disable MSVC compatibility if we're compiling with it. -#if defined(_MSC_VER) || defined(__MINGW32__) - #define DR_NO_MSVC_COMPAT -#endif - -#if defined(_MSC_VER) -#define DR_INLINE static __inline -#else -#define DR_INLINE static inline -#endif - - -#include -#include -#include -#include - -#ifndef DR_NO_MSVC_COMPAT -#include -#endif - -#ifndef DR_SIZED_TYPES_DEFINED -#define DR_SIZED_TYPES_DEFINED -#if defined(_MSC_VER) && _MSC_VER < 1600 -typedef signed char dr_int8; -typedef unsigned char dr_uint8; -typedef signed short dr_int16; -typedef unsigned short dr_uint16; -typedef signed int dr_int32; -typedef unsigned int dr_uint32; -typedef signed __int64 dr_int64; -typedef unsigned __int64 dr_uint64; -#else -#include -typedef int8_t dr_int8; -typedef uint8_t dr_uint8; -typedef int16_t dr_int16; -typedef uint16_t dr_uint16; -typedef int32_t dr_int32; -typedef uint32_t dr_uint32; -typedef int64_t dr_int64; -typedef uint64_t dr_uint64; -#endif -typedef dr_uint8 dr_bool8; -typedef dr_uint32 dr_bool32; -#define DR_TRUE 1 -#define DR_FALSE 0 -#endif - - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) - - -///////////////////////////////////////////////////////// -// Annotations - -#ifndef IN -#define IN -#endif - -#ifndef OUT -#define OUT -#endif - -#ifndef UNUSED -#define UNUSED(x) ((void)(x)) -#endif - - -///////////////////////////////////////////////////////// -// min/max/clamp - -#ifndef dr_min -#define dr_min(x, y) (((x) < (y)) ? (x) : (y)) -#endif - -#ifndef dr_max -#define dr_max(x, y) (((x) > (y)) ? (x) : (y)) -#endif - -#ifndef dr_clamp -#define dr_clamp(x, low, high) (dr_max(low, dr_min(x, high))) -#endif - -#ifndef dr_round_up -#define dr_round_up(x, multiple) ((((x) + ((multiple) - 1)) / (multiple)) * (multiple)) -#endif - -#ifndef dr_round_up_signed -#define dr_round_up_signed(x, multiple) ((((x) + (((x) >= 0)*((multiple) - 1))) / (multiple)) * (multiple)) -#endif - -DR_INLINE dr_uint32 dr_next_power_of_2(dr_uint32 value) -{ - --value; - value = (value >> 1) | value; - value = (value >> 2) | value; - value = (value >> 4) | value; - value = (value >> 8) | value; - value = (value >> 16) | value; - return value + 1; -} - - -#define dr_abs(x) (((x) < 0) ? (-(x)) : (x)) - - -///////////////////////////////////////////////////////// -// MSVC Compatibility - -// A basic implementation of MSVC's strcpy_s(). -int dr_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src); - -// A basic implementation of MSVC's strncpy_s(). -int dr_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count); - -// A basic implementation of MSVC's strcat_s(). -int dr_strcat_s(char* dst, size_t dstSizeInBytes, const char* src); - -// A basic implementation of MSVC's strncat_s() -int dr_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count); - -// A basic implementation of MSVC's _atoi_s() -int dr_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix); - -#ifndef DR_NO_MSVC_COMPAT -#ifndef _TRUNCATE -#define _TRUNCATE ((size_t)-1) -#endif - -DR_INLINE int strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - return dr_strcpy_s(dst, dstSizeInBytes, src); -} - -DR_INLINE int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - return dr_strncpy_s(dst, dstSizeInBytes, src, count); -} - -DR_INLINE int strcat_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - return dr_strcat_s(dst, dstSizeInBytes, src); -} - -DR_INLINE int strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - return dr_strncat_s(dst, dstSizeInBytes, src, count); -} - -#ifndef __MINGW32__ -DR_INLINE int _stricmp(const char* string1, const char* string2) -{ - return strcasecmp(string1, string2); -} -#endif - -DR_INLINE int _itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) -{ - return dr_itoa_s(value, dst, dstSizeInBytes, radix); -} -#endif - - -///////////////////////////////////////////////////////// -// String Helpers - -// Determines if the given character is whitespace. -dr_bool32 dr_is_whitespace(dr_uint32 utf32); - -/// Removes every occurance of the given character from the given string. -void dr_strrmchar(char* str, char c); - -/// Finds the first non-whitespace character in the given string. -const char* dr_first_non_whitespace(const char* str); - -static inline const char* dr_ltrim(const char* str) { return dr_first_non_whitespace(str); } -static const char* dr_rtrim(const char* str); - -/// Trims both the leading and trailing whitespace from the given string. -void dr_trim(char* str); - -/// Finds the first occurance of a whitespace character in the given string. -const char* dr_first_whitespace(const char* str); - -/// Finds the beginning of the next line. -const char* dr_next_line(const char* str); - -/// Makes a copy of the first line of the given string. -size_t dr_copy_line(const char* str, char* lineOut, size_t lineOutSize); - -// A slow string replace function. Free the returned string with free(). -char* dr_string_replace(const char* src, const char* query, const char* replacement); - -// Replaces an ASCII character with another in the given string. -void dr_string_replace_ascii(char* src, char c, char replacement); - - -///////////////////////////////////////////////////////// -// Unicode Utilities - -/// Converts a UTF-32 character to UTF-16. -/// -/// @param utf16 [in] A pointer to an array of at least two 16-bit values that will receive the UTF-16 character. -/// -/// @return 2 if the returned character is a surrogate pair, 1 if it's a simple UTF-16 code point, or 0 if it's an invalid character. -/// -/// @remarks -/// It is assumed the is large enough to hold at least 2 unsigned shorts. will be padded with 0 for unused -/// components. -DR_INLINE int dr_utf32_to_utf16_ch(unsigned int utf32, unsigned short utf16[2]) -{ - if (utf16 == NULL) { - return 0; - } - - if (utf32 < 0xD800 || (utf32 >= 0xE000 && utf32 <= 0xFFFF)) - { - utf16[0] = (unsigned short)utf32; - utf16[1] = 0; - return 1; - } - else - { - if (utf32 >= 0x10000 && utf32 <= 0x10FFFF) - { - utf16[0] = (unsigned short)(0xD7C0 + (unsigned short)(utf32 >> 10)); - utf16[1] = (unsigned short)(0xDC00 + (unsigned short)(utf32 & 0x3FF)); - return 2; - } - else - { - // Invalid. - utf16[0] = 0; - utf16[1] = 0; - return 0; - } - } -} - -/// Converts a UTF-16 character to UTF-32. -DR_INLINE unsigned int dr_utf16_to_utf32_ch(unsigned short utf16[2]) -{ - if (utf16 == NULL) { - return 0; - } - - if (utf16[0] < 0xD800 || utf16[0] > 0xDFFF) - { - return utf16[0]; - } - else - { - if ((utf16[0] & 0xFC00) == 0xD800 && (utf16[1] & 0xFC00) == 0xDC00) - { - return ((unsigned int)utf16[0] << 10) + utf16[1] - 0x35FDC00; - } - else - { - // Invalid. - return 0; - } - } -} - -/// Converts a UTF-16 surrogate pair to UTF-32. -DR_INLINE unsigned int dr_utf16pair_to_utf32_ch(unsigned short utf160, unsigned short utf161) -{ - unsigned short utf16[2]; - utf16[0] = utf160; - utf16[1] = utf161; - return dr_utf16_to_utf32_ch(utf16); -} - - -///////////////////////////////////////////////////////// -// Aligned Allocations - -#ifndef DRUTIL_NO_ALIGNED_MALLOC -DR_INLINE void* dr_aligned_malloc(size_t alignment, size_t size) -{ -#if defined(_WIN32) || defined(_WIN64) - return _aligned_malloc(size, alignment); -#else - void* pResult; - if (posix_memalign(&pResult, alignment, size) == 0) { - return pResult; - } - - return 0; -#endif -} - -DR_INLINE void dr_aligned_free(void* ptr) -{ -#if defined(_WIN32) || defined(_WIN64) - _aligned_free(ptr); -#else - free(ptr); -#endif -} -#endif // !DRUTIL_NO_ALIGNED_MALLOC - - - -///////////////////////////////////////////////////////// -// Key/Value Pair Parsing - -typedef size_t (* dr_key_value_read_proc) (void* pUserData, void* pDataOut, size_t bytesToRead); -typedef void (* dr_key_value_pair_proc) (void* pUserData, const char* key, const char* value); -typedef void (* dr_key_value_error_proc)(void* pUserData, const char* message, unsigned int line); - -/// Parses a series of simple Key/Value pairs. -/// -/// @remarks -/// This function is suitable for parsing simple key/value config files. -/// @par -/// This function will never allocate memory on the heap. Because of this there is a minor restriction in the length of an individual -/// key/value pair which is 4KB. -/// @par -/// Formatting rules are as follows: -/// - The basic syntax for a key/value pair is [key][whitespace][value]. Example: MyProperty 1234 -/// - All key/value pairs must be declared on a single line, and a single line cannot contain more than a single key/value pair. -/// - Comments begin with the '#' character and continue until the end of the line. -/// - A key cannot contain spaces but are permitted in values. -/// - The value will have any leading and trailing whitespace trimmed. -/// @par -/// If an error occurs, that line will be skipped and processing will continue. -void dr_parse_key_value_pairs(dr_key_value_read_proc onRead, dr_key_value_pair_proc onPair, dr_key_value_error_proc onError, void* pUserData); - -// This will only return DR_FALSE if the file fails to open. It will still return DR_TRUE even if there are syntax error or whatnot. -dr_bool32 dr_parse_key_value_pairs_from_file(const char* filePath, dr_key_value_pair_proc onPair, dr_key_value_error_proc onError, void* pUserData); - - - -///////////////////////////////////////////////////////// -// Basic Tokenizer - -/// Retrieves the first token in the given string. -/// -/// @remarks -/// This function is suitable for doing a simple whitespace tokenization of a null-terminated string. -/// @par -/// The return value is a pointer to one character past the last character of the next token. You can use the return value to execute -/// this function in a loop to parse an entire string. -/// @par -/// can be null. If the buffer is too small to contain the entire token it will be set to an empty string. The original -/// input string combined with the return value can be used to reliably find the token. -/// @par -/// This will handle double-quoted strings, so a string such as "My \"Complex String\"" contains two tokens: "My" and "\"Complex String\"". -/// @par -/// This function has no dependencies. -const char* dr_next_token(const char* tokens, char* tokenOut, size_t tokenOutSize); - - - -///////////////////////////////////////////////////////// -// Known Folders - -/// Retrieves the path of the executable. -/// -/// @remarks -/// Currently only works on Windows and Linux. Other platforms will be added as they're needed. -dr_bool32 dr_get_executable_path(char* pathOut, size_t pathOutSize); - -/// Retrieves the path of the directory containing the executable. -/// -/// @remarks -/// Currently only works on Windows and Linux. Other platforms will be added as they're needed. -dr_bool32 dr_get_executable_directory_path(char* pathOut, size_t pathOutSize); - -/// Retrieves the path of the user's config directory. -/// -/// @remarks -/// On Windows this will typically be %APPDATA% and on Linux it will usually be ~/.config -dr_bool32 dr_get_config_folder_path(char* pathOut, size_t pathOutSize); - -/// Retrieves the path of the user's log directory. -/// -/// @remarks -/// On Windows this will typically be %APPDATA% and on Linux it will usually be var/log -dr_bool32 dr_get_log_folder_path(char* pathOut, size_t pathOutSize); - -/// Retrieves the current directory. -const char* dr_get_current_directory(char* pathOut, size_t pathOutSize); - -/// Sets the current directory. -dr_bool32 dr_set_current_directory(const char* path); - - - -///////////////////////////////////////////////////////// -// Basic File Management - -// Callback function for file iteration. -typedef dr_bool32 (* dr_iterate_files_proc)(const char* filePath, void* pUserData); - - -// Helper for opening a stdio FILE. -FILE* dr_fopen(const char* fileName, const char* openMode); - -// Helper for creating an empty file. -dr_bool32 dr_create_empty_file(const char* fileName, dr_bool32 failIfExists); - -// Retrieves the file data of the given file. Free the returned pointer with dr_free_file_data(). -void* dr_open_and_read_file(const char* filePath, size_t* pFileSizeOut); - -// Retrieves the file data of the given file as a null terminated string. Free the returned pointer with dr_free_file_data(). The -// returned file size is the length of the string not including the null terminator. -char* dr_open_and_read_text_file(const char* filePath, size_t* pFileSizeOut); - -// Creates a new file with the given data. -dr_bool32 dr_open_and_write_file(const char* filePath, const void* pData, size_t dataSize); - -// Creates a new file with the given string. -dr_bool32 dr_open_and_write_text_file(const char* filePath, const char* text); - -// Frees the file data returned by dr_open_and_read_file(). -void dr_free_file_data(void* valueReturnedByOpenAndReadFile); - -// Determines whether or not the given file path is to a file. -// -// This will return DR_FALSE if the path points to a directory. -dr_bool32 dr_file_exists(const char* filePath); - -// Determines whether or not the given file path points to a directory. -// -// This will return DR_FALSE if the path points to a file. -dr_bool32 dr_directory_exists(const char* directoryPath); -static inline dr_bool32 dr_is_directory(const char* directoryPath) { return dr_directory_exists(directoryPath); } - -// Moves a file. -// -// This uses rename() on POSIX platforms and MoveFileEx(oldPath, newPath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH) on windows platforms. -dr_bool32 dr_move_file(const char* oldPath, const char* newPath); - -// Copies a file. -dr_bool32 dr_copy_file(const char* srcPath, const char* dstPath, dr_bool32 failIfExists); - -// Determines if the given file is read only. -dr_bool32 dr_is_file_read_only(const char* filePath); - -// Retrieves the last modified time of the file at the given path. -dr_uint64 dr_get_file_modified_time(const char* filePath); - -// Deletes the file at the given path. -// -// This uses remove() on POSIX platforms and DeleteFile() on Windows platforms. -dr_bool32 dr_delete_file(const char* filePath); - -// Cross-platform wrapper for creating a directory. -dr_bool32 dr_mkdir(const char* directoryPath); - -// Recursively creates a directory. -dr_bool32 dr_mkdir_recursive(const char* directoryPath); - -// Iterates over every file and folder of the given directory. -dr_bool32 dr_iterate_files(const char* directory, dr_bool32 recursive, dr_iterate_files_proc proc, void* pUserData); - - -///////////////////////////////////////////////////////// -// DPI Awareness - -#if defined(_WIN32) -/// Win32 Only: Makes the application DPI aware. -void dr_win32_make_dpi_aware(); - -/// Win32 Only: Retrieves the base DPI to use as a reference when calculating DPI scaling. -void dr_win32_get_base_dpi(int* pDPIXOut, int* pDPIYOut); - -/// Win32 Only: Retrieves the system-wide DPI. -void dr_win32_get_system_dpi(int* pDPIXOut, int* pDPIYOut); - -/// Win32 Only: Retrieves the actual DPI of the monitor at the given index. -/// -/// @remarks -/// If per-monitor DPI is not supported, the system wide DPI settings will be used instead. -/// @par -/// This runs in linear time. -void dr_win32_get_monitor_dpi(int monitor, int* pDPIXOut, int* pDPIYOut); - -/// Win32 Only: Retrieves the number of monitors active at the time of calling. -/// -/// @remarks -/// This runs in linear time. -int dr_win32_get_monitor_count(); -#endif - - - -///////////////////////////////////////////////////////// -// Date / Time - -/// Retrieves a time_t as of the time the function was called. -time_t dr_now(); - -/// Formats a data/time string. -void dr_datetime_short(time_t t, char* strOut, unsigned int strOutSize); - -// Returns a date string in YYYYMMDD format. -void dr_date_YYYYMMDD(time_t t, char* strOut, unsigned int strOutSize); - - - -///////////////////////////////////////////////////////// -// Command Line -// -// The command line functions below are just simple iteration functions. This command line system is good for -// simple command lines, but probably not the best for programs requiring complex command line work. -// -// For argv style command lines, parse_cmdline() will run without any heap allocations. With a Win32 style -// command line there will be one malloc() per call fo parse_cmdline(). This is the only function that will do -// a malloc(). -// -// Below is an example: -// -// dr_cmdline cmdline; -// if (dr_init_cmdline(&cmdline, argc, argv)) { -// dr_parse_cmdline(&cmdline, my_cmdline_handler, pMyUserData); -// } -// -// void my_cmdline_handler(const char* key, const char* value, void* pUserData) -// { -// // Do something... -// } -// -// -// When parsing the command line, the first iteration will be the program path and the key will be "[path]". -// -// For segments such as "-abcd", the callback will be called for "a", "b", "c", "d" individually, with the -// value set to NULL. -// -// For segments such as "--server", the callback will be called for "server", with the value set to NULL. -// -// For segments such as "-f file.txt", the callback will be called with the key set to "f" and the value set -// to "file.txt". -// -// For segments such as "-f file1.txt file2.txt", the callback will be called twice, once for file1.txt and -// again for file2.txt, with with the key set to "f" in both cases. -// -// For segments where there is no leading key, the values will be posted as annonymous (key set to NULL). An example -// is "my_program.exe file1.txt file2.txt", in which case the first iteration will be the program path, the second iteration -// will be "file1.txt", with the key set to NULL. The third iteration will be "file2.txt" with the key set to NULL. -// -// For segments such as "-abcd file.txt", "a", "b", "c", "d" will be sent with NULL values, and "file.txt" will be -// posted with a NULL key. - -typedef struct dr_cmdline dr_cmdline; -struct dr_cmdline -{ - // argv style. - int argc; - char** argv; - - // Win32 style - const char* win32; -}; - -typedef dr_bool32 dr_cmdline_parse_proc(const char* key, const char* value, void* pUserData); - - -/// Initializes a command line object. -dr_bool32 dr_init_cmdline(dr_cmdline* pCmdLine, int argc, char** argv); - -/// Initializes a command line object using a Win32 style command line. -dr_bool32 dr_init_cmdline_win32(dr_cmdline* pCmdLine, const char* args); - -/// Parses the given command line. -void dr_parse_cmdline(dr_cmdline* pCmdLine, dr_cmdline_parse_proc callback, void* pUserData); - -/// Helper for determining whether or not the given key exists. -dr_bool32 dr_cmdline_key_exists(dr_cmdline* pCmdLine, const char* key); - -// Convers the given command line object to argc/argv style. -// -// Returns the argument count. Returns 0 if an error occurs. Free "argvOut" with dr_free_argv(). -int dr_cmdline_to_argv(dr_cmdline* pCmdLine, char*** argvOut); - -// Converts a WinMain style command line to argc/argv. -// -// Returns the argument count. Returns 0 if an error occurs. Free "argvOut" with dr_free_argv(). -int dr_winmain_to_argv(const char* cmdlineWinMain, char*** argvOut); - -// Frees the argc/argv command line that was generated by dr.h -void dr_free_argv(char** argv); - - - - -///////////////////////////////////////////////////////// -// Threading - -/// Puts the calling thread to sleep for approximately the given number of milliseconds. -/// -/// @remarks -/// This is not 100% accurate and should be considered an approximation. -void dr_sleep(unsigned int milliseconds); -void dr_yield(); - -/// Retrieves the number of logical cores on system. -unsigned int dr_get_logical_processor_count(); - - -/// Thread. -typedef void* dr_thread; -typedef int (* dr_thread_entry_proc)(void* pData); - -/// Creates and begins executing a new thread. -/// -/// @remarks -/// This will not return until the thread has entered into it's entry point. -/// @par -/// Creating a thread should be considered an expensive operation. For high performance, you should create threads -/// at load time and cache them. -dr_thread dr_create_thread(dr_thread_entry_proc entryProc, void* pData); - -/// Deletes the given thread. -/// -/// @remarks -/// This does not actually exit the thread, but rather deletes the memory that was allocated for the thread -/// object returned by dr_create_thread(). -/// @par -/// It is usually best to wait for the thread to terminate naturally with dr_wait_thread() before calling -/// this function, however it is still safe to do something like the following. -/// @code -/// dr_delete_thread(dr_create_thread(my_thread_proc, pData)) -/// @endcode -void dr_delete_thread(dr_thread thread); - -/// Waits for the given thread to terminate. -void dr_wait_thread(dr_thread thread); - -/// Helper function for waiting for a thread and then deleting the handle after it has terminated. -void dr_wait_and_delete_thread(dr_thread thread); - - - -/// Mutex -typedef void* dr_mutex; - -/// Creates a mutex object. -/// -/// @remarks -/// If an error occurs, 0 is returned. Otherwise a handle the size of a pointer is returned. -dr_mutex dr_create_mutex(); - -/// Deletes a mutex object. -void dr_delete_mutex(dr_mutex mutex); - -/// Locks the given mutex. -void dr_lock_mutex(dr_mutex mutex); - -/// Unlocks the given mutex. -void dr_unlock_mutex(dr_mutex mutex); - - - -/// Semaphore -typedef void* dr_semaphore; - -/// Creates a semaphore object. -/// -/// @remarks -/// If an error occurs, 0 is returned. Otherwise a handle the size of a pointer is returned. -dr_semaphore dr_create_semaphore(int initialValue); - -/// Deletes the given semaphore. -void dr_delete_semaphore(dr_semaphore semaphore); - -/// Waits on the given semaphore object and decrements it's counter by one upon returning. -dr_bool32 dr_wait_semaphore(dr_semaphore semaphore); - -/// Releases the given semaphore and increments it's counter by one upon returning. -dr_bool32 dr_release_semaphore(dr_semaphore semaphore); - - - -///////////////////////////////////////////////////////// -// Timing - -typedef struct -{ - dr_int64 counter; -} dr_timer; - -// Initializes a high-resolution timer. -void dr_timer_init(dr_timer* pTimer); - -// Ticks the timer and returns the number of seconds since the previous tick. -// -// The maximum return value is about 140 years or so. -double dr_timer_tick(dr_timer* pTimer); - - - - -///////////////////////////////////////////////////////// -// Random - -// Generates a random double between 0 and 1. This is bassed of C standard rand(). -double dr_randd(); - -// Generates a random float between 0 and 1. This is based off C standard rand(). -float dr_randf(); - - - -///////////////////////////////////////////////////////// -// User Accounts and Process Management - -// Retrieves the user name of the user running the application. -size_t dr_get_username(char* usernameOut, size_t usernameOutSize); - -// Retrieves the ID of the current process. -unsigned int dr_get_process_id(); - - - - -///////////////////////////////////////////////////////// -// Miscellaneous Stuff. - -// Helper for clearing the given object to 0. -#define dr_zero_object(pObject) memset(pObject, 0, sizeof(*pObject)); - -// Converts an ASCII hex character to it's integral equivalent. Returns DR_FALSE if it's not a valid hex character. -dr_bool32 dr_hex_char_to_uint(char ascii, unsigned int* out); - - -///////////////////////////////////////////////////////// -// C++ Specific - -#ifdef __cplusplus - -// Use this to prevent objects of the given class or struct from being copied. This is also useful for eliminating some -// compiler warnings. -// -// Note for structs - this sets the access mode to private, so place this at the end of the declaration. -#define NO_COPY(classname) \ - private: \ - classname(const classname &); \ - classname & operator=(const classname &); - - -#ifndef DR_NO_MSVC_COMPAT -extern "C++" -{ - -template -int strcpy_s(char (&dst)[dstSizeInBytes], const char* src) -{ - return strcpy_s(dst, dstSizeInBytes, src); -} - -template -int strncpy_s(char (&dst)[dstSizeInBytes], const char* src, size_t count) -{ - return strncpy_s(dst, dstSizeInBytes, src, count); -} - -template -int strcat_s(char (&dst)[dstSizeInBytes], const char* src) -{ - return strcat_s(dst, dstSizeInBytes, src); -} - -template -int strncat_s(char (&dst)[dstSizeInBytes], const char* src, size_t count) -{ - return strncat_s(dst, dstSizeInBytes, src, count); -} - -} -#endif - -#endif - - - -#ifdef __cplusplus -} -#endif - -#endif //dr_util_h - - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// - -#ifdef DR_IMPLEMENTATION -#include -#include -#include -#include // For memmove() -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#include -#include -#include -#endif - -int dr_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t i; - for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstSizeInBytes) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -} - -int dr_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t maxcount = count; - if (count == ((size_t)-1) || count >= dstSizeInBytes) { // -1 = _TRUNCATE - maxcount = dstSizeInBytes - 1; - } - - size_t i; - for (i = 0; i < maxcount && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (src[i] == '\0' || i == count || count == ((size_t)-1)) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -} - -int dr_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - char* dstorig = dst; - - while (dstSizeInBytes > 0 && dst[0] != '\0') { - dst += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - return EINVAL; // Unterminated. - } - - - while (dstSizeInBytes > 0 && src[0] != '\0') { - *dst++ = *src++; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes > 0) { - dst[0] = '\0'; - } else { - dstorig[0] = '\0'; - return ERANGE; - } - - return 0; -} - -int dr_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - return EINVAL; - } - - char* dstorig = dst; - - while (dstSizeInBytes > 0 && dst[0] != '\0') { - dst += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - return EINVAL; // Unterminated. - } - - - if (count == ((size_t)-1)) { // _TRUNCATE - count = dstSizeInBytes - 1; - } - - while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) - { - *dst++ = *src++; - dstSizeInBytes -= 1; - count -= 1; - } - - if (dstSizeInBytes > 0) { - dst[0] = '\0'; - } else { - dstorig[0] = '\0'; - return ERANGE; - } - - return 0; -} - -int dr_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) -{ - if (dst == NULL || dstSizeInBytes == 0) { - return EINVAL; - } - if (radix < 2 || radix > 36) { - dst[0] = '\0'; - return EINVAL; - } - - int sign = (value < 0 && radix == 10) ? -1 : 1; // The negative sign is only used when the base is 10. - - unsigned int valueU; - if (value < 0) { - valueU = -value; - } else { - valueU = value; - } - - char* dstEnd = dst; - do - { - int remainder = valueU % radix; - if (remainder > 9) { - *dstEnd = (char)((remainder - 10) + 'a'); - } else { - *dstEnd = (char)(remainder + '0'); - } - - dstEnd += 1; - dstSizeInBytes -= 1; - valueU /= radix; - } while (dstSizeInBytes > 0 && valueU > 0); - - if (dstSizeInBytes == 0) { - dst[0] = '\0'; - return EINVAL; // Ran out of room in the output buffer. - } - - if (sign < 0) { - *dstEnd++ = '-'; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - dst[0] = '\0'; - return EINVAL; // Ran out of room in the output buffer. - } - - *dstEnd = '\0'; - - - // At this point the string will be reversed. - dstEnd -= 1; - while (dst < dstEnd) { - char temp = *dst; - *dst = *dstEnd; - *dstEnd = temp; - - dst += 1; - dstEnd -= 1; - } - - return 0; -} - -///////////////////////////////////////////////////////// -// String Helpers - -dr_bool32 dr_is_whitespace(dr_uint32 utf32) -{ - return utf32 == ' ' || utf32 == '\t' || utf32 == '\n' || utf32 == '\v' || utf32 == '\f' || utf32 == '\r'; -} - -void dr_strrmchar(char* str, char c) -{ - char* src = str; - char* dst = str; - - while (src[0] != '\0') - { - dst[0] = src[0]; - - if (dst[0] != c) { - dst += 1; - } - - src += 1; - } - - dst[0] = '\0'; -} - -const char* dr_first_non_whitespace(const char* str) -{ - if (str == NULL) { - return NULL; - } - - while (str[0] != '\0' && !(str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != '\v' && str[0] != '\f' && str[0] != '\r')) { - str += 1; - } - - return str; -} - -const char* dr_first_whitespace(const char* str) -{ - if (str == NULL) { - return NULL; - } - - while (str[0] != '\0' && (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != '\v' && str[0] != '\f' && str[0] != '\r')) { - str += 1; - } - - return str; -} - -const char* dr_rtrim(const char* str) -{ - if (str == NULL) { - return NULL; - } - - const char* rstr = str; - while (str[0] != '\0') { - if (dr_is_whitespace(str[0])) { - str += 1; - continue; - } - - str += 1; - rstr = str; - } - - return rstr; -} - -void dr_trim(char* str) -{ - if (str == NULL) { - return; - } - - const char* lstr = dr_ltrim(str); - const char* rstr = dr_rtrim(lstr); - - if (lstr > str) { - memmove(str, lstr, rstr-lstr); - } - - str[rstr-lstr] = '\0'; -} - -const char* dr_next_line(const char* str) -{ - if (str == NULL) { - return NULL; - } - - while (str[0] != '\0' && (str[0] != '\n' && !(str[0] == '\r' && str[1] == '\n'))) { - str += 1; - } - - if (str[0] == '\0') { - return NULL; - } - - if (str[0] == '\r') { - return str + 2; - } - - return str + 1; -} - -size_t dr_copy_line(const char* str, char* lineOut, size_t lineOutSize) -{ - if (str == NULL) { - return 0; - } - - if (str == NULL) { - return 0; - } - - size_t length = 0; - while (lineOutSize > 0 && str[0] != '\0' && (str[0] != '\n' && !(str[0] == '\r' && str[1] == '\n'))) { - *lineOut++ = *str++; - lineOutSize -= 1; - length += 1; - } - - if (lineOutSize == 0) { - return 0; - } - - *lineOut = '\0'; - return length; -} - -char* dr_string_replace(const char* src, const char* query, const char* replacement) -{ - // This function could be improved, but it's good enough for now. - - if (src == NULL || query == NULL) { - return NULL; - } - - if (replacement == NULL) { - replacement = ""; - } - - int queryLen = (int)strlen(query); - int replacementLen = (int)strlen(replacement); - - size_t replacementCount = 0; - - const char* temp = src; - for (;;) { - temp = strstr(temp, query); - if (temp == NULL) { - break; - } - - temp += queryLen; - replacementCount += 1; - } - - - char* result = (char*)malloc(strlen(src) + (replacementLen - queryLen)*replacementCount + 1); // +1 for null terminator. - if (result == NULL) { - return NULL; - } - - char* runningResult = result; - for (size_t i = 0; i < replacementCount; ++i) { - size_t len = strstr(src, query) - src; - for (size_t j = 0; j < len; ++j) { - runningResult[j] = src[j]; - } - - runningResult += len; - for (int j = 0; j < replacementLen; ++j) { - runningResult[j] = replacement[j]; - } - - runningResult += replacementLen; - src += len + queryLen; - } - - // The trailing part. - strcpy_s(runningResult, strlen(src)+1, src); - return result; -} - -void dr_string_replace_ascii(char* src, char c, char replacement) -{ - for (;;) { - if (*src == '\0') { - break; - } - - if (*src == c) { - *src = replacement; - } - - src += 1; - } -} - - -///////////////////////////////////////////////////////// -// Key/Value Pair Parsing - -void dr_parse_key_value_pairs(dr_key_value_read_proc onRead, dr_key_value_pair_proc onPair, dr_key_value_error_proc onError, void* pUserData) -{ - if (onRead == NULL) { - return; - } - - char pChunk[4096]; - size_t chunkSize = 0; - - unsigned int currentLine = 1; - - dr_bool32 moveToNextLineBeforeProcessing = DR_FALSE; - dr_bool32 skipWhitespaceBeforeProcessing = DR_FALSE; - - // Just keep looping. We'll break from this loop when we have run out of data. - for (;;) - { - // Start the iteration by reading as much data as we can. - chunkSize = onRead(pUserData, pChunk, sizeof(pChunk)); - if (chunkSize == 0) { - // No more data available. - return; - } - - char* pChunkEnd = pChunk + chunkSize; - char* pC = pChunk; // Chunk pointer. This is as the chunk is processed. - - if (moveToNextLineBeforeProcessing) - { - move_to_next_line: - while (pC < pChunkEnd && pC[0] != '\n') { - pC += 1; - } - - if (pC == pChunkEnd) { - // Ran out of data. Load the next chunk and keep going. - moveToNextLineBeforeProcessing = DR_TRUE; - continue; - } - - pC += 1; // pC[0] == '\n' - skip past the new line character. - currentLine += 1; - moveToNextLineBeforeProcessing = DR_FALSE; - } - - if (skipWhitespaceBeforeProcessing) - { - while (pC < pChunkEnd && (pC[0] == ' ' || pC[0] == '\t' || pC[0] == '\r')) { - pC += 1; - } - - if (pC == pChunkEnd) { - // Ran out of data. - skipWhitespaceBeforeProcessing = DR_TRUE; - continue; - } - - skipWhitespaceBeforeProcessing = DR_FALSE; - } - - - // We loop character by character. When we run out of data, we start again. - while (pC < pChunkEnd) - { - //// Key //// - - // Skip whitespace. - while (pC < pChunkEnd && (pC[0] == ' ' || pC[0] == '\t' || pC[0] == '\r')) { - pC += 1; - } - - if (pC == pChunkEnd) { - // Ran out of data. - skipWhitespaceBeforeProcessing = DR_TRUE; - continue; - } - - if (pC[0] == '\n') { - // Found the end of the line. - pC += 1; - currentLine += 1; - continue; - } - - if (pC[0] == '#') { - // Found a comment. Move to the end of the line and continue. - goto move_to_next_line; - } - - char* pK = pC; - while (pC < pChunkEnd && pC[0] != ' ' && pC[0] != '\t' && pC[0] != '\r' && pC[0] != '\n' && pC[0] != '#') { - pC += 1; - } - - if (pC == pChunkEnd) - { - // Ran out of data. We need to move what we have of the key to the start of the chunk buffer, and then read more data. - if (chunkSize == sizeof(pChunk)) - { - size_t lineSizeSoFar = pC - pK; - memmove(pChunk, pK, lineSizeSoFar); - - chunkSize = lineSizeSoFar + onRead(pUserData, pChunk + lineSizeSoFar, sizeof(pChunk) - lineSizeSoFar); - pChunkEnd = pChunk + chunkSize; - - pK = pChunk; - pC = pChunk + lineSizeSoFar; - while (pC < pChunkEnd && pC[0] != ' ' && pC[0] != '\t' && pC[0] != '\r' && pC[0] != '\n' && pC[0] != '#') { - pC += 1; - } - } - - if (pC == pChunkEnd) { - if (chunkSize == sizeof(pChunk)) { - if (onError) { - onError(pUserData, "Line is too long. A single line cannot exceed 4KB.", currentLine); - } - - goto move_to_next_line; - } else { - // No more data. Just treat this one as a value-less key and return. - if (onPair) { - pC[0] = '\0'; - onPair(pUserData, pK, NULL); - } - - return; - } - } - } - - char* pKEnd = pC; - - //// Value //// - - // Skip whitespace. - while (pC < pChunkEnd && (pC[0] == ' ' || pC[0] == '\t' || pC[0] == '\r')) { - pC += 1; - } - - if (pC == pChunkEnd) - { - // Ran out of data. We need to move what we have of the key to the start of the chunk buffer, and then read more data. - if (chunkSize == sizeof(pChunk)) - { - size_t lineSizeSoFar = pC - pK; - memmove(pChunk, pK, lineSizeSoFar); - - chunkSize = lineSizeSoFar + onRead(pUserData, pChunk + lineSizeSoFar, sizeof(pChunk) - lineSizeSoFar); - pChunkEnd = pChunk + chunkSize; - - pKEnd = pChunk + (pKEnd - pK); - pK = pChunk; - pC = pChunk + lineSizeSoFar; - while (pC < pChunkEnd && (pC[0] == ' ' || pC[0] == '\t' || pC[0] == '\r')) { - pC += 1; - } - } - - if (pC == pChunkEnd) { - if (chunkSize == sizeof(pChunk)) { - if (onError) { - onError(pUserData, "Line is too long. A single line cannot exceed 4KB.", currentLine); - } - - goto move_to_next_line; - } else { - // No more data. Just treat this one as a value-less key and return. - if (onPair) { - pKEnd[0] = '\0'; - onPair(pUserData, pK, NULL); - } - - return; - } - } - } - - if (pC[0] == '\n') { - // Found the end of the line. Treat it as a value-less key. - pKEnd[0] = '\0'; - if (onPair) { - onPair(pUserData, pK, NULL); - } - - pC += 1; - currentLine += 1; - continue; - } - - if (pC[0] == '#') { - // Found a comment. Treat is as a value-less key and move to the end of the line. - pKEnd[0] = '\0'; - if (onPair) { - onPair(pUserData, pK, NULL); - } - - goto move_to_next_line; - } - - char* pV = pC; - - // Find the last non-whitespace character. - char* pVEnd = pC; - while (pC < pChunkEnd && pC[0] != '\n' && pC[0] != '#') { - if (pC[0] != ' ' && pC[0] != '\t' && pC[0] != '\r') { - pVEnd = pC; - } - - pC += 1; - } - - if (pC == pChunkEnd) - { - // Ran out of data. We need to move what we have of the key to the start of the chunk buffer, and then read more data. - if (chunkSize == sizeof(pChunk)) - { - size_t lineSizeSoFar = pC - pK; - memmove(pChunk, pK, lineSizeSoFar); - - chunkSize = lineSizeSoFar + onRead(pUserData, pChunk + lineSizeSoFar, sizeof(pChunk) - lineSizeSoFar); - pChunkEnd = pChunk + chunkSize; - - pVEnd = pChunk + (pVEnd - pK); - pKEnd = pChunk + (pKEnd - pK); - pV = pChunk + (pV - pK); - pK = pChunk; - pC = pChunk + lineSizeSoFar; - while (pC < pChunkEnd && pC[0] != '\n' && pC[0] != '#') { - if (pC[0] != ' ' && pC[0] != '\t' && pC[0] != '\r') { - pVEnd = pC; - } - - pC += 1; - } - } - - if (pC == pChunkEnd) { - if (chunkSize == sizeof(pChunk)) { - if (onError) { - onError(pUserData, "Line is too long. A single line cannot exceed 4KB.", currentLine); - } - - goto move_to_next_line; - } - } - } - - - // Before null-terminating the value we first need to determine how we'll proceed after posting onPair. - dr_bool32 wasOnNL = pVEnd[1] == '\n'; - - pKEnd[0] = '\0'; - pVEnd[1] = '\0'; - if (onPair) { - onPair(pUserData, pK, pV); - } - - if (wasOnNL) - { - // Was sitting on a new-line character. - pC += 1; - currentLine += 1; - continue; - } - else - { - // Was sitting on a comment - just to the next line. - goto move_to_next_line; - } - } - } -} - - -typedef struct -{ - FILE* pFile; - dr_key_value_pair_proc onPair; - dr_key_value_error_proc onError; - void* pOriginalUserData; -} dr_parse_key_value_pairs_from_file_data; - -size_t dr_parse_key_value_pairs_from_file__on_read(void* pUserData, void* pDataOut, size_t bytesToRead) -{ - dr_parse_key_value_pairs_from_file_data* pData = (dr_parse_key_value_pairs_from_file_data*)pUserData; - assert(pData != NULL); - - return fread(pDataOut, 1, bytesToRead, pData->pFile); -} - -void dr_parse_key_value_pairs_from_file__on_pair(void* pUserData, const char* key, const char* value) -{ - dr_parse_key_value_pairs_from_file_data* pData = (dr_parse_key_value_pairs_from_file_data*)pUserData; - assert(pData != NULL); - - pData->onPair(pData->pOriginalUserData, key, value); -} - -void dr_parse_key_value_pairs_from_file__on_error(void* pUserData, const char* message, unsigned int line) -{ - dr_parse_key_value_pairs_from_file_data* pData = (dr_parse_key_value_pairs_from_file_data*)pUserData; - assert(pData != NULL); - - pData->onError(pData->pOriginalUserData, message, line); -} - -dr_bool32 dr_parse_key_value_pairs_from_file(const char* filePath, dr_key_value_pair_proc onPair, dr_key_value_error_proc onError, void* pUserData) -{ - dr_parse_key_value_pairs_from_file_data data; - data.pFile = dr_fopen(filePath, "rb"); - if (data.pFile == NULL) { - if (onError) onError(pUserData, "Could not open file.", 0); - return DR_FALSE; - } - - data.onPair = onPair; - data.onError = onError; - data.pOriginalUserData = pUserData; - dr_parse_key_value_pairs(dr_parse_key_value_pairs_from_file__on_read, dr_parse_key_value_pairs_from_file__on_pair, dr_parse_key_value_pairs_from_file__on_error, &data); - - fclose(data.pFile); - return DR_TRUE; -} - - -///////////////////////////////////////////////////////// -// Basic Tokenizer - -const char* dr_next_token(const char* tokens, char* tokenOut, size_t tokenOutSize) -{ - if (tokenOut) tokenOut[0] = '\0'; - - if (tokens == NULL) { - return NULL; - } - - // Skip past leading whitespace. - while (tokens[0] != '\0' && !(tokens[0] != ' ' && tokens[0] != '\t' && tokens[0] != '\n' && tokens[0] != '\v' && tokens[0] != '\f' && tokens[0] != '\r')) { - tokens += 1; - } - - if (tokens[0] == '\0') { - return NULL; - } - - - const char* strBeg = tokens; - const char* strEnd = strBeg; - - if (strEnd[0] == '\"') - { - // It's double-quoted - loop until the next unescaped quote character. - - // Skip past the first double-quote character. - strBeg += 1; - strEnd += 1; - - // Keep looping until the next unescaped double-quote character. - char prevChar = '\0'; - while (strEnd[0] != '\0' && (strEnd[0] != '\"' || prevChar == '\\')) - { - prevChar = strEnd[0]; - strEnd += 1; - } - } - else - { - // It's not double-quoted - just loop until the first whitespace. - while (strEnd[0] != '\0' && (strEnd[0] != ' ' && strEnd[0] != '\t' && strEnd[0] != '\n' && strEnd[0] != '\v' && strEnd[0] != '\f' && strEnd[0] != '\r')) { - strEnd += 1; - } - } - - - // If the output buffer is large enough to hold the token, copy the token into it. When we copy the token we need to - // ensure we don't include the escape character. - //assert(strEnd >= strBeg); - - while (tokenOutSize > 1 && strBeg < strEnd) - { - if (strBeg[0] == '\\' && strBeg[1] == '\"' && strBeg < strEnd) { - strBeg += 1; - } - - *tokenOut++ = *strBeg++; - tokenOutSize -= 1; - } - - // Null-terminate. - if (tokenOutSize > 0) { - *tokenOut = '\0'; - } - - - // Skip past the double-quote character before returning. - if (strEnd[0] == '\"') { - strEnd += 1; - } - - return strEnd; -} - - - - -///////////////////////////////////////////////////////// -// Known Folders - -#if defined(_WIN32) -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4091) // 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared -#endif -#include -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - - -dr_bool32 dr_get_executable_path(char* pathOut, size_t pathOutSize) -{ - if (pathOut == NULL || pathOutSize == 0) { - return 0; - } - - DWORD length = GetModuleFileNameA(NULL, pathOut, (DWORD)pathOutSize); - if (length == 0) { - pathOut[0] = '\0'; - return DR_FALSE; - } - - // Force null termination. - if (length == pathOutSize) { - pathOut[length - 1] = '\0'; - } - - // Back slashes need to be normalized to forward. - while (pathOut[0] != '\0') { - if (pathOut[0] == '\\') { - pathOut[0] = '/'; - } - - pathOut += 1; - } - - return DR_TRUE; -} - -dr_bool32 dr_get_config_folder_path(char* pathOut, size_t pathOutSize) -{ - // The documentation for SHGetFolderPathA() says that the output path should be the size of MAX_PATH. We'll enforce - // that just to be safe. - if (pathOutSize >= MAX_PATH) - { - SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pathOut); - } - else - { - char pathOutTemp[MAX_PATH]; - SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pathOutTemp); - - if (strcpy_s(pathOut, pathOutSize, pathOutTemp) != 0) { - return 0; - } - } - - - // Back slashes need to be normalized to forward. - while (pathOut[0] != '\0') { - if (pathOut[0] == '\\') { - pathOut[0] = '/'; - } - - pathOut += 1; - } - - return 1; -} - -dr_bool32 dr_get_log_folder_path(char* pathOut, size_t pathOutSize) -{ - return dr_get_config_folder_path(pathOut, pathOutSize); -} - -const char* dr_get_current_directory(char* pathOut, size_t pathOutSize) -{ - DWORD result = GetCurrentDirectoryA((DWORD)pathOutSize, pathOut); - if (result == 0) { - return NULL; - } - - return pathOut; -} - -dr_bool32 dr_set_current_directory(const char* path) -{ - return SetCurrentDirectoryA(path) != 0; -} -#else -#include -#include -#include - -dr_bool32 dr_get_executable_path(char* pathOut, size_t pathOutSize) -{ - if (pathOut == NULL || pathOutSize == 0) { - return 0; - } - - ssize_t length = readlink("/proc/self/exe", pathOut, pathOutSize); - if (length == -1) { - pathOut[0] = '\0'; - return DR_FALSE; - } - - if ((size_t)length == pathOutSize) { - pathOut[length - 1] = '\0'; - } else { - pathOut[length] = '\0'; - } - - return DR_TRUE; -} - -dr_bool32 dr_get_config_folder_path(char* pathOut, size_t pathOutSize) -{ - const char* configdir = getenv("XDG_CONFIG_HOME"); - if (configdir != NULL) - { - return strcpy_s(pathOut, pathOutSize, configdir) == 0; - } - else - { - const char* homedir = getenv("HOME"); - if (homedir == NULL) { - homedir = getpwuid(getuid())->pw_dir; - } - - if (homedir != NULL) - { - if (strcpy_s(pathOut, pathOutSize, homedir) == 0) - { - size_t homedirLength = strlen(homedir); - pathOut += homedirLength; - pathOutSize -= homedirLength; - - if (pathOutSize > 0) - { - pathOut[0] = '/'; - pathOut += 1; - pathOutSize -= 1; - - return strcpy_s(pathOut, pathOutSize, ".config") == 0; - } - } - } - } - - return 0; -} - -dr_bool32 dr_get_log_folder_path(char* pathOut, size_t pathOutSize) -{ - return strcpy_s(pathOut, pathOutSize, "var/log") == 0; -} - -const char* dr_get_current_directory(char* pathOut, size_t pathOutSize) -{ - return getcwd(pathOut, pathOutSize); -} - -dr_bool32 dr_set_current_directory(const char* path) -{ - return chdir(path) == 0; -} -#endif - -dr_bool32 dr_get_executable_directory_path(char* pathOut, size_t pathOutSize) -{ - if (!dr_get_executable_path(pathOut, pathOutSize)) { - return DR_FALSE; - } - - // A null terminator needs to be placed at the last slash. - char* lastSlash = pathOut; - while (pathOut[0] != '\0') { - if (pathOut[0] == '/' || pathOut[0] == '\\') { - lastSlash = pathOut; - } - pathOut += 1; - } - - lastSlash[0] = '\0'; - return DR_TRUE; -} - - - -///////////////////////////////////////////////////////// -// Basic File Management - -#ifndef _WIN32 -#include -#include -#include -#endif - -FILE* dr_fopen(const char* filePath, const char* openMode) -{ - FILE* pFile; -#ifdef _MSC_VER - if (fopen_s(&pFile, filePath, openMode) != 0) { - return NULL; - } -#else - pFile = fopen(filePath, openMode); - if (pFile == NULL) { - return NULL; - } -#endif - - return pFile; -} - -dr_bool32 dr_create_empty_file(const char* fileName, dr_bool32 failIfExists) -{ - if (fileName == NULL) { - return DR_FALSE; - } -#ifdef _WIN32 - DWORD dwCreationDisposition; - if (failIfExists) { - dwCreationDisposition = CREATE_NEW; - } else { - dwCreationDisposition = CREATE_ALWAYS; - } - - HANDLE hFile = CreateFileA(fileName, FILE_GENERIC_WRITE, 0, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return DR_FALSE; - } - - CloseHandle(hFile); - return DR_TRUE; -#else - int flags = O_WRONLY | O_CREAT; - if (failIfExists) { - flags |= O_EXCL; - } else { - flags |= O_TRUNC; - } - int fd = open(fileName, flags, 0666); - if (fd == -1) { - return DR_FALSE; - } - - close(fd); - return DR_TRUE; -#endif -} - -static void* dr_open_and_read_file_with_extra_data(const char* filePath, size_t* pFileSizeOut, size_t extraBytes) -{ - if (pFileSizeOut) *pFileSizeOut = 0; // For safety. - - if (filePath == NULL) { - return NULL; - } - - // TODO: Use 64-bit versions of the FILE APIs. - - FILE* pFile = dr_fopen(filePath, "rb"); - if (pFile == NULL) { - return NULL; - } - - fseek(pFile, 0, SEEK_END); - dr_uint64 fileSize = ftell(pFile); - fseek(pFile, 0, SEEK_SET); - - if (fileSize + extraBytes > SIZE_MAX) { - fclose(pFile); - return NULL; // File is too big. - } - - void* pFileData = malloc((size_t)fileSize + extraBytes); // <-- Safe cast due to the check above. - if (pFileData == NULL) { - fclose(pFile); - return NULL; // Failed to allocate memory for the file. Good chance the file is too big. - } - - size_t bytesRead = fread(pFileData, 1, (size_t)fileSize, pFile); - if (bytesRead != fileSize) { - free(pFileData); - fclose(pFile); - return NULL; // Failed to read every byte from the file. - } - - fclose(pFile); - - if (pFileSizeOut) *pFileSizeOut = (size_t)fileSize; - return pFileData; -} - -void* dr_open_and_read_file(const char* filePath, size_t* pFileSizeOut) -{ - return dr_open_and_read_file_with_extra_data(filePath, pFileSizeOut, 0); -} - -char* dr_open_and_read_text_file(const char* filePath, size_t* pFileSizeOut) -{ - if (pFileSizeOut) *pFileSizeOut = 0; // For safety. - - size_t fileSize; - char* pFileData = (char*)dr_open_and_read_file_with_extra_data(filePath, &fileSize, 1); // <-- 1 extra byte for the null terminator. - if (pFileData == NULL) { - return NULL; - } - - pFileData[fileSize] = '\0'; - - if (pFileSizeOut) *pFileSizeOut = fileSize; - return pFileData; -} - -dr_bool32 dr_open_and_write_file(const char* filePath, const void* pData, size_t dataSize) -{ - if (filePath == NULL) { - return DR_FALSE; - } - - // TODO: Use 64-bit versions of the FILE APIs. - - FILE* pFile = dr_fopen(filePath, "wb"); - if (pFile == NULL) { - return DR_FALSE; - } - - if (pData != NULL && dataSize > 0) { - fwrite(pData, 1, dataSize, pFile); - } - - fclose(pFile); - return DR_TRUE; -} - -dr_bool32 dr_open_and_write_text_file(const char* filePath, const char* text) -{ - if (text == NULL) { - text = ""; - } - - return dr_open_and_write_file(filePath, text, strlen(text)); -} - -void dr_free_file_data(void* valueReturnedByOpenAndReadFile) -{ - free(valueReturnedByOpenAndReadFile); -} - -dr_bool32 dr_file_exists(const char* filePath) -{ - if (filePath == NULL) { - return DR_FALSE; - } - -#if _WIN32 - DWORD attributes = GetFileAttributesA(filePath); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; -#else - struct stat info; - if (stat(filePath, &info) != 0) { - return DR_FALSE; // Likely the folder doesn't exist. - } - - return (info.st_mode & S_IFDIR) == 0; -#endif -} - -dr_bool32 dr_directory_exists(const char* directoryPath) -{ - if (directoryPath == NULL) { - return DR_FALSE; - } - -#if _WIN32 - DWORD attributes = GetFileAttributesA(directoryPath); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; -#else - struct stat info; - if (stat(directoryPath, &info) != 0) { - return DR_FALSE; // Likely the folder doesn't exist. - } - - return (info.st_mode & S_IFDIR) != 0; -#endif -} - -dr_bool32 dr_move_file(const char* oldPath, const char* newPath) -{ - if (oldPath == NULL || newPath == NULL) { - return DR_FALSE; - } - -#if _WIN32 - return MoveFileExA(oldPath, newPath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH) != 0; -#else - return rename(oldPath, newPath) == 0; -#endif -} - -dr_bool32 dr_copy_file(const char* srcPath, const char* dstPath, dr_bool32 failIfExists) -{ - if (srcPath == NULL || dstPath == NULL) { - return DR_FALSE; - } - -#if _WIN32 - return CopyFileA(srcPath, dstPath, failIfExists) != 0; -#else - int fdSrc = open(srcPath, O_RDONLY, 0666); - if (fdSrc == -1) { - return DR_FALSE; - } - - int fdDst = open(dstPath, O_WRONLY | O_TRUNC | O_CREAT | ((failIfExists) ? O_EXCL : 0), 0666); - if (fdDst == -1) { - close(fdSrc); - return DR_FALSE; - } - - dr_bool32 result = DR_TRUE; - struct stat info; - if (fstat(fdSrc, &info) == 0) { - char buffer[BUFSIZ]; - int bytesRead; - while ((bytesRead = read(fdSrc, buffer, sizeof(buffer))) > 0) { - if (write(fdDst, buffer, bytesRead) != bytesRead) { - result = DR_FALSE; - break; - } - } - } else { - result = DR_FALSE; - } - - close(fdDst); - close(fdSrc); - - // Permissions. - chmod(dstPath, info.st_mode & 07777); - - return result; -#endif -} - -dr_bool32 dr_is_file_read_only(const char* filePath) -{ - if (filePath == NULL || filePath[0] == '\0') { - return DR_FALSE; - } - -#if _WIN32 - DWORD attributes = GetFileAttributesA(filePath); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_READONLY) != 0; -#else - return access(filePath, W_OK) == -1; -#endif -} - -dr_uint64 dr_get_file_modified_time(const char* filePath) -{ - if (filePath == NULL || filePath[0] == '\0') { - return 0; - } - -#if _WIN32 - HANDLE hFile = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return 0; - } - - FILETIME fileTime; - BOOL wasSuccessful = GetFileTime(hFile, NULL, NULL, &fileTime); - CloseHandle(hFile); - - if (!wasSuccessful) { - return 0; - } - - ULARGE_INTEGER result; - result.HighPart = fileTime.dwHighDateTime; - result.LowPart = fileTime.dwLowDateTime; - return result.QuadPart; -#else - struct stat info; - if (stat(filePath, &info) != 0) { - return 0; - } - - return info.st_mtime; -#endif -} - -dr_bool32 dr_delete_file(const char* filePath) -{ - if (filePath == NULL) { - return DR_FALSE; - } - -#if _WIN32 - return DeleteFileA(filePath) != 0; -#else - return remove(filePath) == 0; -#endif -} - -dr_bool32 dr_mkdir(const char* directoryPath) -{ - if (directoryPath == NULL) { - return DR_FALSE; - } - -#if _WIN32 - return CreateDirectoryA(directoryPath, NULL) != 0; -#else - return mkdir(directoryPath, 0777) == 0; -#endif -} - -dr_bool32 dr_mkdir_recursive(const char* directoryPath) -{ - if (directoryPath == NULL || directoryPath[0] == '\0') { - return DR_FALSE; - } - - // All we need to do is iterate over every segment in the path and try creating the directory. - char runningPath[4096]; - memset(runningPath, 0, sizeof(runningPath)); - - size_t i = 0; - for (;;) { - if (i >= sizeof(runningPath)-1) { - return DR_FALSE; // Path is too long. - } - - if (directoryPath[0] == '\0' || directoryPath[0] == '/' || directoryPath[0] == '\\') { - if (runningPath[0] != '\0' && !(runningPath[1] == ':' && runningPath[2] == '\0')) { // <-- If the running path is empty, it means we're trying to create the root directory. - if (!dr_directory_exists(runningPath)) { - if (!dr_mkdir(runningPath)) { - return DR_FALSE; - } - } - } - - //printf("%s\n", runningPath); - runningPath[i++] = '/'; - runningPath[i] = '\0'; - - if (directoryPath[0] == '\0') { - break; - } - } else { - runningPath[i++] = directoryPath[0]; - } - - directoryPath += 1; - } - - return DR_TRUE; -} - -dr_bool32 dr_iterate_files(const char* directory, dr_bool32 recursive, dr_iterate_files_proc proc, void* pUserData) -{ -#ifdef _WIN32 - char searchQuery[MAX_PATH]; - strcpy_s(searchQuery, sizeof(searchQuery), directory); - - unsigned int searchQueryLength = (unsigned int)strlen(searchQuery); - if (searchQueryLength >= MAX_PATH - 3) { - return DR_FALSE; // Path is too long. - } - - searchQuery[searchQueryLength + 0] = '\\'; - searchQuery[searchQueryLength + 1] = '*'; - searchQuery[searchQueryLength + 2] = '\0'; - - WIN32_FIND_DATAA ffd; - HANDLE hFind = FindFirstFileA(searchQuery, &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - return DR_FALSE; // Failed to begin search. - } - - do - { - // Skip past "." and ".." directories. - if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) { - continue; - } - - char filePath[MAX_PATH]; - strcpy_s(filePath, sizeof(filePath), directory); - strcat_s(filePath, sizeof(filePath), "/"); - strcat_s(filePath, sizeof(filePath), ffd.cFileName); - - if (!proc(filePath, pUserData)) { - return DR_FALSE; - } - - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (recursive) { - if (!dr_iterate_files(filePath, recursive, proc, pUserData)) { - return DR_FALSE; - } - } - } - - } while (FindNextFileA(hFind, &ffd)); - - FindClose(hFind); -#else - DIR* dir = opendir(directory); - if (dir == NULL) { - return DR_FALSE; - } - - struct dirent* info = NULL; - while ((info = readdir(dir)) != NULL) - { - // Skip past "." and ".." directories. - if (strcmp(info->d_name, ".") == 0 || strcmp(info->d_name, "..") == 0) { - continue; - } - - char filePath[4096]; - strcpy_s(filePath, sizeof(filePath), directory); - strcat_s(filePath, sizeof(filePath), "/"); - strcat_s(filePath, sizeof(filePath), info->d_name); - - struct stat fileinfo; - if (stat(filePath, &fileinfo) != 0) { - continue; - } - - if (!proc(filePath, pUserData)) { - return DR_FALSE; - } - - if (fileinfo.st_mode & S_IFDIR) { - if (recursive) { - if (!dr_iterate_files(filePath, recursive, proc, pUserData)) { - return DR_FALSE; - } - } - } - } - - closedir(dir); -#endif - - return DR_TRUE; -} - - - -///////////////////////////////////////////////////////// -// DPI Awareness - -#if defined(_WIN32) || defined(_WIN64) - -typedef enum PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 -} PROCESS_DPI_AWARENESS; - -typedef enum MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI -} MONITOR_DPI_TYPE; - -typedef BOOL (__stdcall * PFN_SetProcessDPIAware) (void); -typedef HRESULT (__stdcall * PFN_SetProcessDpiAwareness) (PROCESS_DPI_AWARENESS); -typedef HRESULT (__stdcall * PFN_GetDpiForMonitor) (HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY); - -void dr_win32_make_dpi_aware() -{ - dr_bool32 fallBackToDiscouragedAPI = DR_FALSE; - - // We can't call SetProcessDpiAwareness() directly because otherwise on versions of Windows < 8.1 we'll get an error at load time about - // a missing DLL. - HMODULE hSHCoreDLL = LoadLibraryW(L"shcore.dll"); - if (hSHCoreDLL != NULL) - { - PFN_SetProcessDpiAwareness _SetProcessDpiAwareness = (PFN_SetProcessDpiAwareness)GetProcAddress(hSHCoreDLL, "SetProcessDpiAwareness"); - if (_SetProcessDpiAwareness != NULL) - { - if (_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) != S_OK) - { - fallBackToDiscouragedAPI = DR_FALSE; - } - } - else - { - fallBackToDiscouragedAPI = DR_FALSE; - } - - FreeLibrary(hSHCoreDLL); - } - else - { - fallBackToDiscouragedAPI = DR_FALSE; - } - - - if (fallBackToDiscouragedAPI) - { - HMODULE hUser32DLL = LoadLibraryW(L"user32.dll"); - if (hUser32DLL != NULL) - { - PFN_SetProcessDPIAware _SetProcessDPIAware = (PFN_SetProcessDPIAware)GetProcAddress(hUser32DLL, "SetProcessDPIAware"); - if (_SetProcessDPIAware != NULL) { - _SetProcessDPIAware(); - } - - FreeLibrary(hUser32DLL); - } - } -} - -void dr_win32_get_base_dpi(int* pDPIXOut, int* pDPIYOut) -{ - if (pDPIXOut != NULL) { - *pDPIXOut = 96; - } - - if (pDPIYOut != NULL) { - *pDPIYOut = 96; - } -} - -void dr_win32_get_system_dpi(int* pDPIXOut, int* pDPIYOut) -{ - if (pDPIXOut != NULL) { - *pDPIXOut = GetDeviceCaps(GetDC(NULL), LOGPIXELSX); - } - - if (pDPIYOut != NULL) { - *pDPIYOut = GetDeviceCaps(GetDC(NULL), LOGPIXELSY); - } -} - - -typedef struct -{ - int monitorIndex; - int i; - int dpiX; - int dpiY; - PFN_GetDpiForMonitor _GetDpiForMonitor; - -} win32_get_monitor_dpi_data; - -static BOOL CALLBACK win32_get_monitor_dpi_callback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - (void)hdcMonitor; - (void)lprcMonitor; - - win32_get_monitor_dpi_data* pData = (win32_get_monitor_dpi_data*)dwData; - if (pData->monitorIndex == pData->i) - { - UINT dpiX; - UINT dpiY; - if (pData->_GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK) - { - pData->dpiX = (int)dpiX; - pData->dpiY = (int)dpiY; - } - else - { - dr_win32_get_system_dpi(&pData->dpiX, &pData->dpiY); - } - - return FALSE; // Return DR_FALSE to terminate the enumerator. - } - - pData->i += 1; - return TRUE; -} - -void dr_win32_get_monitor_dpi(int monitor, int* pDPIXOut, int* pDPIYOut) -{ - // If multi-monitor DPI awareness is not supported we will need to fall back to system DPI. - HMODULE hSHCoreDLL = LoadLibraryW(L"shcore.dll"); - if (hSHCoreDLL == NULL) { - dr_win32_get_system_dpi(pDPIXOut, pDPIYOut); - return; - } - - PFN_GetDpiForMonitor _GetDpiForMonitor = (PFN_GetDpiForMonitor)GetProcAddress(hSHCoreDLL, "GetDpiForMonitor"); - if (_GetDpiForMonitor == NULL) { - dr_win32_get_system_dpi(pDPIXOut, pDPIYOut); - FreeLibrary(hSHCoreDLL); - return; - } - - - win32_get_monitor_dpi_data data; - data.monitorIndex = monitor; - data.i = 0; - data.dpiX = 0; - data.dpiY = 0; - data._GetDpiForMonitor = _GetDpiForMonitor; - EnumDisplayMonitors(NULL, NULL, win32_get_monitor_dpi_callback, (LPARAM)&data); - - if (pDPIXOut) { - *pDPIXOut = data.dpiX; - } - - if (pDPIYOut) { - *pDPIYOut = data.dpiY; - } - - - FreeLibrary(hSHCoreDLL); -} - - -static BOOL CALLBACK win32_get_monitor_count_callback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - (void)hMonitor; - (void)hdcMonitor; - (void)lprcMonitor; - - int *count = (int*)dwData; - (*count)++; - - return TRUE; -} - -int dr_win32_get_monitor_count() -{ - int count = 0; - if (EnumDisplayMonitors(NULL, NULL, win32_get_monitor_count_callback, (LPARAM)&count)) { - return count; - } - - return 0; -} -#endif - - -///////////////////////////////////////////////////////// -// Date / Time - -time_t dr_now() -{ - return time(NULL); -} - -void dr_datetime_short(time_t t, char* strOut, unsigned int strOutSize) -{ -#if defined(_MSC_VER) - struct tm local; - localtime_s(&local, &t); - strftime(strOut, strOutSize, "%x %H:%M:%S", &local); -#else - struct tm *local = localtime(&t); - strftime(strOut, strOutSize, "%x %H:%M:%S", local); -#endif -} - -void dr_date_YYYYMMDD(time_t t, char* strOut, unsigned int strOutSize) -{ -#if defined(_MSC_VER) - struct tm local; - localtime_s(&local, &t); - strftime(strOut, strOutSize, "%Y%m%d", &local); -#else - struct tm *local = localtime(&t); - strftime(strOut, strOutSize, "%Y%m%d", local); -#endif -} - - - -///////////////////////////////////////////////////////// -// Command Line - -typedef struct -{ - dr_cmdline* pCmdLine; - char* value; - - // Win32 style data. - char* win32_payload; - char* valueEnd; - - // argv style data. - int iarg; // <-- This starts at -1 so that the first call to next() increments it to 0. - -} dr_cmdline_iterator; - -dr_cmdline_iterator dr_cmdline_begin(dr_cmdline* pCmdLine) -{ - dr_cmdline_iterator i; - i.pCmdLine = pCmdLine; - i.value = NULL; - i.win32_payload = NULL; - i.valueEnd = NULL; - i.iarg = -1; - - if (pCmdLine != NULL && pCmdLine->win32 != NULL) { - // Win32 style - size_t length = strlen(pCmdLine->win32); - i.win32_payload = (char*)malloc(length + 2); // +2 for a double null terminator. - strcpy_s(i.win32_payload, length + 2, pCmdLine->win32); - i.win32_payload[length + 1] = '\0'; - - i.valueEnd = i.win32_payload; - } - - return i; -} - -dr_bool32 dr_cmdline_next(dr_cmdline_iterator* i) -{ - if (i != NULL && i->pCmdLine != NULL) - { - if (i->pCmdLine->win32 != NULL) - { - // Win32 style - if (i->value == NULL) { - i->value = i->win32_payload; - i->valueEnd = i->value; - } else { - i->value = i->valueEnd + 1; - } - - - // Move to the start of the next argument. - while (i->value[0] == ' ') { - i->value += 1; - } - - - // If at this point we are sitting on the null terminator it means we have finished iterating. - if (i->value[0] == '\0') - { - free(i->win32_payload); - i->win32_payload = NULL; - i->pCmdLine = NULL; - i->value = NULL; - i->valueEnd = NULL; - - return DR_FALSE; - } - - - // Move to the end of the token. If the argument begins with a double quote, we iterate until we find - // the next unescaped double-quote. - if (i->value[0] == '\"') - { - // Go to the last unescaped double-quote. - i->value += 1; - i->valueEnd = i->value + 1; - - while (i->valueEnd[0] != '\0' && i->valueEnd[0] != '\"') - { - if (i->valueEnd[0] == '\\') { - i->valueEnd += 1; - - if (i->valueEnd[0] == '\0') { - break; - } - } - - i->valueEnd += 1; - } - i->valueEnd[0] = '\0'; - } - else - { - // Go to the next space. - i->valueEnd = i->value + 1; - - while (i->valueEnd[0] != '\0' && i->valueEnd[0] != ' ') - { - i->valueEnd += 1; - } - i->valueEnd[0] = '\0'; - } - - return DR_TRUE; - } - else - { - // argv style - i->iarg += 1; - if (i->iarg < i->pCmdLine->argc) - { - i->value = i->pCmdLine->argv[i->iarg]; - return DR_TRUE; - } - else - { - i->value = NULL; - return DR_FALSE; - } - } - } - - return DR_FALSE; -} - - -dr_bool32 dr_init_cmdline(dr_cmdline* pCmdLine, int argc, char** argv) -{ - if (pCmdLine == NULL) { - return DR_FALSE; - } - - pCmdLine->argc = argc; - pCmdLine->argv = argv; - pCmdLine->win32 = NULL; - - return DR_TRUE; -} - -dr_bool32 dr_init_cmdline_win32(dr_cmdline* pCmdLine, const char* args) -{ - if (pCmdLine == NULL) { - return DR_FALSE; - } - - pCmdLine->argc = 0; - pCmdLine->argv = NULL; - pCmdLine->win32 = args; - - return DR_TRUE; -} - -void dr_parse_cmdline(dr_cmdline* pCmdLine, dr_cmdline_parse_proc callback, void* pUserData) -{ - if (pCmdLine == NULL || callback == NULL) { - return; - } - - - char pTemp[2] = {0}; - - char* pKey = NULL; - char* pVal = NULL; - - dr_cmdline_iterator arg = dr_cmdline_begin(pCmdLine); - if (dr_cmdline_next(&arg)) - { - if (!callback("[path]", arg.value, pUserData)) { - return; - } - } - - while (dr_cmdline_next(&arg)) - { - if (arg.value[0] == '-') - { - // key - - // If the key is non-null, but the value IS null, it means we hit a key with no value in which case it will not yet have been posted. - if (pKey != NULL && pVal == NULL) - { - if (!callback(pKey, pVal, pUserData)) { - return; - } - - pKey = NULL; - } - else - { - // Need to ensure the key and value are reset before doing any further processing. - pKey = NULL; - pVal = NULL; - } - - - - if (arg.value[1] == '-') - { - // --argument style - pKey = arg.value + 2; - } - else - { - // -a -b -c -d or -abcd style - if (arg.value[1] != '\0') - { - if (arg.value[2] == '\0') - { - // -a -b -c -d style - pTemp[0] = arg.value[1]; - pKey = pTemp; - pVal = NULL; - } - else - { - // -abcd style. - int i = 1; - while (arg.value[i] != '\0') - { - pTemp[0] = arg.value[i]; - - if (!callback(pTemp, NULL, pUserData)) { - return; - } - - pKey = NULL; - pVal = NULL; - - i += 1; - } - } - } - } - } - else - { - // value - - pVal = arg.value; - if (!callback(pKey, pVal, pUserData)) { - return; - } - } - } - - - // There may be a key without a value that needs posting. - if (pKey != NULL && pVal == NULL) { - callback(pKey, pVal, pUserData); - } -} - -typedef struct -{ - dr_bool32 exists; - const char* key; -} dr_cmdline_key_exists_data; - -dr_bool32 dr_cmdline_key_exists_callback(const char* key, const char* value, void* pUserData) -{ - (void)value; - - dr_cmdline_key_exists_data* pData = (dr_cmdline_key_exists_data*)pUserData; - assert(pData != NULL); - - if (key != NULL && strcmp(pData->key, key) == 0) { - pData->exists = DR_TRUE; - return DR_FALSE; - } - - return DR_TRUE; -} - -dr_bool32 dr_cmdline_key_exists(dr_cmdline* pCmdLine, const char* key) -{ - dr_cmdline_key_exists_data data; - data.exists = DR_FALSE; - data.key = key; - dr_parse_cmdline(pCmdLine, dr_cmdline_key_exists_callback, &data); - - return data.exists; -} - -int dr_cmdline_to_argv(dr_cmdline* pCmdLine, char*** argvOut) -{ - if (argvOut == NULL) return 0; - *argvOut = NULL; // Safety. - - int argc = 0; - char** argv = NULL; - size_t cmdlineLen = 0; - - // The command line is parsed in 2 passes. The first pass simple calculates the required sizes of each buffer. The second - // pass fills those buffers with actual data. - - // First pass. - dr_cmdline_iterator arg = dr_cmdline_begin(pCmdLine); - while (dr_cmdline_next(&arg)) { - cmdlineLen += strlen(arg.value) + 1; // +1 for null terminator. - argc += 1; - } - - if (argc == 0) { - return 0; - } - - - // The entire data for the command line is stored in a single buffer. - char* data = (char*)malloc((argc * sizeof(char**)) + (cmdlineLen * sizeof(char))); - if (data == NULL) { - return 0; // Ran out of memory. - } - - argv = (char**)data; - char* cmdlineStr = data + (argc * sizeof(char**)); - - - - // Second pass. - argc = 0; - cmdlineLen = 0; - - arg = dr_cmdline_begin(pCmdLine); - while (dr_cmdline_next(&arg)) { - argv[argc] = cmdlineStr + cmdlineLen; - - int i = 0; - while (arg.value[i] != '\0') { - argv[argc][i] = arg.value[i]; - i += 1; - } - argv[argc][i] = '\0'; - - - cmdlineLen += strlen(arg.value) + 1; // +1 for null terminator. - argc += 1; - } - - - *argvOut = argv; - return argc; -} - -int dr_winmain_to_argv(const char* cmdlineWinMain, char*** argvOut) -{ - dr_cmdline cmdline; - if (!dr_init_cmdline_win32(&cmdline, cmdlineWinMain)) { - return 0; - } - - return dr_cmdline_to_argv(&cmdline, argvOut); -} - -void dr_free_argv(char** argv) -{ - if (argv == NULL) { - return; - } - - free(argv); -} - - - -///////////////////////////////////////////////////////// -// Threading - -#if defined(_WIN32) -void dr_sleep(unsigned int milliseconds) -{ - Sleep((DWORD)milliseconds); -} - -void dr_yield() -{ - SwitchToThread(); -} - -unsigned int dr_get_logical_processor_count() -{ - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - - return (unsigned int)sysinfo.dwNumberOfProcessors; -} - - -typedef struct -{ - /// The Win32 thread handle. - HANDLE hThread; - - /// The entry point. - dr_thread_entry_proc entryProc; - - /// The user data to pass to the thread's entry point. - void* pData; - - /// Set to DR_TRUE by the entry function. We use this to wait for the entry function to start. - dr_bool32 isInEntryProc; - -} dr_thread_win32; - -static DWORD WINAPI dr_thread_entry_proc_win32(LPVOID pUserData) -{ - dr_thread_win32* pThreadWin32 = (dr_thread_win32*)pUserData; - assert(pThreadWin32 != NULL); - - void* pEntryProcData = pThreadWin32->pData; - dr_thread_entry_proc entryProc = pThreadWin32->entryProc; - assert(entryProc != NULL); - - pThreadWin32->isInEntryProc = DR_TRUE; - - return (DWORD)entryProc(pEntryProcData); -} - -dr_thread dr_create_thread(dr_thread_entry_proc entryProc, void* pData) -{ - if (entryProc == NULL) { - return NULL; - } - - dr_thread_win32* pThreadWin32 = (dr_thread_win32*)malloc(sizeof(*pThreadWin32)); - if (pThreadWin32 != NULL) - { - pThreadWin32->entryProc = entryProc; - pThreadWin32->pData = pData; - pThreadWin32->isInEntryProc = DR_FALSE; - - pThreadWin32->hThread = CreateThread(NULL, 0, dr_thread_entry_proc_win32, pThreadWin32, 0, NULL); - if (pThreadWin32 == NULL) { - free(pThreadWin32); - return NULL; - } - - // Wait for the new thread to enter into it's entry point before returning. We need to do this so we can safely - // support something like dr_delete_thread(dr_create_thread(my_thread_proc, pData)). - // - // On Win32 there are times when this can get stuck in an infinite loop - I expect it's something to do with some - // bad scheduling by the OS. This can be "fixed" by sleeping for a bit. - while (!pThreadWin32->isInEntryProc) { dr_sleep(0); } - } - - return (dr_thread)pThreadWin32; -} - -void dr_delete_thread(dr_thread thread) -{ - dr_thread_win32* pThreadWin32 = (dr_thread_win32*)thread; - if (pThreadWin32 != NULL) - { - CloseHandle(pThreadWin32->hThread); - } - - free(pThreadWin32); -} - -void dr_wait_thread(dr_thread thread) -{ - dr_thread_win32* pThreadWin32 = (dr_thread_win32*)thread; - if (pThreadWin32 != NULL) - { - WaitForSingleObject(pThreadWin32->hThread, INFINITE); - } -} - -void dr_wait_and_delete_thread(dr_thread thread) -{ - dr_wait_thread(thread); - dr_delete_thread(thread); -} - - -#ifdef DR_UTIL_WIN32_USE_CRITICAL_SECTION_MUTEX -dr_mutex dr_create_mutex() -{ - dr_mutex mutex = malloc(sizeof(CRITICAL_SECTION)); - if (mutex != NULL) - { - InitializeCriticalSection(mutex); - } - - return mutex; -} - -void dr_delete_mutex(dr_mutex mutex) -{ - DeleteCriticalSection(mutex); - free(mutex); -} - -void dr_lock_mutex(dr_mutex mutex) -{ - EnterCriticalSection(mutex); -} - -void dr_unlock_mutex(dr_mutex mutex) -{ - LeaveCriticalSection(mutex); -} -#else -dr_mutex dr_create_mutex() -{ - return CreateEventA(NULL, FALSE, TRUE, NULL); -} - -void dr_delete_mutex(dr_mutex mutex) -{ - CloseHandle((HANDLE)mutex); -} - -void dr_lock_mutex(dr_mutex mutex) -{ - WaitForSingleObject((HANDLE)mutex, INFINITE); -} - -void dr_unlock_mutex(dr_mutex mutex) -{ - SetEvent((HANDLE)mutex); -} -#endif - - -dr_semaphore dr_create_semaphore(int initialValue) -{ - return (void*)CreateSemaphoreA(NULL, initialValue, LONG_MAX, NULL); -} - -void dr_delete_semaphore(dr_semaphore semaphore) -{ - CloseHandle(semaphore); -} - -dr_bool32 dr_wait_semaphore(dr_semaphore semaphore) -{ - return WaitForSingleObject((HANDLE)semaphore, INFINITE) == WAIT_OBJECT_0; -} - -dr_bool32 dr_release_semaphore(dr_semaphore semaphore) -{ - return ReleaseSemaphore((HANDLE)semaphore, 1, NULL) != 0; -} -#else -void dr_sleep(unsigned int milliseconds) -{ - usleep(milliseconds * 1000); // <-- usleep is in microseconds. -} - -void dr_yield() -{ - sched_yield(); -} - -unsigned int dr_get_logical_processor_count() -{ - return (unsigned int)sysconf(_SC_NPROCESSORS_ONLN); -} - - -typedef struct -{ - /// The Win32 thread handle. - pthread_t pthread; - - /// The entry point. - dr_thread_entry_proc entryProc; - - /// The user data to pass to the thread's entry point. - void* pData; - - /// Set to DR_TRUE by the entry function. We use this to wait for the entry function to start. - dr_bool32 isInEntryProc; - -} dr_thread_posix; - -static void* dr_thread_entry_proc_posix(void* pDataIn) -{ - dr_thread_posix* pThreadPosix = (dr_thread_posix*)pDataIn; - assert(pThreadPosix != NULL); - - void* pEntryProcData = pThreadPosix->pData; - dr_thread_entry_proc entryProc = pThreadPosix->entryProc; - assert(entryProc != NULL); - - pThreadPosix->isInEntryProc = DR_TRUE; - - return (void*)(size_t)entryProc(pEntryProcData); -} - -dr_thread dr_create_thread(dr_thread_entry_proc entryProc, void* pData) -{ - if (entryProc == NULL) { - return NULL; - } - - dr_thread_posix* pThreadPosix = (dr_thread_posix*)malloc(sizeof(*pThreadPosix)); - if (pThreadPosix != NULL) - { - pThreadPosix->entryProc = entryProc; - pThreadPosix->pData = pData; - pThreadPosix->isInEntryProc = DR_FALSE; - - if (pthread_create(&pThreadPosix->pthread, NULL, dr_thread_entry_proc_posix, pThreadPosix) != 0) { - free(pThreadPosix); - return NULL; - } - - // Wait for the new thread to enter into it's entry point before returning. We need to do this so we can safely - // support something like dr_delete_thread(dr_create_thread(my_thread_proc, pData)). - while (!pThreadPosix->isInEntryProc) {} - } - - return (dr_thread)pThreadPosix; -} - -void dr_delete_thread(dr_thread thread) -{ - free(thread); -} - -void dr_wait_thread(dr_thread thread) -{ - dr_thread_posix* pThreadPosix = (dr_thread_posix*)thread; - if (pThreadPosix != NULL) - { - pthread_join(pThreadPosix->pthread, NULL); - } -} - - - -dr_mutex dr_create_mutex() -{ - pthread_mutex_t* mutex = (pthread_mutex_t*)malloc(sizeof(*mutex)); - if (pthread_mutex_init(mutex, NULL) != 0) { - free(mutex); - mutex = NULL; - } - - return mutex; -} - -void dr_delete_mutex(dr_mutex mutex) -{ - pthread_mutex_destroy((pthread_mutex_t*)mutex); -} - -void dr_lock_mutex(dr_mutex mutex) -{ - pthread_mutex_lock((pthread_mutex_t*)mutex); -} - -void dr_unlock_mutex(dr_mutex mutex) -{ - pthread_mutex_unlock((pthread_mutex_t*)mutex); -} - - - -dr_semaphore dr_create_semaphore(int initialValue) -{ - sem_t* semaphore = (sem_t*)malloc(sizeof(*semaphore)); - if (sem_init(semaphore, 0, (unsigned int)initialValue) == -1) { - free(semaphore); - semaphore = NULL; - } - - return semaphore; -} - -void dr_delete_semaphore(dr_semaphore semaphore) -{ - sem_close((sem_t*)semaphore); -} - -dr_bool32 dr_wait_semaphore(dr_semaphore semaphore) -{ - return sem_wait((sem_t*)semaphore) != -1; -} - -dr_bool32 dr_release_semaphore(dr_semaphore semaphore) -{ - return sem_post((sem_t*)semaphore) != -1; -} -#endif - - - -///////////////////////////////////////////////////////// -// Timing - -// macOS does not have clock_gettime on OS X < 10.12 -#ifdef __MACH__ -#include -#ifndef MAC_OS_X_VERSION_10_12 -#define MAC_OS_X_VERSION_10_12 101200 -#endif -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12 -#include -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 0 -int clock_gettime(int clk_id, struct timespec* t) -{ - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - dr_uint64 time; - time = mach_absolute_time(); - double nseconds = ((double)time * (double)timebase.numer) / ((double)timebase.denom); - double seconds = ((double)time * (double)timebase.numer) / ((double)timebase.denom * 1e9); - t->tv_sec = seconds; - t->tv_nsec = nseconds; - return 0; -} -#endif -#endif - -#ifdef _WIN32 -static LARGE_INTEGER g_DRTimerFrequency = {{0}}; -void dr_timer_init(dr_timer* pTimer) -{ - if (g_DRTimerFrequency.QuadPart == 0) { - QueryPerformanceFrequency(&g_DRTimerFrequency); - } - - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - pTimer->counter = (dr_uint64)counter.QuadPart; -} - -double dr_timer_tick(dr_timer* pTimer) -{ - LARGE_INTEGER counter; - if (!QueryPerformanceCounter(&counter)) { - return 0; - } - - dr_uint64 newTimeCounter = counter.QuadPart; - dr_uint64 oldTimeCounter = pTimer->counter; - - pTimer->counter = newTimeCounter; - - return (newTimeCounter - oldTimeCounter) / (double)g_DRTimerFrequency.QuadPart; -} -#else -void dr_timer_init(dr_timer* pTimer) -{ - struct timespec newTime; - clock_gettime(CLOCK_MONOTONIC, &newTime); - - pTimer->counter = (newTime.tv_sec * 1000000000LL) + newTime.tv_nsec; -} - -double dr_timer_tick(dr_timer* pTimer) -{ - struct timespec newTime; - clock_gettime(CLOCK_MONOTONIC, &newTime); - - dr_uint64 newTimeCounter = (newTime.tv_sec * 1000000000LL) + newTime.tv_nsec; - dr_uint64 oldTimeCounter = pTimer->counter; - - pTimer->counter = newTimeCounter; - - return (newTimeCounter - oldTimeCounter) / 1000000000.0; -} -#endif - - -///////////////////////////////////////////////////////// -// Random - -double dr_randd() -{ - return (double)rand() / (double)RAND_MAX; -} - -float dr_randf() -{ - return (float)dr_randd(); -} - - -///////////////////////////////////////////////////////// -// User Accounts and Process Management - -size_t dr_get_username(char* usernameOut, size_t usernameOutSize) -{ - if (usernameOut != NULL && usernameOutSize > 0) { - usernameOut[0] = '\0'; - } - -#ifdef _WIN32 - DWORD dwSize = (DWORD)usernameOutSize; - if (!GetUserNameA(usernameOut, &dwSize)) { - return 0; - } - - return dwSize; -#else - struct passwd *pw = getpwuid(geteuid()); - if (pw == NULL) { - return 0; - } - - if (usernameOut != NULL) { - strcpy_s(usernameOut, usernameOutSize, pw->pw_name); - } - - return strlen(pw->pw_name); -#endif -} - -unsigned int dr_get_process_id() -{ -#ifdef _WIN32 - return GetProcessId(GetCurrentProcess()); -#else - return (unsigned int)getpid(); -#endif -} - - - -///////////////////////////////////////////////////////// -// Miscellaneous Stuff. - -dr_bool32 dr_hex_char_to_uint(char ascii, unsigned int* out) -{ - if (ascii >= '0' && ascii <= '9') { - if (out) *out = ascii - '0'; - return DR_TRUE; - } - - if (ascii >= 'A' && ascii <= 'F') { - if (out) *out = 10 + (ascii - 'A'); - return DR_TRUE; - } - - if (ascii >= 'a' && ascii <= 'f') { - if (out) *out = 10 + (ascii - 'a'); - return DR_TRUE; - } - - if (out) *out = 0; - return DR_FALSE; -} - -#endif //DR_IMPLEMENTATION - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// dr_path -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef dr_path_h -#define dr_path_h - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -// Structure representing a section of a path. -typedef struct -{ - size_t offset; - size_t length; - -} drpath_segment; - -// Structure used for iterating over a path while at the same time providing useful and easy-to-use information about the iteration. -typedef struct drpath_iterator -{ - const char* path; - drpath_segment segment; - -} drpath_iterator; - - - -/// Compares a section of two strings for equality. -/// -/// @param s0Path [in] The first path. -/// @param s0 [in] The segment of the first path to compare. -/// @param s1Path [in] The second path. -/// @param s1 [in] The segment of the second path to compare. -/// -/// @return DR_TRUE if the strings are equal; DR_FALSE otherwise. -dr_bool32 drpath_segments_equal(const char* s0Path, const drpath_segment s0, const char* s1Path, const drpath_segment s1); - - -/// Creates an iterator for iterating over each segment in a path. -/// -/// @param path [in] The path whose segments are being iterated. -/// -/// @return True if at least one segment is found; DR_FALSE if it's an empty path. -dr_bool32 drpath_first(const char* path, drpath_iterator* i); - -/// Creates an iterator beginning at the last segment. -dr_bool32 drpath_last(const char* path, drpath_iterator* i); - -/// Goes to the next segment in the path as per the given iterator. -/// -/// @param i [in] A pointer to the iterator to increment. -/// -/// @return True if the iterator contains a valid value. Use this to determine when to terminate iteration. -dr_bool32 drpath_next(drpath_iterator* i); - -/// Goes to the previous segment in the path. -/// -/// @param i [in] A pointer to the iterator to decrement. -/// -/// @return DR_TRUE if the iterator contains a valid value. Use this to determine when to terminate iteration. -dr_bool32 drpath_prev(drpath_iterator* i); - -/// Determines if the given iterator is at the end. -/// -/// @param i [in] The iterator to check. -dr_bool32 drpath_at_end(drpath_iterator i); - -/// Determines if the given iterator is at the start. -/// -/// @param i [in] The iterator to check. -dr_bool32 drpath_at_start(drpath_iterator i); - -/// Compares the string values of two iterators for equality. -/// -/// @param i0 [in] The first iterator to compare. -/// @param i1 [in] The second iterator to compare. -/// -/// @return DR_TRUE if the strings are equal; DR_FALSE otherwise. -dr_bool32 drpath_iterators_equal(const drpath_iterator i0, const drpath_iterator i1); - - -/// Determines whether or not the given iterator refers to the root segment of a path. -dr_bool32 drpath_is_root_segment(const drpath_iterator i); - -/// Determines whether or not the given iterator refers to a Linux style root directory ("/") -dr_bool32 drpath_is_linux_style_root_segment(const drpath_iterator i); - -/// Determines whether or not the given iterator refers to a Windows style root directory. -dr_bool32 drpath_is_win32_style_root_segment(const drpath_iterator i); - - -/// Converts the slashes in the given path to forward slashes. -/// -/// @param path [in] The path whose slashes are being converted. -void drpath_to_forward_slashes(char* path); - -/// Converts the slashes in the given path to back slashes. -/// -/// @param path [in] The path whose slashes are being converted. -void drpath_to_backslashes(char* path); - - -/// Determines whether or not the given path is a decendant of another. -/// -/// @param descendantAbsolutePath [in] The absolute path of the descendant. -/// @param parentAbsolutePath [in] The absolute path of the parent. -/// -/// @remarks -/// As an example, "C:/My/Folder" is a descendant of "C:/". -/// @par -/// If either path contains "." or "..", clean it with drpath_clean() before calling this. -dr_bool32 drpath_is_descendant(const char* descendantAbsolutePath, const char* parentAbsolutePath); - -/// Determines whether or not the given path is a direct child of another. -/// -/// @param childAbsolutePath [in] The absolute of the child. -/// @param parentAbsolutePath [in] The absolute path of the parent. -/// -/// @remarks -/// As an example, "C:/My/Folder" is NOT a child of "C:/" - it is a descendant. Alternatively, "C:/My" IS a child of "C:/". -/// @par -/// If either path contains "." or "..", clean it with drpath_clean() before calling this. -dr_bool32 drpath_is_child(const char* childAbsolutePath, const char* parentAbsolutePath); - - -/// Modifies the given path by transforming it into it's base path. -/// -/// Returns , for convenience. -char* drpath_base_path(char* path); - -/// Retrieves the base path from the given path, not including the trailing slash. -/// -/// @param path [in] The full path. -/// @param baseOut [out] A pointer to the buffer that will receive the base path. -/// @param baseSizeInBytes [in] The size in bytes of the buffer that will receive the base directory. -/// -/// @remarks -/// As an example, when "path" is "C:/MyFolder/MyFile", the output will be "C:/MyFolder". Note that there is no trailing slash. -/// @par -/// If "path" is something like "/MyFolder", the return value will be an empty string. -void drpath_copy_base_path(const char* path, char* baseOut, size_t baseSizeInBytes); - -/// Finds the file name portion of the path. -/// -/// @param path [in] The path to search. -/// -/// @return A pointer to the beginning of the string containing the file name. If this is non-null, it will be an offset of "path". -/// -/// @remarks -/// A path with a trailing slash will return an empty string. -/// @par -/// The return value is just an offset of "path". -const char* drpath_file_name(const char* path); - -/// Copies the file name into the given buffer. -const char* drpath_copy_file_name(const char* path, char* fileNameOut, size_t fileNameSizeInBytes); - -/// Finds the file extension of the given file path. -/// -/// @param path [in] The path to search. -/// -/// @return A pointer to the beginning of the string containing the file's extension. -/// -/// @remarks -/// A path with a trailing slash will return an empty string. -/// @par -/// The return value is just an offset of "path". -/// @par -/// On a path such as "filename.ext1.ext2" the returned string will be "ext2". -const char* drpath_extension(const char* path); - - -/// Checks whether or not the two paths are equal. -/// -/// @param path1 [in] The first path. -/// @param path2 [in] The second path. -/// -/// @return DR_TRUE if the paths are equal, DR_FALSE otherwise. -/// -/// @remarks -/// This is case-sensitive. -/// @par -/// This is more than just a string comparison. Rather, this splits the path and compares each segment. The path "C:/My/Folder" is considered -/// equal to to "C:\\My\\Folder". -dr_bool32 drpath_equal(const char* path1, const char* path2); - -/// Checks if the extension of the given path is equal to the given extension. -/// -/// @remarks -/// By default this is NOT case-sensitive, however if the standard library is disable, it is case-sensitive. -dr_bool32 drpath_extension_equal(const char* path, const char* extension); - - -/// Determines whether or not the given path is relative. -/// -/// @param path [in] The path to check. -dr_bool32 drpath_is_relative(const char* path); - -/// Determines whether or not the given path is absolute. -/// -/// @param path [in] The path to check. -dr_bool32 drpath_is_absolute(const char* path); - - -/// Appends two paths together, ensuring there is not double up on the last slash. -/// -/// @param base [in, out] The base path that is being appended to. -/// @param baseBufferSizeInBytes [in] The size of the buffer pointed to by "base", in bytes. -/// @param other [in] The other path segment. -/// -/// @remarks -/// This assumes both paths are well formed and "other" is a relative path. -dr_bool32 drpath_append(char* base, size_t baseBufferSizeInBytes, const char* other); - -/// Appends an iterator object to the given base path. -dr_bool32 drpath_append_iterator(char* base, size_t baseBufferSizeInBytes, drpath_iterator i); - -/// Appends an extension to the given path. -dr_bool32 drpath_append_extension(char* base, size_t baseBufferSizeInBytes, const char* extension); - -/// Appends two paths together, and copyies them to a separate buffer. -/// -/// @param dst [out] The destination buffer. -/// @param dstSizeInBytes [in] The size of the buffer pointed to by "dst", in bytes. -/// @param base [in] The base directory. -/// @param other [in] The relative path to append to "base". -/// -/// @return DR_TRUE if the paths were appended successfully; DR_FALSE otherwise. -/// -/// @remarks -/// This assumes both paths are well formed and "other" is a relative path. -dr_bool32 drpath_copy_and_append(char* dst, size_t dstSizeInBytes, const char* base, const char* other); - -/// Appends a base path and an iterator together, and copyies them to a separate buffer. -/// -/// @param dst [out] The destination buffer. -/// @param dstSizeInBytes [in] The size of the buffer pointed to by "dst", in bytes. -/// @param base [in] The base directory. -/// @param i [in] The iterator to append. -/// -/// @return DR_TRUE if the paths were appended successfully; DR_FALSE otherwise. -/// -/// @remarks -/// This assumes both paths are well formed and "i" is a valid iterator. -dr_bool32 drpath_copy_and_append_iterator(char* dst, size_t dstSizeInBytes, const char* base, drpath_iterator i); - -/// Appends an extension to the given base path and copies them to a separate buffer. -/// @param dst [out] The destination buffer. -/// @param dstSizeInBytes [in] The size of the buffer pointed to by "dst", in bytes. -/// @param base [in] The base directory. -/// @param extension [in] The relative path to append to "base". -/// -/// @return DR_TRUE if the paths were appended successfully; DR_FALSE otherwise. -dr_bool32 drpath_copy_and_append_extension(char* dst, size_t dstSizeInBytes, const char* base, const char* extension); - - -/// Cleans the path and resolves the ".." and "." segments. -/// -/// @param path [in] The path to clean. -/// @param pathOut [out] A pointer to the buffer that will receive the path. -/// @param pathOutSizeInBytes [in] The size of the buffer pointed to by pathOut, in bytes. -/// -/// @return The number of bytes written to the output buffer, including the null terminator. -/// -/// @remarks -/// The output path will never be longer than the input path. -/// @par -/// The output buffer should never overlap with the input path. -/// @par -/// As an example, the path "my/messy/../path" will result in "my/path" -/// @par -/// The path "my/messy/../../../path" (note how there are too many ".." segments) will return "path" (the extra ".." segments will be dropped.) -/// @par -/// If an error occurs, such as an invalid input path, 0 will be returned. -size_t drpath_clean(const char* path, char* pathOut, size_t pathOutSizeInBytes); - -/// Appends one path to the other and then cleans it. -size_t drpath_append_and_clean(char* dst, size_t dstSizeInBytes, const char* base, const char* other); - - -/// Removes the extension from the given path. -/// -/// @remarks -/// If the given path does not have an extension, 1 will be returned, but the string will be left unmodified. -dr_bool32 drpath_remove_extension(char* path); - -/// Creates a copy of the given string and removes the extension. -dr_bool32 drpath_copy_and_remove_extension(char* dst, size_t dstSizeInBytes, const char* path); - - -/// Removes the last segment from the given path. -dr_bool32 drpath_remove_file_name(char* path); - -/// Creates a copy of the given string and removes the extension. -dr_bool32 drpath_copy_and_remove_file_name(char* dst, size_t dstSizeInBytes, const char* path); - - -/// Converts an absolute path to a relative path. -/// -/// @return DR_TRUE if the conversion was successful; DR_FALSE if there was an error. -/// -/// @remarks -/// This will normalize every slash to forward slashes. -dr_bool32 drpath_to_relative(const char* absolutePathToMakeRelative, const char* absolutePathToMakeRelativeTo, char* relativePathOut, size_t relativePathOutSizeInBytes); - -/// Converts a relative path to an absolute path based on a base path. -/// -/// @return DR_TRUE if the conversion was successful; DR_FALSE if there was an error. -/// -/// @remarks -/// This is equivalent to an append followed by a clean. Slashes will be normalized to forward slashes. -dr_bool32 drpath_to_absolute(const char* relativePathToMakeAbsolute, const char* basePath, char* absolutePathOut, size_t absolutePathOutSizeInBytes); - - -#ifdef __cplusplus -} -#endif -#endif //dr_path_h - - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_IMPLEMENTATION -#include -#include -#include - -dr_bool32 drpath_first(const char* path, drpath_iterator* i) -{ - if (i == 0) return DR_FALSE; - i->path = path; - i->segment.offset = 0; - i->segment.length = 0; - - if (path == 0 || path[0] == '\0') { - return DR_FALSE; - } - - while (i->path[i->segment.length] != '\0' && (i->path[i->segment.length] != '/' && i->path[i->segment.length] != '\\')) { - i->segment.length += 1; - } - - return DR_TRUE; -} - -dr_bool32 drpath_last(const char* path, drpath_iterator* i) -{ - if (i == 0) return DR_FALSE; - i->path = path; - i->segment.offset = 0; - i->segment.length = 0; - - if (path == 0 || path[0] == '\0') { - return DR_FALSE; - } - - i->path = path; - i->segment.offset = strlen(path); - i->segment.length = 0; - - return drpath_prev(i); -} - -dr_bool32 drpath_next(drpath_iterator* i) -{ - if (i == NULL || i->path == NULL) { - return DR_FALSE; - } - - i->segment.offset = i->segment.offset + i->segment.length; - i->segment.length = 0; - - while (i->path[i->segment.offset] != '\0' && (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\')) { - i->segment.offset += 1; - } - - if (i->path[i->segment.offset] == '\0') { - return DR_FALSE; - } - - - while (i->path[i->segment.offset + i->segment.length] != '\0' && (i->path[i->segment.offset + i->segment.length] != '/' && i->path[i->segment.offset + i->segment.length] != '\\')) { - i->segment.length += 1; - } - - return DR_TRUE; -} - -dr_bool32 drpath_prev(drpath_iterator* i) -{ - if (i == NULL || i->path == NULL || i->segment.offset == 0) { - return DR_FALSE; - } - - i->segment.length = 0; - - do - { - i->segment.offset -= 1; - } while (i->segment.offset > 0 && (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\')); - - if (i->segment.offset == 0) { - if (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\') { - i->segment.length = 0; - return DR_TRUE; - } - - return DR_FALSE; - } - - - size_t offsetEnd = i->segment.offset + 1; - while (i->segment.offset > 0 && (i->path[i->segment.offset] != '/' && i->path[i->segment.offset] != '\\')) { - i->segment.offset -= 1; - } - - if (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\') { - i->segment.offset += 1; - } - - - i->segment.length = offsetEnd - i->segment.offset; - - return DR_TRUE; -} - -dr_bool32 drpath_at_end(drpath_iterator i) -{ - return i.path == 0 || i.path[i.segment.offset] == '\0'; -} - -dr_bool32 drpath_at_start(drpath_iterator i) -{ - return i.path != 0 && i.segment.offset == 0; -} - -dr_bool32 drpath_iterators_equal(const drpath_iterator i0, const drpath_iterator i1) -{ - return drpath_segments_equal(i0.path, i0.segment, i1.path, i1.segment); -} - -dr_bool32 drpath_segments_equal(const char* s0Path, const drpath_segment s0, const char* s1Path, const drpath_segment s1) -{ - if (s0Path == NULL || s1Path == NULL) { - return DR_FALSE; - } - - if (s0.length != s1.length) { - return DR_FALSE; - } - - return strncmp(s0Path + s0.offset, s1Path + s1.offset, s0.length) == 0; -} - - -dr_bool32 drpath_is_root_segment(const drpath_iterator i) -{ - return drpath_is_linux_style_root_segment(i) || drpath_is_win32_style_root_segment(i); -} - -dr_bool32 drpath_is_linux_style_root_segment(const drpath_iterator i) -{ - if (i.path == NULL) { - return DR_FALSE; - } - - if (i.segment.offset == 0 && i.segment.length == 0) { - return DR_TRUE; // "/" style root. - } - - return DR_FALSE; -} - -dr_bool32 drpath_is_win32_style_root_segment(const drpath_iterator i) -{ - if (i.path == NULL) { - return DR_FALSE; - } - - if (i.segment.offset == 0 && i.segment.length == 2) { - if (((i.path[0] >= 'a' && i.path[0] <= 'z') || (i.path[0] >= 'A' && i.path[0] <= 'Z')) && i.path[1] == ':') { - return DR_TRUE; - } - } - - return DR_FALSE; -} - - -void drpath_to_forward_slashes(char* path) -{ - if (path == NULL) { - return; - } - - while (path[0] != '\0') { - if (path[0] == '\\') { - path[0] = '/'; - } - - path += 1; - } -} - -void drpath_to_backslashes(char* path) -{ - if (path == NULL) { - return; - } - - while (path[0] != '\0') { - if (path[0] == '/') { - path[0] = '\\'; - } - - path += 1; - } -} - - -dr_bool32 drpath_is_descendant(const char* descendantAbsolutePath, const char* parentAbsolutePath) -{ - drpath_iterator iChild; - if (!drpath_first(descendantAbsolutePath, &iChild)) { - return DR_FALSE; // The descendant is an empty string which makes it impossible for it to be a descendant. - } - - drpath_iterator iParent; - if (drpath_first(parentAbsolutePath, &iParent)) - { - do - { - // If the segment is different, the paths are different and thus it is not a descendant. - if (!drpath_iterators_equal(iParent, iChild)) { - return DR_FALSE; - } - - if (!drpath_next(&iChild)) { - return DR_FALSE; // The descendant is shorter which means it's impossible for it to be a descendant. - } - - } while (drpath_next(&iParent)); - } - - return DR_TRUE; -} - -dr_bool32 drpath_is_child(const char* childAbsolutePath, const char* parentAbsolutePath) -{ - drpath_iterator iChild; - if (!drpath_first(childAbsolutePath, &iChild)) { - return DR_FALSE; // The descendant is an empty string which makes it impossible for it to be a descendant. - } - - drpath_iterator iParent; - if (drpath_first(parentAbsolutePath, &iParent)) - { - do - { - // If the segment is different, the paths are different and thus it is not a descendant. - if (!drpath_iterators_equal(iParent, iChild)) { - return DR_FALSE; - } - - if (!drpath_next(&iChild)) { - return DR_FALSE; // The descendant is shorter which means it's impossible for it to be a descendant. - } - - } while (drpath_next(&iParent)); - } - - // At this point we have finished iteration of the parent, which should be shorter one. We now do one more iterations of - // the child to ensure it is indeed a direct child and not a deeper descendant. - return !drpath_next(&iChild); -} - -char* drpath_base_path(char* path) -{ - if (path == NULL) { - return NULL; - } - - char* pathorig = path; - char* baseend = path; - - // We just loop through the path until we find the last slash. - while (path[0] != '\0') { - if (path[0] == '/' || path[0] == '\\') { - baseend = path; - } - - path += 1; - } - - - // Now we just loop backwards until we hit the first non-slash. - while (baseend > path) { - if (baseend[0] != '/' && baseend[0] != '\\') { - break; - } - - baseend -= 1; - } - - - // We just put a null terminator on the end. - baseend[0] = '\0'; - - return pathorig; -} - -void drpath_copy_base_path(const char* path, char* baseOut, size_t baseSizeInBytes) -{ - if (path == NULL || baseOut == NULL || baseSizeInBytes == 0) { - return; - } - - strcpy_s(baseOut, baseSizeInBytes, path); - drpath_base_path(baseOut); -} - -const char* drpath_file_name(const char* path) -{ - if (path == NULL) { - return NULL; - } - - const char* fileName = path; - - // We just loop through the path until we find the last slash. - while (path[0] != '\0') { - if (path[0] == '/' || path[0] == '\\') { - fileName = path; - } - - path += 1; - } - - // At this point the file name is sitting on a slash, so just move forward. - while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { - fileName += 1; - } - - return fileName; -} - -const char* drpath_copy_file_name(const char* path, char* fileNameOut, size_t fileNameSizeInBytes) -{ - const char* fileName = drpath_file_name(path); - if (fileName != NULL) { - strcpy_s(fileNameOut, fileNameSizeInBytes, fileName); - } - - return fileName; -} - -const char* drpath_extension(const char* path) -{ - if (path == NULL) { - return NULL; - } - - const char* extension = drpath_file_name(path); - const char* lastoccurance = 0; - - // Just find the last '.' and return. - while (extension[0] != '\0') - { - if (extension[0] == '.') { - extension += 1; - lastoccurance = extension; - } - - extension += 1; - } - - return (lastoccurance != 0) ? lastoccurance : extension; -} - - -dr_bool32 drpath_equal(const char* path1, const char* path2) -{ - if (path1 == NULL || path2 == NULL) { - return DR_FALSE; - } - - if (path1 == path2 || (path1[0] == '\0' && path2[0] == '\0')) { - return DR_TRUE; // Two empty paths are treated as the same. - } - - drpath_iterator iPath1; - drpath_iterator iPath2; - if (drpath_first(path1, &iPath1) && drpath_first(path2, &iPath2)) - { - dr_bool32 isPath1Valid; - dr_bool32 isPath2Valid; - - do - { - if (!drpath_iterators_equal(iPath1, iPath2)) { - return DR_FALSE; - } - - isPath1Valid = drpath_next(&iPath1); - isPath2Valid = drpath_next(&iPath2); - - } while (isPath1Valid && isPath2Valid); - - // At this point either iPath1 and/or iPath2 have finished iterating. If both of them are at the end, the two paths are equal. - return isPath1Valid == isPath2Valid && iPath1.path[iPath1.segment.offset] == '\0' && iPath2.path[iPath2.segment.offset] == '\0'; - } - - return DR_FALSE; -} - -dr_bool32 drpath_extension_equal(const char* path, const char* extension) -{ - if (path == NULL || extension == NULL) { - return DR_FALSE; - } - - const char* ext1 = extension; - const char* ext2 = drpath_extension(path); - -#ifdef _MSC_VER - return _stricmp(ext1, ext2) == 0; -#else - return strcasecmp(ext1, ext2) == 0; -#endif -} - - - -dr_bool32 drpath_is_relative(const char* path) -{ - if (path == NULL) { - return DR_FALSE; - } - - drpath_iterator seg; - if (drpath_first(path, &seg)) { - return !drpath_is_root_segment(seg); - } - - // We'll get here if the path is empty. We consider this to be a relative path. - return DR_TRUE; -} - -dr_bool32 drpath_is_absolute(const char* path) -{ - return !drpath_is_relative(path); -} - - -dr_bool32 drpath_append(char* base, size_t baseBufferSizeInBytes, const char* other) -{ - if (base == NULL || other == NULL) { - return DR_FALSE; - } - - size_t path1Length = strlen(base); - size_t path2Length = strlen(other); - - if (path1Length >= baseBufferSizeInBytes) { - return DR_FALSE; - } - - - // Slash. - if (path1Length > 0 && base[path1Length - 1] != '/' && base[path1Length - 1] != '\\') { - base[path1Length] = '/'; - path1Length += 1; - } - - // Other part. - if (path1Length + path2Length >= baseBufferSizeInBytes) { - path2Length = baseBufferSizeInBytes - path1Length - 1; // -1 for the null terminator. - } - - strncpy_s(base + path1Length, baseBufferSizeInBytes - path1Length, other, path2Length); - - return DR_TRUE; -} - -dr_bool32 drpath_append_iterator(char* base, size_t baseBufferSizeInBytes, drpath_iterator i) -{ - if (base == NULL) { - return DR_FALSE; - } - - size_t path1Length = strlen(base); - size_t path2Length = i.segment.length; - - if (path1Length >= baseBufferSizeInBytes) { - return DR_FALSE; - } - - if (drpath_is_linux_style_root_segment(i)) { - if (baseBufferSizeInBytes > 1) { - base[0] = '/'; - base[1] = '\0'; - return DR_TRUE; - } - } - - // Slash. - if (path1Length > 0 && base[path1Length - 1] != '/' && base[path1Length - 1] != '\\') { - base[path1Length] = '/'; - path1Length += 1; - } - - // Other part. - if (path1Length + path2Length >= baseBufferSizeInBytes) { - path2Length = baseBufferSizeInBytes - path1Length - 1; // -1 for the null terminator. - } - - strncpy_s(base + path1Length, baseBufferSizeInBytes - path1Length, i.path + i.segment.offset, path2Length); - - return DR_TRUE; -} - -dr_bool32 drpath_append_extension(char* base, size_t baseBufferSizeInBytes, const char* extension) -{ - if (base == NULL || extension == NULL) { - return DR_FALSE; - } - - size_t baseLength = strlen(base); - size_t extLength = strlen(extension); - - if (baseLength >= baseBufferSizeInBytes) { - return DR_FALSE; - } - - base[baseLength] = '.'; - baseLength += 1; - - if (baseLength + extLength >= baseBufferSizeInBytes) { - extLength = baseBufferSizeInBytes - baseLength - 1; // -1 for the null terminator. - } - - strncpy_s(base + baseLength, baseBufferSizeInBytes - baseLength, extension, extLength); - - return DR_TRUE; -} - -dr_bool32 drpath_copy_and_append(char* dst, size_t dstSizeInBytes, const char* base, const char* other) -{ - if (dst == NULL || dstSizeInBytes == 0) { - return DR_FALSE; - } - - strcpy_s(dst, dstSizeInBytes, base); - return drpath_append(dst, dstSizeInBytes, other); -} - -dr_bool32 drpath_copy_and_append_iterator(char* dst, size_t dstSizeInBytes, const char* base, drpath_iterator i) -{ - if (dst == NULL || dstSizeInBytes == 0) { - return DR_FALSE; - } - - strcpy_s(dst, dstSizeInBytes, base); - return drpath_append_iterator(dst, dstSizeInBytes, i); -} - -dr_bool32 drpath_copy_and_append_extension(char* dst, size_t dstSizeInBytes, const char* base, const char* extension) -{ - if (dst == NULL || dstSizeInBytes == 0) { - return DR_FALSE; - } - - strcpy_s(dst, dstSizeInBytes, base); - return drpath_append_extension(dst, dstSizeInBytes, extension); -} - - - -// This function recursively cleans a path which is defined as a chain of iterators. This function works backwards, which means at the time of calling this -// function, each iterator in the chain should be placed at the end of the path. -// -// This does not write the null terminator, nor a leading slash for absolute paths. -size_t _drpath_clean_trywrite(drpath_iterator* iterators, unsigned int iteratorCount, char* pathOut, size_t pathOutSizeInBytes, unsigned int ignoreCounter) -{ - if (iteratorCount == 0) { - return 0; - } - - drpath_iterator isegment = iterators[iteratorCount - 1]; - - - // If this segment is a ".", we ignore it. If it is a ".." we ignore it and increment "ignoreCount". - int ignoreThisSegment = ignoreCounter > 0 && isegment.segment.length > 0; - - if (isegment.segment.length == 1 && isegment.path[isegment.segment.offset] == '.') - { - // "." - ignoreThisSegment = 1; - } - else - { - if (isegment.segment.length == 2 && isegment.path[isegment.segment.offset] == '.' && isegment.path[isegment.segment.offset + 1] == '.') - { - // ".." - ignoreThisSegment = 1; - ignoreCounter += 1; - } - else - { - // It's a regular segment, so decrement the ignore counter. - if (ignoreCounter > 0) { - ignoreCounter -= 1; - } - } - } - - - // The previous segment needs to be written before we can write this one. - size_t bytesWritten = 0; - - drpath_iterator prev = isegment; - if (!drpath_prev(&prev)) - { - if (iteratorCount > 1) - { - iteratorCount -= 1; - prev = iterators[iteratorCount - 1]; - } - else - { - prev.path = NULL; - prev.segment.offset = 0; - prev.segment.length = 0; - } - } - - if (prev.segment.length > 0) - { - iterators[iteratorCount - 1] = prev; - bytesWritten = _drpath_clean_trywrite(iterators, iteratorCount, pathOut, pathOutSizeInBytes, ignoreCounter); - } - - - if (!ignoreThisSegment) - { - if (pathOutSizeInBytes > 0) - { - pathOut += bytesWritten; - pathOutSizeInBytes -= bytesWritten; - - if (bytesWritten > 0) - { - pathOut[0] = '/'; - bytesWritten += 1; - - pathOut += 1; - pathOutSizeInBytes -= 1; - } - - if (pathOutSizeInBytes >= isegment.segment.length) - { - strncpy_s(pathOut, pathOutSizeInBytes, isegment.path + isegment.segment.offset, isegment.segment.length); - bytesWritten += isegment.segment.length; - } - else - { - strncpy_s(pathOut, pathOutSizeInBytes, isegment.path + isegment.segment.offset, pathOutSizeInBytes); - bytesWritten += pathOutSizeInBytes; - } - } - } - - return bytesWritten; -} - -size_t drpath_clean(const char* path, char* pathOut, size_t pathOutSizeInBytes) -{ - if (path == NULL) { - return 0; - } - - drpath_iterator last; - if (drpath_last(path, &last)) - { - size_t bytesWritten = 0; - if (path[0] == '/') { - if (pathOut != NULL && pathOutSizeInBytes > 1) { - pathOut[0] = '/'; - bytesWritten = 1; - } - } - - bytesWritten += _drpath_clean_trywrite(&last, 1, pathOut + bytesWritten, pathOutSizeInBytes - bytesWritten - 1, 0); // -1 to ensure there is enough room for a null terminator later on. - if (pathOutSizeInBytes > bytesWritten) { - pathOut[bytesWritten] = '\0'; - } - - return bytesWritten + 1; - } - - return 0; -} - -size_t drpath_append_and_clean(char* dst, size_t dstSizeInBytes, const char* base, const char* other) -{ - if (base == NULL || other == NULL) { - return 0; - } - - drpath_iterator last[2] = { - {NULL, {0, 0}}, - {NULL, {0, 0}} - }; - - dr_bool32 isPathEmpty0 = !drpath_last(base, last + 0); - dr_bool32 isPathEmpty1 = !drpath_last(other, last + 1); - - int iteratorCount = !isPathEmpty0 + !isPathEmpty1; - if (iteratorCount == 0) { - return 0; // Both input strings are empty. - } - - size_t bytesWritten = 0; - if (base[0] == '/') { - if (dst != NULL && dstSizeInBytes > 1) { - dst[0] = '/'; - bytesWritten = 1; - } - } - - bytesWritten += _drpath_clean_trywrite(last, 2, dst + bytesWritten, dstSizeInBytes - bytesWritten - 1, 0); // -1 to ensure there is enough room for a null terminator later on. - if (dstSizeInBytes > bytesWritten) { - dst[bytesWritten] = '\0'; - } - - return bytesWritten + 1; -} - - -dr_bool32 drpath_remove_extension(char* path) -{ - if (path == NULL) { - return DR_FALSE; - } - - const char* extension = drpath_extension(path); - if (extension != NULL) { - extension -= 1; - path[(extension - path)] = '\0'; - } - - return DR_TRUE; -} - -dr_bool32 drpath_copy_and_remove_extension(char* dst, size_t dstSizeInBytes, const char* path) -{ - if (dst == NULL || dstSizeInBytes == 0 || path == NULL) { - return DR_FALSE; - } - - const char* extension = drpath_extension(path); - if (extension != NULL) { - extension -= 1; - } - - strncpy_s(dst, dstSizeInBytes, path, (size_t)(extension - path)); - return DR_TRUE; -} - - -dr_bool32 drpath_remove_file_name(char* path) -{ - if (path == NULL) { - return DR_FALSE; - } - - - // We just create an iterator that starts at the last segment. We then move back one and place a null terminator at the end of - // that segment. That will ensure the resulting path is not left with a slash. - drpath_iterator iLast; - if (!drpath_last(path, &iLast)) { - return DR_FALSE; // The path is empty. - } - - if (drpath_is_root_segment(iLast)) { - return DR_FALSE; - } - - - drpath_iterator iSecondLast = iLast; - if (drpath_prev(&iSecondLast)) - { - // There is a segment before it so we just place a null terminator at the end, but only if it's not the root of a Linux-style absolute path. - if (drpath_is_linux_style_root_segment(iSecondLast)) { - path[iLast.segment.offset] = '\0'; - } else { - path[iSecondLast.segment.offset + iSecondLast.segment.length] = '\0'; - } - } - else - { - // This is already the last segment, so just place a null terminator at the beginning of the string. - path[0] = '\0'; - } - - return DR_TRUE; -} - -dr_bool32 drpath_copy_and_remove_file_name(char* dst, size_t dstSizeInBytes, const char* path) -{ - if (dst == NULL) { - return DR_FALSE; - } - if (dstSizeInBytes == 0) { - return DR_FALSE; - } - if (path == NULL) { - dst[0] = '\0'; - return DR_FALSE; - } - - - // We just create an iterator that starts at the last segment. We then move back one and place a null terminator at the end of - // that segment. That will ensure the resulting path is not left with a slash. - drpath_iterator iLast; - if (!drpath_last(path, &iLast)) { - dst[0] = '\0'; - return DR_FALSE; // The path is empty. - } - - if (drpath_is_linux_style_root_segment(iLast)) { - if (dstSizeInBytes > 1) { - dst[0] = '/'; dst[1] = '\0'; - return DR_FALSE; - } else { - dst[0] = '\0'; - return DR_FALSE; - } - } - - if (drpath_is_win32_style_root_segment(iLast)) { - return strncpy_s(dst, dstSizeInBytes, path + iLast.segment.offset, iLast.segment.length) == 0; - } - - - drpath_iterator iSecondLast = iLast; - if (drpath_prev(&iSecondLast)) - { - // There is a segment before it so we just place a null terminator at the end, but only if it's not the root of a Linux-style absolute path. - if (drpath_is_linux_style_root_segment(iSecondLast)) { - return strcpy_s(dst, dstSizeInBytes, "/") == 0; - } else { - return strncpy_s(dst, dstSizeInBytes, path, iSecondLast.segment.offset + iSecondLast.segment.length) == 0; - } - } - else - { - // This is already the last segment, so just place a null terminator at the beginning of the string. - dst[0] = '\0'; - return DR_TRUE; - } -} - - -dr_bool32 drpath_to_relative(const char* absolutePathToMakeRelative, const char* absolutePathToMakeRelativeTo, char* relativePathOut, size_t relativePathOutSizeInBytes) -{ - // We do this in two phases. The first phase just iterates past each segment of both the path to convert and the - // base path until we find two that are not equal. The second phase just adds the appropriate ".." segments. - - if (relativePathOut == 0) { - return DR_FALSE; - } - if (relativePathOutSizeInBytes == 0) { - return DR_FALSE; - } - - if (!drpath_is_absolute(absolutePathToMakeRelative) || !drpath_is_absolute(absolutePathToMakeRelativeTo)) { - return DR_FALSE; - } - - - drpath_iterator iPath; - drpath_iterator iBase; - dr_bool32 isPathEmpty = !drpath_first(absolutePathToMakeRelative, &iPath); - dr_bool32 isBaseEmpty = !drpath_first(absolutePathToMakeRelativeTo, &iBase); - - if (isPathEmpty && isBaseEmpty) - { - // Looks like both paths are empty. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - - // Phase 1: Get past the common section. - int isPathAtEnd = 0; - int isBaseAtEnd = 0; - while (!isPathAtEnd && !isBaseAtEnd && drpath_iterators_equal(iPath, iBase)) - { - isPathAtEnd = !drpath_next(&iPath); - isBaseAtEnd = !drpath_next(&iBase); - } - - if (iPath.segment.offset == 0) - { - // The path is not relative to the base path. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - - // Phase 2: Append ".." segments - one for each remaining segment in the base path. - char* pDst = relativePathOut; - size_t bytesAvailable = relativePathOutSizeInBytes; - - if (!drpath_at_end(iBase)) - { - do - { - if (pDst != relativePathOut) - { - if (bytesAvailable <= 3) - { - // Ran out of room. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - pDst[0] = '/'; - pDst[1] = '.'; - pDst[2] = '.'; - - pDst += 3; - bytesAvailable -= 3; - } - else - { - // It's the first segment, so we need to ensure we don't lead with a slash. - if (bytesAvailable <= 2) - { - // Ran out of room. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - pDst[0] = '.'; - pDst[1] = '.'; - - pDst += 2; - bytesAvailable -= 2; - } - } while (drpath_next(&iBase)); - } - - - // Now we just append whatever is left of the main path. We want the path to be clean, so we append segment-by-segment. - if (!drpath_at_end(iPath)) - { - do - { - // Leading slash, if required. - if (pDst != relativePathOut) - { - if (bytesAvailable <= 1) - { - // Ran out of room. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - pDst[0] = '/'; - - pDst += 1; - bytesAvailable -= 1; - } - - - if (bytesAvailable <= iPath.segment.length) - { - // Ran out of room. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - if (strncpy_s(pDst, bytesAvailable, iPath.path + iPath.segment.offset, iPath.segment.length) != 0) - { - // Error copying the string. Probably ran out of room in the output buffer. - relativePathOut[0] = '\0'; - return DR_FALSE; - } - - pDst += iPath.segment.length; - bytesAvailable -= iPath.segment.length; - - - } while (drpath_next(&iPath)); - } - - - // Always null terminate. - //assert(bytesAvailable > 0); - pDst[0] = '\0'; - - return DR_TRUE; -} - -dr_bool32 drpath_to_absolute(const char* relativePathToMakeAbsolute, const char* basePath, char* absolutePathOut, size_t absolutePathOutSizeInBytes) -{ - return drpath_append_and_clean(absolutePathOut, absolutePathOutSizeInBytes, basePath, relativePathToMakeAbsolute) != 0; -} -#endif //DR_IMPLEMENTATION - - - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_2d.h b/source/engine/thirdparty/dr_libs/old/dr_2d.h deleted file mode 100644 index 36d1a40..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_2d.h +++ /dev/null @@ -1,3417 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. - -// ABOUT -// -// dr_2d is a simple library for drawing simple 2D graphics. -// -// -// -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_2D_IMPLEMENTATION -// #include "dr_2d.h" -// -// You can then #include dr_2d.h in other parts of the program as you would with any other header file. -// -// -// -// QUICK NOTES -// -// - Drawing must be done inside a dr2d_begin_draw() and dr2d_end_draw() pair. Rationale: 1) required for compatibility -// with GDI's BeginPaint() and EndPaint() APIs; 2) gives implementations opportunity to save and restore state, such as -// OpenGL state and whatnot. -// - This library is not thread safe. -// -// -// -// OPTIONS -// -// #define DR2D_NO_GDI -// Excludes the GDI back-end. -// -// #define DR2D_NO_CAIRO -// Excludes the Cairo back-end. -// -// -// -// TODO -// - Document resource management. - -#ifndef dr_2d_h -#define dr_2d_h - -#include -#include - -#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64) -#include - -// No Cairo on Win32 builds. -#ifndef DR2D_NO_CAIRO -#define DR2D_NO_CAIRO -#endif -#else -// No GDI on non-Win32 builds. -#ifndef DR2D_NO_GDI -#define DR2D_NO_GDI -#endif -#endif - -#ifndef DR2D_MAX_FONT_FAMILY_LENGTH -#define DR2D_MAX_FONT_FAMILY_LENGTH 128 -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - - -///////////////////////////////////////////////////////////////// -// -// CORE 2D API -// -///////////////////////////////////////////////////////////////// - -typedef unsigned char dr2d_byte; - -typedef struct dr2d_context dr2d_context; -typedef struct dr2d_surface dr2d_surface; -typedef struct dr2d_font dr2d_font; -typedef struct dr2d_image dr2d_image; -typedef struct dr2d_color dr2d_color; -typedef struct dr2d_font_metrics dr2d_font_metrics; -typedef struct dr2d_glyph_metrics dr2d_glyph_metrics; -typedef struct dr2d_drawing_callbacks dr2d_drawing_callbacks; - - -/// Structure representing an RGBA color. Color components are specified in the range of 0 - 255. -struct dr2d_color -{ - dr2d_byte r; - dr2d_byte g; - dr2d_byte b; - dr2d_byte a; -}; - -struct dr2d_font_metrics -{ - int ascent; - int descent; - int lineHeight; - int spaceWidth; -}; - -struct dr2d_glyph_metrics -{ - int width; - int height; - int originX; - int originY; - int advanceX; - int advanceY; -}; - -typedef enum -{ - dr2d_font_weight_medium = 0, - dr2d_font_weight_thin, - dr2d_font_weight_extra_light, - dr2d_font_weight_light, - dr2d_font_weight_semi_light, - dr2d_font_weight_book, - dr2d_font_weight_semi_bold, - dr2d_font_weight_bold, - dr2d_font_weight_extra_bold, - dr2d_font_weight_heavy, - dr2d_font_weight_extra_heavy, - - dr2d_font_weight_normal = dr2d_font_weight_medium, - dr2d_font_weight_default = dr2d_font_weight_medium - -} dr2d_font_weight; - -typedef enum -{ - dr2d_font_slant_none = 0, - dr2d_font_slant_italic, - dr2d_font_slant_oblique - -} dr2d_font_slant; - -typedef enum -{ - dr2d_image_format_rgba8, - dr2d_image_format_bgra8, - dr2d_image_format_argb8, -} dr2d_image_format; - - -#define DR2D_IMAGE_DRAW_BACKGROUND (1 << 0) -#define DR2D_IMAGE_HINT_NO_ALPHA (1 << 1) - -#define DR2D_READ (1 << 0) -#define DR2D_WRITE (1 << 1) - -#define DR2D_FONT_NO_CLEARTYPE (1 << 0) - -typedef struct -{ - /// The destination position on the x axis. This is ignored if the DR2D_IMAGE_ALIGN_CENTER option is set. - float dstX; - - /// The destination position on the y axis. This is ignored if the DR2D_IMAGE_ALIGN_CENTER option is set. - float dstY; - - /// The destination width. - float dstWidth; - - /// The destination height. - float dstHeight; - - - /// The source offset on the x axis. - float srcX; - - /// The source offset on the y axis. - float srcY; - - /// The source width. - float srcWidth; - - /// The source height. - float srcHeight; - - - /// The foreground tint color. This is not applied to the background color, and the alpha component is ignored. - dr2d_color foregroundTint; - - /// The background color. Only used if the DR2D_IMAGE_DRAW_BACKGROUND option is set. - dr2d_color backgroundColor; - - - /// Flags for controlling how the image should be drawn. - unsigned int options; - -} dr2d_draw_image_args; - - -typedef bool (* dr2d_on_create_context_proc) (dr2d_context* pContext, const void* pUserData); -typedef void (* dr2d_on_delete_context_proc) (dr2d_context* pContext); -typedef bool (* dr2d_on_create_surface_proc) (dr2d_surface* pSurface, float width, float height); -typedef void (* dr2d_on_delete_surface_proc) (dr2d_surface* pSurface); -typedef bool (* dr2d_on_create_font_proc) (dr2d_font* pFont); -typedef void (* dr2d_on_delete_font_proc) (dr2d_font* pFont); -typedef bool (* dr2d_on_create_image_proc) (dr2d_image* pImage, unsigned int stride, const void* pData); -typedef void (* dr2d_on_delete_image_proc) (dr2d_image* pImage); -typedef void (* dr2d_begin_draw_proc) (dr2d_surface* pSurface); -typedef void (* dr2d_end_draw_proc) (dr2d_surface* pSurface); -typedef void (* dr2d_clear_proc) (dr2d_surface* pSurface, dr2d_color color); -typedef void (* dr2d_draw_rect_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color); -typedef void (* dr2d_draw_rect_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth); -typedef void (* dr2d_draw_rect_with_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor); -typedef void (* dr2d_draw_round_rect_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float width); -typedef void (* dr2d_draw_round_rect_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float width, float outlineWidth); -typedef void (* dr2d_draw_round_rect_with_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float width, float outlineWidth, dr2d_color outlineColor); -typedef void (* dr2d_draw_text_proc) (dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor); -typedef void (* dr2d_draw_image_proc) (dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs); -typedef void (* dr2d_set_clip_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom); -typedef void (* dr2d_get_clip_proc) (dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut); -typedef dr2d_image_format (* dr2d_get_optimal_image_format_proc) (dr2d_context* pContext); -typedef void* (* dr2d_map_image_data_proc) (dr2d_image* pImage, unsigned int accessFlags); -typedef void (* dr2d_unmap_image_data_proc) (dr2d_image* pImage); -typedef bool (* dr2d_get_font_metrics_proc) (dr2d_font* pFont, dr2d_font_metrics* pMetricsOut); -typedef bool (* dr2d_get_glyph_metrics_proc) (dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pMetricsOut); -typedef bool (* dr2d_measure_string_proc) (dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut); -typedef bool (* dr2d_get_text_cursor_position_from_point_proc)(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); -typedef bool (* dr2d_get_text_cursor_position_from_char_proc) (dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - - -struct dr2d_drawing_callbacks -{ - dr2d_on_create_context_proc on_create_context; - dr2d_on_delete_context_proc on_delete_context; - dr2d_on_create_surface_proc on_create_surface; - dr2d_on_delete_surface_proc on_delete_surface; - dr2d_on_create_font_proc on_create_font; - dr2d_on_delete_font_proc on_delete_font; - dr2d_on_create_image_proc on_create_image; - dr2d_on_delete_image_proc on_delete_image; - - dr2d_begin_draw_proc begin_draw; - dr2d_end_draw_proc end_draw; - dr2d_clear_proc clear; - dr2d_draw_rect_proc draw_rect; - dr2d_draw_rect_outline_proc draw_rect_outline; - dr2d_draw_rect_with_outline_proc draw_rect_with_outline; - dr2d_draw_round_rect_proc draw_round_rect; - dr2d_draw_round_rect_outline_proc draw_round_rect_outline; - dr2d_draw_round_rect_with_outline_proc draw_round_rect_with_outline; - dr2d_draw_text_proc draw_text; - dr2d_draw_image_proc draw_image; - dr2d_set_clip_proc set_clip; - dr2d_get_clip_proc get_clip; - - dr2d_get_optimal_image_format_proc get_optimal_image_format; - dr2d_map_image_data_proc map_image_data; - dr2d_unmap_image_data_proc unmap_image_data; - - dr2d_get_font_metrics_proc get_font_metrics; - dr2d_get_glyph_metrics_proc get_glyph_metrics; - dr2d_measure_string_proc measure_string; - dr2d_get_text_cursor_position_from_point_proc get_text_cursor_position_from_point; - dr2d_get_text_cursor_position_from_char_proc get_text_cursor_position_from_char; -}; - -struct dr2d_image -{ - /// A pointer to the context that owns the image. - dr2d_context* pContext; - - /// The width of the image. - unsigned int width; - - /// The height of the image. - unsigned int height; - - /// The format of the image data. - dr2d_image_format format; - - /// Whether or not the image's data is already mapped. - bool isMapped; - - /// The extra bytes. The size of this buffer is equal to pContext->imageExtraBytes. - dr2d_byte pExtraData[1]; -}; - -struct dr2d_font -{ - /// A pointer to the context that owns the font. - dr2d_context* pContext; - - /// The font family. - char family[DR2D_MAX_FONT_FAMILY_LENGTH]; - - /// The size of the font. - unsigned int size; - - /// The font's weight. - dr2d_font_weight weight; - - /// The font's slant. - dr2d_font_slant slant; - - /// The font's rotation, in degrees. - float rotation; - - /// Flags. Can be a combination of the following. - /// DR2D_FONT_NO_CLEARTYPE - unsigned int flags; - - /// The extra bytes. The size of this buffer is equal to pContext->fontExtraBytes. - dr2d_byte pExtraData[1]; -}; - -struct dr2d_surface -{ - /// A pointer to the context that owns the surface. - dr2d_context* pContext; - - /// The width of the surface. - float width; - - /// The height of the surface. - float height; - - /// The extra bytes. The size of this buffer is equal to pContext->surfaceExtraBytes. - dr2d_byte pExtraData[1]; -}; - -struct dr2d_context -{ - /// The drawing callbacks. - dr2d_drawing_callbacks drawingCallbacks; - - /// The number of extra bytes to allocate for each image. - size_t imageExtraBytes; - - /// The number of extra bytes to allocate for each font. - size_t fontExtraBytes; - - /// The number of extra bytes to allocate for each surface. - size_t surfaceExtraBytes; - - /// The number of extra bytes to allocate for the context. - size_t contextExtraBytes; - - /// The extra bytes. - dr2d_byte pExtraData[1]; -}; - - - -/// Creats a context. -dr2d_context* dr2d_create_context(dr2d_drawing_callbacks drawingCallbacks, size_t contextExtraBytes, size_t surfaceExtraBytes, size_t fontExtraBytes, size_t imageExtraBytes, const void* pUserData); - -/// Deletes the given context. -void dr2d_delete_context(dr2d_context* pContext); - -/// Retrieves a pointer to the given context's extra data buffer. -void* dr2d_get_context_extra_data(dr2d_context* pContext); - - -/// Creates a surface. -dr2d_surface* dr2d_create_surface(dr2d_context* pContext, float width, float height); - -/// Deletes the given surface. -void dr2d_delete_surface(dr2d_surface* pSurface); - -/// Retrieves the width of the surface. -float dr2d_get_surface_width(const dr2d_surface* pSurface); - -/// Retrieves the height of the surface. -float dr2d_get_surface_height(const dr2d_surface* pSurface); - -/// Retrieves a pointer to the given surface's extra data buffer. -void* dr2d_get_surface_extra_data(dr2d_surface* pSurface); - - - -//// Drawing //// - -/// Marks the beginning of a paint operation. -void dr2d_begin_draw(dr2d_surface* pSurface); - -/// Marks the end of a paint operation. -void dr2d_end_draw(dr2d_surface* pSurface); - -/// Clears the given surface with the given color. -void dr2d_clear(dr2d_surface* pSurface, dr2d_color color); - -/// Draws a filled rectangle without an outline. -void dr2d_draw_rect(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color); - -/// Draws the outline of the given rectangle. -void dr2d_draw_rect_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth); - -/// Draws a filled rectangle with an outline. -void dr2d_draw_rect_with_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor); - -/// Draws a filled rectangle without an outline with rounded corners. -void dr2d_draw_round_rect(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius); - -/// Draws the outline of the given rectangle with rounded corners. -void dr2d_draw_round_rect_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth); - -/// Draws a filled rectangle with an outline. -void dr2d_draw_round_rect_with_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor); - -/// Draws a run of text. -void dr2d_draw_text(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor); - -/// Draws an image. -void dr2d_draw_image(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs); - -/// Sets the clipping rectangle. -void dr2d_set_clip(dr2d_surface* pSurface, float left, float top, float right, float bottom); - -/// Retrieves the clipping rectangle. -void dr2d_get_clip(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut); - - -/// Creates a font that can be passed to dr2d_draw_text(). -dr2d_font* dr2d_create_font(dr2d_context* pContext, const char* family, unsigned int size, dr2d_font_weight weight, dr2d_font_slant slant, float rotation, unsigned int flags); - -/// Deletes a font that was previously created with dr2d_create_font() -void dr2d_delete_font(dr2d_font* pFont); - -/// Retrieves a pointer to the given font's extra data buffer. -void* dr2d_get_font_extra_data(dr2d_font* pFont); - -/// Retrieves the size of the given font. -unsigned int dr2d_get_font_size(dr2d_font* pFont); - -/// Retrieves the metrics of the given font. -bool dr2d_get_font_metrics(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut); - -/// Retrieves the metrics of the glyph for the given character when rendered with the given font. -bool dr2d_get_glyph_metrics(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pMetricsOut); - -/// Retrieves the dimensions of the given string when drawn with the given font. -bool dr2d_measure_string(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut); - -/// Retrieves the position to place a text cursor based on the given point for the given string when drawn with the given font. -bool dr2d_get_text_cursor_position_from_point(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); - -/// Retrieves the position to palce a text cursor based on the character at the given index for the given string when drawn with the given font. -bool dr2d_get_text_cursor_position_from_char(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - - -/// Creates an image that can be passed to dr2d_draw_image(). -/// -/// @remarks -/// The dimensions and format of an image are immutable. If these need to change, then the image needs to be deleted and re-created. -/// @par -/// If pData is NULL, the default image data is undefined. -/// @par -/// Use dr2d_map_image_data() and dr2d_unmap_image_data() to update or retrieve image data. -dr2d_image* dr2d_create_image(dr2d_context* pContext, unsigned int width, unsigned int height, dr2d_image_format format, unsigned int stride, const void* pData); - -/// Deletes the given image. -void dr2d_delete_image(dr2d_image* pImage); - -/// Retrieves a pointer to the given image's extra data buffer. -void* dr2d_get_image_extra_data(dr2d_image* pImage); - -/// Retrieves the size of the given image. -void dr2d_get_image_size(dr2d_image* pImage, unsigned int* pWidthOut, unsigned int* pHeightOut); - -/// Retrieves a pointer to a buffer representing the given image's data. -/// -/// Call dr2d_unmap_image_data() when you are done with this function. -/// -/// Use this function to access an image's data. The returned pointer does not necessarilly point to the image's actual data, so when -/// writing to this pointer, nothing is guaranteed to be updated until dr2d_unmap_image_data() is called. -/// -/// The returned data will contain the image data at the time of the mapping. -/// -/// This will fail if the image's data is already mapped. -void* dr2d_map_image_data(dr2d_image* pImage, unsigned int accessFlags); - -/// Unmaps the given image's data. -/// -/// A flush is done at this point to ensure the actual underlying image data is updated. -void dr2d_unmap_image_data(dr2d_image* pImage); - -/// Retrieves the optimal image format for the given context. This depends on the backend. -dr2d_image_format dr2d_get_optimal_image_format(dr2d_context* pContext); - - -///////////////////////////////////////////////////////////////// -// -// UTILITY API -// -///////////////////////////////////////////////////////////////// - -/// Creates a color object from a set of RGBA color components. -dr2d_color dr2d_rgba(dr2d_byte r, dr2d_byte g, dr2d_byte b, dr2d_byte a); - -/// Creates a fully opaque color object from a set of RGB color components. -dr2d_color dr2d_rgb(dr2d_byte r, dr2d_byte g, dr2d_byte b); - - - - -///////////////////////////////////////////////////////////////// -// -// WINDOWS GDI 2D API -// -// When using GDI as the rendering back-end you will usually want to only call drawing functions in response to a WM_PAINT message. -// -///////////////////////////////////////////////////////////////// -#ifndef DR2D_NO_GDI - -/// Creates a 2D context with GDI as the backend and, optionally, a custom HDC. -/// -/// hDC [in, optional] The main device context. Can be null. -dr2d_context* dr2d_create_context_gdi(HDC hDC); - -/// Creates a surface that draws directly to the given window. -/// -/// @remarks -/// When using this kind of surface, the internal HBITMAP is not used. -dr2d_surface* dr2d_create_surface_gdi_HWND(dr2d_context* pContext, HWND hWnd); -dr2d_surface* dr2d_create_surface_gdi_HDC(dr2d_context* pContext, HDC hDC); - -/// Retrieves the internal HDC that we have been rendering to for the given surface. -/// -/// @remarks -/// This assumes the given surface was created from a context that was created from dr2d_create_context_gdi() -HDC dr2d_get_HDC(dr2d_surface* pSurface); - -/// Retrieves the internal HBITMAP object that we have been rendering to. -/// -/// @remarks -/// This assumes the given surface was created from a context that was created from dr2d_create_context_gdi(). -HBITMAP dr2d_get_HBITMAP(dr2d_surface* pSurface); - -/// Retrieves the internal HFONT object from the given dr2d_font object. -HFONT dr2d_get_HFONT(dr2d_font* pFont); - -#endif // GDI - - - -///////////////////////////////////////////////////////////////// -// -// CAIRO 2D API -// -///////////////////////////////////////////////////////////////// -#ifndef DR2D_NO_CAIRO -#include - -/// Creates a 2D context with Cairo as the backend. -dr2d_context* dr2d_create_context_cairo(); - -/// Creates a surface that draws directly to the given cairo context. -dr2d_surface* dr2d_create_surface_cairo(dr2d_context* pContext, cairo_t* cr); - -/// Retrieves the internal cairo_surface_t object from the given surface. -/// -/// @remarks -/// This assumes the given surface was created from a context that was created with dr2d_create_context_cairo(). -cairo_surface_t* dr2d_get_cairo_surface_t(dr2d_surface* pSurface); - -/// Retrieves the internal cairo_t object from the given surface. -cairo_t* dr2d_get_cairo_t(dr2d_surface* pSurface); - -#endif // Cairo - - -#ifdef __cplusplus -} -#endif - -#endif //dr_2d_h - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_2D_IMPLEMENTATION -#include -#include -#include -#include -#include - -#ifndef DR2D_PRIVATE -#define DR2D_PRIVATE static -#endif - -static int dr2d_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ -#ifdef _WIN32 - return strcpy_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t i; - for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstSizeInBytes) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -#endif -} - - -dr2d_context* dr2d_create_context(dr2d_drawing_callbacks drawingCallbacks, size_t contextExtraBytes, size_t surfaceExtraBytes, size_t fontExtraBytes, size_t imageExtraBytes, const void* pUserData) -{ - dr2d_context* pContext = (dr2d_context*)malloc(sizeof(dr2d_context) + contextExtraBytes); - if (pContext != NULL) - { - pContext->drawingCallbacks = drawingCallbacks; - pContext->imageExtraBytes = imageExtraBytes; - pContext->fontExtraBytes = fontExtraBytes; - pContext->surfaceExtraBytes = surfaceExtraBytes; - pContext->contextExtraBytes = contextExtraBytes; - memset(pContext->pExtraData, 0, contextExtraBytes); - - // The create_context callback is optional. If it is set to NULL, we just finish up here and return successfully. Otherwise - // we want to call the create_context callback and check it's return value. If it's return value if false it means there - // was an error and we need to return null. - if (pContext->drawingCallbacks.on_create_context != NULL) - { - if (!pContext->drawingCallbacks.on_create_context(pContext, pUserData)) - { - // An error was thrown from the callback. - free(pContext); - pContext = NULL; - } - } - } - - return pContext; -} - -void dr2d_delete_context(dr2d_context* pContext) -{ - if (pContext != NULL) { - if (pContext->drawingCallbacks.on_delete_context != NULL) { - pContext->drawingCallbacks.on_delete_context(pContext); - } - - free(pContext); - } -} - -void* dr2d_get_context_extra_data(dr2d_context* pContext) -{ - return pContext->pExtraData; -} - - -dr2d_surface* dr2d_create_surface(dr2d_context* pContext, float width, float height) -{ - if (pContext != NULL) - { - dr2d_surface* pSurface = (dr2d_surface*)malloc(sizeof(dr2d_surface) + pContext->surfaceExtraBytes); - if (pSurface != NULL) - { - pSurface->pContext = pContext; - pSurface->width = width; - pSurface->height = height; - memset(pSurface->pExtraData, 0, pContext->surfaceExtraBytes); - - // The create_surface callback is optional. If it is set to NULL, we just finish up here and return successfully. Otherwise - // we want to call the create_surface callback and check it's return value. If it's return value if false it means there - // was an error and we need to return null. - if (pContext->drawingCallbacks.on_create_surface != NULL) - { - if (!pContext->drawingCallbacks.on_create_surface(pSurface, width, height)) - { - free(pSurface); - pSurface = NULL; - } - } - } - - return pSurface; - } - - return NULL; -} - -void dr2d_delete_surface(dr2d_surface* pSurface) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.on_delete_surface != NULL) { - pSurface->pContext->drawingCallbacks.on_delete_surface(pSurface); - } - - free(pSurface); - } -} - -float dr2d_get_surface_width(const dr2d_surface* pSurface) -{ - if (pSurface != NULL) { - return pSurface->width; - } - - return 0; -} - -float dr2d_get_surface_height(const dr2d_surface* pSurface) -{ - if (pSurface != NULL) { - return pSurface->height; - } - - return 0; -} - -void* dr2d_get_surface_extra_data(dr2d_surface* pSurface) -{ - if (pSurface != NULL) { - return pSurface->pExtraData; - } - - return NULL; -} - - -void dr2d_begin_draw(dr2d_surface* pSurface) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.begin_draw != NULL) { - pSurface->pContext->drawingCallbacks.begin_draw(pSurface); - } - } -} - -void dr2d_end_draw(dr2d_surface* pSurface) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.end_draw != NULL) { - pSurface->pContext->drawingCallbacks.end_draw(pSurface); - } - } -} - -void dr2d_clear(dr2d_surface * pSurface, dr2d_color color) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.clear != NULL) { - pSurface->pContext->drawingCallbacks.clear(pSurface, color); - } - } -} - -void dr2d_draw_rect(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_rect != NULL) { - pSurface->pContext->drawingCallbacks.draw_rect(pSurface, left, top, right, bottom, color); - } - } -} - -void dr2d_draw_rect_outline(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_rect_outline != NULL) { - pSurface->pContext->drawingCallbacks.draw_rect_outline(pSurface, left, top, right, bottom, color, outlineWidth); - } - } -} - -void dr2d_draw_rect_with_outline(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_rect_with_outline != NULL) { - pSurface->pContext->drawingCallbacks.draw_rect_with_outline(pSurface, left, top, right, bottom, color, outlineWidth, outlineColor); - } - } -} - -void dr2d_draw_round_rect(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_round_rect != NULL) { - pSurface->pContext->drawingCallbacks.draw_round_rect(pSurface, left, top, right, bottom, color, radius); - } - } -} - -void dr2d_draw_round_rect_outline(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_round_rect_outline != NULL) { - pSurface->pContext->drawingCallbacks.draw_round_rect_outline(pSurface, left, top, right, bottom, color, radius, outlineWidth); - } - } -} - -void dr2d_draw_round_rect_with_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_round_rect_with_outline != NULL) { - pSurface->pContext->drawingCallbacks.draw_round_rect_with_outline(pSurface, left, top, right, bottom, color, radius, outlineWidth, outlineColor); - } - } -} - -void dr2d_draw_text(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_text != NULL) { - pSurface->pContext->drawingCallbacks.draw_text(pSurface, pFont, text, textSizeInBytes, posX, posY, color, backgroundColor); - } - } -} - -void dr2d_draw_image(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs) -{ - if (pSurface == NULL || pImage == NULL || pArgs == NULL) { - return; - } - - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.draw_image) { - pSurface->pContext->drawingCallbacks.draw_image(pSurface, pImage, pArgs); - } -} - -void dr2d_set_clip(dr2d_surface* pSurface, float left, float top, float right, float bottom) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.set_clip != NULL) { - pSurface->pContext->drawingCallbacks.set_clip(pSurface, left, top, right, bottom); - } - } -} - -void dr2d_get_clip(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut) -{ - if (pSurface != NULL) - { - assert(pSurface->pContext != NULL); - - if (pSurface->pContext->drawingCallbacks.get_clip != NULL) { - pSurface->pContext->drawingCallbacks.get_clip(pSurface, pLeftOut, pTopOut, pRightOut, pBottomOut); - } - } -} - -dr2d_font* dr2d_create_font(dr2d_context* pContext, const char* family, unsigned int size, dr2d_font_weight weight, dr2d_font_slant slant, float rotation, unsigned int flags) -{ - if (pContext == NULL) { - return NULL; - } - - dr2d_font* pFont = (dr2d_font*)malloc(sizeof(dr2d_font) + pContext->fontExtraBytes); - if (pFont == NULL) { - return NULL; - } - - pFont->pContext = pContext; - pFont->family[0] = '\0'; - pFont->size = size; - pFont->weight = weight; - pFont->slant = slant; - pFont->rotation = rotation; - pFont->flags = flags; - - if (family != NULL) { - dr2d_strcpy_s(pFont->family, sizeof(pFont->family), family); - } - - if (pContext->drawingCallbacks.on_create_font != NULL) { - if (!pContext->drawingCallbacks.on_create_font(pFont)) { - free(pFont); - return NULL; - } - } - - return pFont; -} - -void dr2d_delete_font(dr2d_font* pFont) -{ - if (pFont == NULL) { - return; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->drawingCallbacks.on_delete_font != NULL) { - pFont->pContext->drawingCallbacks.on_delete_font(pFont); - } - - free(pFont); -} - -void* dr2d_get_font_extra_data(dr2d_font* pFont) -{ - if (pFont == NULL) { - return NULL; - } - - return pFont->pExtraData; -} - -unsigned int dr2d_get_font_size(dr2d_font* pFont) -{ - if (pFont == NULL) { - return 0; - } - - return pFont->size; -} - -bool dr2d_get_font_metrics(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut) -{ - if (pFont == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->drawingCallbacks.get_font_metrics != NULL) { - return pFont->pContext->drawingCallbacks.get_font_metrics(pFont, pMetricsOut); - } - - return false; -} - -bool dr2d_get_glyph_metrics(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pMetricsOut) -{ - if (pFont == NULL || pMetricsOut == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->drawingCallbacks.get_glyph_metrics != NULL) { - return pFont->pContext->drawingCallbacks.get_glyph_metrics(pFont, utf32, pMetricsOut); - } - - return false; -} - -bool dr2d_measure_string(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut) -{ - if (pFont == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->drawingCallbacks.measure_string != NULL) { - return pFont->pContext->drawingCallbacks.measure_string(pFont, text, textSizeInBytes, pWidthOut, pHeightOut); - } - - return false; -} - -bool dr2d_get_text_cursor_position_from_point(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut) -{ - if (pFont == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->drawingCallbacks.get_text_cursor_position_from_point) { - return pFont->pContext->drawingCallbacks.get_text_cursor_position_from_point(pFont, text, textSizeInBytes, maxWidth, inputPosX, pTextCursorPosXOut, pCharacterIndexOut); - } - - return false; -} - -bool dr2d_get_text_cursor_position_from_char(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut) -{ - if (pFont == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->drawingCallbacks.get_text_cursor_position_from_char) { - return pFont->pContext->drawingCallbacks.get_text_cursor_position_from_char(pFont, text, characterIndex, pTextCursorPosXOut); - } - - return false; -} - - -dr2d_image* dr2d_create_image(dr2d_context* pContext, unsigned int width, unsigned int height, dr2d_image_format format, unsigned int stride, const void* pData) -{ - if (pContext == NULL || width == 0 || height == 0) { - return NULL; - } - - dr2d_image* pImage = (dr2d_image*)malloc(sizeof(dr2d_image) + pContext->imageExtraBytes); - if (pImage == NULL) { - return NULL; - } - - pImage->pContext = pContext; - pImage->width = width; - pImage->height = height; - pImage->format = format; - pImage->isMapped = false; - - if (pContext->drawingCallbacks.on_create_image != NULL) { - if (!pContext->drawingCallbacks.on_create_image(pImage, stride, pData)) { - free(pImage); - return NULL; - } - } - - return pImage; -} - -void dr2d_delete_image(dr2d_image* pImage) -{ - if (pImage == NULL) { - return; - } - - assert(pImage->pContext != NULL); - - if (pImage->pContext->drawingCallbacks.on_delete_image != NULL) { - pImage->pContext->drawingCallbacks.on_delete_image(pImage); - } - - free(pImage); -} - -void* dr2d_get_image_extra_data(dr2d_image* pImage) -{ - if (pImage == NULL) { - return NULL; - } - - return pImage->pExtraData; -} - -void dr2d_get_image_size(dr2d_image* pImage, unsigned int* pWidthOut, unsigned int* pHeightOut) -{ - if (pImage == NULL) { - return; - } - - if (pWidthOut) { - *pWidthOut = pImage->width; - } - if (pHeightOut) { - *pHeightOut = pImage->height; - } -} - -void* dr2d_map_image_data(dr2d_image* pImage, unsigned int accessFlags) -{ - if (pImage == NULL || pImage->pContext->drawingCallbacks.map_image_data == NULL || pImage->pContext->drawingCallbacks.unmap_image_data == NULL || pImage->isMapped) { - return NULL; - } - - void* pImageData = pImage->pContext->drawingCallbacks.map_image_data(pImage, accessFlags); - if (pImageData != NULL) { - pImage->isMapped = true; - } - - return pImageData; -} - -void dr2d_unmap_image_data(dr2d_image* pImage) -{ - if (pImage == NULL || pImage->pContext->drawingCallbacks.unmap_image_data == NULL || !pImage->isMapped) { - return; - } - - pImage->pContext->drawingCallbacks.unmap_image_data(pImage); - pImage->isMapped = false; -} - -dr2d_image_format dr2d_get_optimal_image_format(dr2d_context* pContext) -{ - if (pContext == NULL || pContext->drawingCallbacks.get_optimal_image_format == NULL) { - return dr2d_image_format_rgba8; - } - - return pContext->drawingCallbacks.get_optimal_image_format(pContext); -} - - - -///////////////////////////////////////////////////////////////// -// -// UTILITY API -// -///////////////////////////////////////////////////////////////// - -dr2d_color dr2d_rgba(dr2d_byte r, dr2d_byte g, dr2d_byte b, dr2d_byte a) -{ - dr2d_color color; - color.r = r; - color.g = g; - color.b = b; - color.a = a; - - return color; -} - -dr2d_color dr2d_rgb(dr2d_byte r, dr2d_byte g, dr2d_byte b) -{ - dr2d_color color; - color.r = r; - color.g = g; - color.b = b; - color.a = 255; - - return color; -} - - - -///////////////////////////////////////////////////////////////// -// -// PRIVATE UTILITY API -// -///////////////////////////////////////////////////////////////// - -// RGBA8 <-> BGRA8 swap with alpha pre-multiply. -void dr2d__rgba8_bgra8_swap__premul(const void* pSrc, void* pDst, unsigned int width, unsigned int height, unsigned int srcStride, unsigned int dstStride) -{ - assert(pSrc != NULL); - assert(pDst != NULL); - - const unsigned int srcStride32 = srcStride/4; - const unsigned int dstStride32 = dstStride/4; - - const unsigned int* pSrcRow = (const unsigned int*)pSrc; - unsigned int* pDstRow = (unsigned int*)pDst; - - for (unsigned int iRow = 0; iRow < height; ++iRow) - { - for (unsigned int iCol = 0; iCol < width; ++iCol) - { - unsigned int srcTexel = pSrcRow[iCol]; - unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24; - unsigned int srcTexelB = (srcTexel & 0x00FF0000) >> 16; - unsigned int srcTexelG = (srcTexel & 0x0000FF00) >> 8; - unsigned int srcTexelR = (srcTexel & 0x000000FF) >> 0; - - srcTexelB = (unsigned int)(srcTexelB * (srcTexelA / 255.0f)); - srcTexelG = (unsigned int)(srcTexelG * (srcTexelA / 255.0f)); - srcTexelR = (unsigned int)(srcTexelR * (srcTexelA / 255.0f)); - - pDstRow[iCol] = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24); - } - - pSrcRow += srcStride32; - pDstRow += dstStride32; - } -} - - -///////////////////////////////////////////////////////////////// -// -// WINDOWS GDI 2D API -// -///////////////////////////////////////////////////////////////// -#ifndef DR2D_NO_GDI - -typedef struct -{ - /// The device context that owns every surface HBITMAP object. All drawing is done through this DC. - HDC hDC; - - /// The buffer used to store wchar strings when converting from char* to wchar_t* strings. We just use a global buffer for - /// this so we can avoid unnecessary allocations. - wchar_t* wcharBuffer; - - /// The size of wcharBuffer (including the null terminator). - unsigned int wcharBufferLength; - - /// The cache of glyph character positions. - int* pGlyphCache; - size_t glyphCacheSize; - - /// Whether or not the context owns the device context. - bool ownsDC; - -} gdi_context_data; - -typedef struct -{ - /// The window to draw to. The can be null, which is the case when creating the surface with dr2d_create_surface(). When this - /// is non-null the size of the surface is always tied to the window. - HWND hWnd; - - /// The HDC to use when drawing to the surface. - HDC hDC; - - /// The intermediate DC to use when drawing bitmaps. - HDC hIntermediateDC; - - /// The PAINTSTRUCT object that is filled by BeginPaint(). Only used when hWnd is non-null. - PAINTSTRUCT ps; - - /// The bitmap to render to. This is created with GDI's CreateDIBSection() API, using the DC above. This is only used - /// when hDC is NULL, which is the default. - HBITMAP hBitmap; - - /// A pointer to the raw bitmap data. This is allocated CreateDIBSection(). - void* pBitmapData; - - - /// The stock DC brush. - HGDIOBJ hStockDCBrush; - - /// The stock null brush. - HGDIOBJ hStockNullBrush; - - /// The stock DC pen. - HGDIOBJ hStockDCPen; - - /// The stock null pen. - HGDIOBJ hStockNullPen; - - - /// The pen that was active at the start of drawing. This is restored at the end of drawing. - HGDIOBJ hPrevPen; - - /// The brush that was active at the start of drawing. - HGDIOBJ hPrevBrush; - - /// The brush color at the start of drawing. - COLORREF prevBrushColor; - - /// The previous font. - HGDIOBJ hPrevFont; - - /// The previous text background mode. - int prevBkMode; - - /// The previous text background color. - COLORREF prevBkColor; - - -} gdi_surface_data; - -typedef struct -{ - /// A handle to the Win32 font. - HFONT hFont; - - /// The font metrics for faster retrieval. We cache the metrics when the font is loaded. - dr2d_font_metrics metrics; - -} gdi_font_data; - -typedef struct -{ - /// A handle to the primary bitmap object. - HBITMAP hSrcBitmap; - - /// A pointer to the raw bitmap data. - unsigned int* pSrcBitmapData; - - /// A handle to the secondary bitmap object that we use when we need to change the color values of - /// the primary bitmap before drawing. - HBITMAP hIntermediateBitmap; - - /// A pointer to the raw data of the intermediate bitmap. - unsigned int* pIntermediateBitmapData; - - - /// A pointer to the mapped data. This is null when the image data is not mapped. - void* pMappedImageData; - - /// The mapping flags. - unsigned int mapAccessFlags; - -} gdi_image_data; - - -bool dr2d_on_create_context_gdi(dr2d_context* pContext, const void* pUserData); -void dr2d_on_delete_context_gdi(dr2d_context* pContext); -bool dr2d_on_create_surface_gdi(dr2d_surface* pSurface, float width, float height); -void dr2d_on_delete_surface_gdi(dr2d_surface* pSurface); -bool dr2d_on_create_font_gdi(dr2d_font* pFont); -void dr2d_on_delete_font_gdi(dr2d_font* pFont); -bool dr2d_on_create_image_gdi(dr2d_image* pImage, unsigned int stride, const void* pData); -void dr2d_on_delete_image_gdi(dr2d_image* pImage); - -void dr2d_begin_draw_gdi(dr2d_surface* pSurface); -void dr2d_end_draw_gdi(dr2d_surface* pSurface); -void dr2d_clear_gdi(dr2d_surface* pSurface, dr2d_color color); -void dr2d_draw_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color); -void dr2d_draw_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth); -void dr2d_draw_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor); -void dr2d_draw_round_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius); -void dr2d_draw_round_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth); -void dr2d_draw_round_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor); -void dr2d_draw_text_gdi(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor); -void dr2d_draw_image_gdi(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs); -void dr2d_set_clip_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom); -void dr2d_get_clip_gdi(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut); - -dr2d_image_format dr2d_get_optimal_image_format_gdi(dr2d_context* pContext); -void* dr2d_map_image_data_gdi(dr2d_image* pImage, unsigned accessFlags); -void dr2d_unmap_image_data_gdi(dr2d_image* pImage); - -bool dr2d_get_font_metrics_gdi(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut); -bool dr2d_get_glyph_metrics_gdi(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics); -bool dr2d_measure_string_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut); -bool dr2d_get_text_cursor_position_from_point_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); -bool dr2d_get_text_cursor_position_from_char_gdi(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - -/// Converts a char* to a wchar_t* string. -wchar_t* dr2d_to_wchar_gdi(dr2d_context* pContext, const char* text, size_t textSizeInBytes, unsigned int* characterCountOut); - -/// Converts a UTF-32 character to a UTF-16. -static int dr2d_utf32_to_utf16(unsigned int utf32, unsigned short utf16[2]) -{ - if (utf16 == NULL) { - return 0; - } - - if (utf32 < 0xD800 || (utf32 >= 0xE000 && utf32 <= 0xFFFF)) - { - utf16[0] = (unsigned short)utf32; - utf16[1] = 0; - return 1; - } - else - { - if (utf32 >= 0x10000 && utf32 <= 0x10FFFF) - { - utf16[0] = (unsigned short)(0xD7C0 + (unsigned short)(utf32 >> 10)); - utf16[1] = (unsigned short)(0xDC00 + (unsigned short)(utf32 & 0x3FF)); - return 2; - } - else - { - // Invalid. - utf16[0] = 0; - utf16[0] = 0; - return 0; - } - } -} - -dr2d_context* dr2d_create_context_gdi(HDC hDC) -{ - dr2d_drawing_callbacks callbacks; - callbacks.on_create_context = dr2d_on_create_context_gdi; - callbacks.on_delete_context = dr2d_on_delete_context_gdi; - callbacks.on_create_surface = dr2d_on_create_surface_gdi; - callbacks.on_delete_surface = dr2d_on_delete_surface_gdi; - callbacks.on_create_font = dr2d_on_create_font_gdi; - callbacks.on_delete_font = dr2d_on_delete_font_gdi; - callbacks.on_create_image = dr2d_on_create_image_gdi; - callbacks.on_delete_image = dr2d_on_delete_image_gdi; - - callbacks.begin_draw = dr2d_begin_draw_gdi; - callbacks.end_draw = dr2d_end_draw_gdi; - callbacks.clear = dr2d_clear_gdi; - callbacks.draw_rect = dr2d_draw_rect_gdi; - callbacks.draw_rect_outline = dr2d_draw_rect_outline_gdi; - callbacks.draw_rect_with_outline = dr2d_draw_rect_with_outline_gdi; - callbacks.draw_round_rect = dr2d_draw_round_rect_gdi; - callbacks.draw_round_rect_outline = dr2d_draw_round_rect_outline_gdi; - callbacks.draw_round_rect_with_outline = dr2d_draw_round_rect_with_outline_gdi; - callbacks.draw_text = dr2d_draw_text_gdi; - callbacks.draw_image = dr2d_draw_image_gdi; - callbacks.set_clip = dr2d_set_clip_gdi; - callbacks.get_clip = dr2d_get_clip_gdi; - - callbacks.get_optimal_image_format = dr2d_get_optimal_image_format_gdi; - callbacks.map_image_data = dr2d_map_image_data_gdi; - callbacks.unmap_image_data = dr2d_unmap_image_data_gdi; - - callbacks.get_font_metrics = dr2d_get_font_metrics_gdi; - callbacks.get_glyph_metrics = dr2d_get_glyph_metrics_gdi; - callbacks.measure_string = dr2d_measure_string_gdi; - callbacks.get_text_cursor_position_from_point = dr2d_get_text_cursor_position_from_point_gdi; - callbacks.get_text_cursor_position_from_char = dr2d_get_text_cursor_position_from_char_gdi; - - return dr2d_create_context(callbacks, sizeof(gdi_context_data), sizeof(gdi_surface_data), sizeof(gdi_font_data), sizeof(gdi_image_data), &hDC); -} - -dr2d_surface* dr2d_create_surface_gdi_HWND(dr2d_context* pContext, HWND hWnd) -{ - dr2d_surface* pSurface = dr2d_create_surface(pContext, 0, 0); - if (pSurface != NULL) { - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) { - pGDIData->hWnd = hWnd; - } - } - - return pSurface; -} - -dr2d_surface* dr2d_create_surface_gdi_HDC(dr2d_context* pContext, HDC hDC) -{ - dr2d_surface* pSurface = dr2d_create_surface(pContext, 0, 0); - if (pSurface != NULL) { - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) { - pGDIData->hDC = hDC; - } - } - - return pSurface; -} - -HDC dr2d_get_HDC(dr2d_surface* pSurface) -{ - if (pSurface != NULL) { - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) { - return pGDIData->hDC; - } - } - - return NULL; -} - -HBITMAP dr2d_get_HBITMAP(dr2d_surface* pSurface) -{ - if (pSurface != NULL) { - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) { - return pGDIData->hBitmap; - } - } - - return NULL; -} - -HFONT dr2d_get_HFONT(dr2d_font* pFont) -{ - gdi_font_data* pGDIData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIData == NULL) { - return NULL; - } - - return pGDIData->hFont; -} - - -bool dr2d_on_create_context_gdi(dr2d_context* pContext, const void* pUserData) -{ - assert(pContext != NULL); - - HDC hDC = NULL; - if (pUserData != NULL) { - hDC = *(HDC*)pUserData; - } - - bool ownsDC = false; - if (hDC == NULL) { - hDC = CreateCompatibleDC(GetDC(GetDesktopWindow())); - ownsDC = true; - } - - - // We need to create the DC that all of our rendering commands will be drawn to. - gdi_context_data* pGDIData = (gdi_context_data*)dr2d_get_context_extra_data(pContext); - if (pGDIData == NULL) { - return false; - } - - pGDIData->hDC = hDC; - if (pGDIData->hDC == NULL) { - return false; - } - - pGDIData->ownsDC = ownsDC; - - - // We want to use the advanced graphics mode so that GetTextExtentPoint32() performs the conversions for font rotation for us. - SetGraphicsMode(pGDIData->hDC, GM_ADVANCED); - - - pGDIData->wcharBuffer = NULL; - pGDIData->wcharBufferLength = 0; - - pGDIData->pGlyphCache = NULL; - pGDIData->glyphCacheSize = 0; - - return true; -} - -void dr2d_on_delete_context_gdi(dr2d_context* pContext) -{ - assert(pContext != NULL); - - gdi_context_data* pGDIData = (gdi_context_data*)dr2d_get_context_extra_data(pContext); - if (pGDIData != NULL) - { - free(pGDIData->pGlyphCache); - pGDIData->glyphCacheSize = 0; - - free(pGDIData->wcharBuffer); - pGDIData->wcharBuffer = 0; - pGDIData->wcharBufferLength = 0; - - if (pGDIData->ownsDC) { - DeleteDC(pGDIData->hDC); - } - - pGDIData->hDC = NULL; - } -} - -bool dr2d_on_create_surface_gdi(dr2d_surface* pSurface, float width, float height) -{ - assert(pSurface != NULL); - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pSurface->pContext); - if (pGDIContextData == NULL) { - return false; - } - - gdi_surface_data* pGDISurfaceData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDISurfaceData == NULL) { - return false; - } - - HDC hDC = pGDIContextData->hDC; - if (hDC == NULL) { - return false; - } - - HDC hIntermediateDC = CreateCompatibleDC(hDC); - if (hIntermediateDC == NULL) { - return false; - } - - pGDISurfaceData->hIntermediateDC = hIntermediateDC; - pGDISurfaceData->hWnd = NULL; - - - if (width != 0 && height != 0) - { - pGDISurfaceData->hDC = hDC; - - BITMAPINFO bmi; - ZeroMemory(&bmi, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); - bmi.bmiHeader.biWidth = (LONG)width; - bmi.bmiHeader.biHeight = (LONG)height; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - pGDISurfaceData->hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pGDISurfaceData->pBitmapData, NULL, 0); - if (pGDISurfaceData->hBitmap == NULL) { - return false; - } - } - else - { - pGDISurfaceData->hBitmap = NULL; - pGDISurfaceData->hDC = NULL; - } - - - return true; -} - -void dr2d_on_delete_surface_gdi(dr2d_surface* pSurface) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - DeleteObject(pGDIData->hBitmap); - pGDIData->hBitmap = NULL; - - DeleteDC(pGDIData->hIntermediateDC); - pGDIData->hIntermediateDC = NULL; - } -} - -bool dr2d_on_create_font_gdi(dr2d_font* pFont) -{ - assert(pFont != NULL); - - gdi_font_data* pGDIData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIData == NULL) { - return false; - } - - - LONG weightGDI = FW_REGULAR; - switch (pFont->weight) - { - case dr2d_font_weight_medium: weightGDI = FW_MEDIUM; break; - case dr2d_font_weight_thin: weightGDI = FW_THIN; break; - case dr2d_font_weight_extra_light: weightGDI = FW_EXTRALIGHT; break; - case dr2d_font_weight_light: weightGDI = FW_LIGHT; break; - case dr2d_font_weight_semi_bold: weightGDI = FW_SEMIBOLD; break; - case dr2d_font_weight_bold: weightGDI = FW_BOLD; break; - case dr2d_font_weight_extra_bold: weightGDI = FW_EXTRABOLD; break; - case dr2d_font_weight_heavy: weightGDI = FW_HEAVY; break; - default: break; - } - - BYTE slantGDI = FALSE; - if (pFont->slant == dr2d_font_slant_italic || pFont->slant == dr2d_font_slant_oblique) { - slantGDI = TRUE; - } - - - LOGFONTA logfont; - memset(&logfont, 0, sizeof(logfont)); - - - - logfont.lfHeight = -(LONG)pFont->size; - logfont.lfWeight = weightGDI; - logfont.lfItalic = slantGDI; - logfont.lfCharSet = DEFAULT_CHARSET; - //logfont.lfQuality = (pFont->size > 36) ? ANTIALIASED_QUALITY : CLEARTYPE_QUALITY; - logfont.lfQuality = (pFont->flags & DR2D_FONT_NO_CLEARTYPE) ? ANTIALIASED_QUALITY : CLEARTYPE_QUALITY; - logfont.lfEscapement = (LONG)pFont->rotation * 10; - logfont.lfOrientation = (LONG)pFont->rotation * 10; - - size_t familyLength = strlen(pFont->family); - memcpy(logfont.lfFaceName, pFont->family, (familyLength < 31) ? familyLength : 31); - - - pGDIData->hFont = CreateFontIndirectA(&logfont); - if (pGDIData->hFont == NULL) { - return false; - } - - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext); - if (pGDIContextData == NULL) { - return false; - } - - // Cache the font metrics. - HGDIOBJ hPrevFont = SelectObject(pGDIContextData->hDC, pGDIData->hFont); - { - TEXTMETRIC metrics; - GetTextMetrics(pGDIContextData->hDC, &metrics); - - pGDIData->metrics.ascent = metrics.tmAscent; - pGDIData->metrics.descent = metrics.tmDescent; - pGDIData->metrics.lineHeight = metrics.tmHeight; - - - const MAT2 transform = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // <-- Identity matrix - - GLYPHMETRICS spaceMetrics; - DWORD bitmapBufferSize = GetGlyphOutlineW(pGDIContextData->hDC, ' ', GGO_NATIVE, &spaceMetrics, 0, NULL, &transform); - if (bitmapBufferSize == GDI_ERROR) { - pGDIData->metrics.spaceWidth = 4; - } else { - pGDIData->metrics.spaceWidth = spaceMetrics.gmCellIncX; - } - } - SelectObject(pGDIContextData->hDC, hPrevFont); - - - return true; -} - -void dr2d_on_delete_font_gdi(dr2d_font* pFont) -{ - assert(pFont != NULL); - - gdi_font_data* pGDIData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIData == NULL) { - return; - } - - DeleteObject(pGDIData->hFont); -} - -bool dr2d_on_create_image_gdi(dr2d_image* pImage, unsigned int stride, const void* pData) -{ - assert(pImage != NULL); - - gdi_image_data* pGDIData = (gdi_image_data*)dr2d_get_image_extra_data(pImage); - if (pGDIData == NULL) { - return false; - } - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pImage->pContext); - if (pGDIContextData == NULL) { - return false; - } - - - BITMAPINFO bmi; - ZeroMemory(&bmi, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); - bmi.bmiHeader.biWidth = pImage->width; - bmi.bmiHeader.biHeight = pImage->height; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; // Only supporting 32-bit formats. - bmi.bmiHeader.biCompression = BI_RGB; - pGDIData->hSrcBitmap = CreateDIBSection(pGDIContextData->hDC, &bmi, DIB_RGB_COLORS, (void**)&pGDIData->pSrcBitmapData, NULL, 0); - if (pGDIData->hSrcBitmap == NULL) { - return false; - } - - pGDIData->hIntermediateBitmap = CreateDIBSection(pGDIContextData->hDC, &bmi, DIB_RGB_COLORS, (void**)&pGDIData->pIntermediateBitmapData, NULL, 0); - if (pGDIData->hIntermediateBitmap == NULL) { - DeleteObject(pGDIData->hSrcBitmap); - return false; - } - - - // We need to convert the data so it renders correctly with AlphaBlend(). - if (pData != NULL) { - dr2d__rgba8_bgra8_swap__premul(pData, pGDIData->pSrcBitmapData, pImage->width, pImage->height, stride, pImage->width*4); - } - - // Flush GDI to let it know we are finished with the bitmap object's data. - GdiFlush(); - - - pGDIData->pMappedImageData = NULL; - pGDIData->mapAccessFlags = 0; - - // At this point everything should be good. - return true; -} - -void dr2d_on_delete_image_gdi(dr2d_image* pImage) -{ - assert(pImage != NULL); - - gdi_image_data* pGDIData = (gdi_image_data*)dr2d_get_image_extra_data(pImage); - if (pGDIData == NULL) { - return; - } - - DeleteObject(pGDIData->hSrcBitmap); - pGDIData->hSrcBitmap = NULL; - - DeleteObject(pGDIData->hIntermediateBitmap); - pGDIData->hIntermediateBitmap = NULL; -} - - -void dr2d_begin_draw_gdi(dr2d_surface* pSurface) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) { - if (pGDIData->hWnd != NULL) { - pGDIData->hDC = BeginPaint(pGDIData->hWnd, &pGDIData->ps); - } else { - SelectObject(dr2d_get_HDC(pSurface), pGDIData->hBitmap); - } - - HDC hDC = dr2d_get_HDC(pSurface); - - pGDIData->hStockDCBrush = GetStockObject(DC_BRUSH); - pGDIData->hStockNullBrush = GetStockObject(NULL_BRUSH); - pGDIData->hStockDCPen = GetStockObject(DC_PEN); - pGDIData->hStockNullPen = GetStockObject(NULL_PEN); - - // Retrieve the defaults so they can be restored later. - pGDIData->hPrevPen = GetCurrentObject(hDC, OBJ_PEN); - pGDIData->hPrevBrush = GetCurrentObject(hDC, OBJ_BRUSH); - pGDIData->prevBrushColor = GetDCBrushColor(hDC); - pGDIData->hPrevFont = GetCurrentObject(hDC, OBJ_FONT); - pGDIData->prevBkMode = GetBkMode(hDC); - pGDIData->prevBkColor = GetBkColor(hDC); - } -} - -void dr2d_end_draw_gdi(dr2d_surface* pSurface) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) { - HDC hDC = dr2d_get_HDC(pSurface); - - SelectClipRgn(hDC, NULL); - - SelectObject(hDC, pGDIData->hPrevPen); - SelectObject(hDC, pGDIData->hPrevBrush); - SetDCBrushColor(hDC, pGDIData->prevBrushColor); - SelectObject(hDC, pGDIData->hPrevFont); - SetBkMode(hDC, pGDIData->prevBkMode); - SetBkColor(hDC, pGDIData->prevBkColor); - - if (pGDIData->hWnd != NULL) { - EndPaint(pGDIData->hWnd, &pGDIData->ps); - } - } -} - -void dr2d_clear_gdi(dr2d_surface* pSurface, dr2d_color color) -{ - assert(pSurface != NULL); - - dr2d_draw_rect_gdi(pSurface, 0, 0, pSurface->width, pSurface->height, color); -} - -void dr2d_draw_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - SelectObject(hDC, pGDIData->hStockNullPen); - SelectObject(hDC, pGDIData->hStockDCBrush); - SetDCBrushColor(hDC, RGB(color.r, color.g, color.b)); - - // Now draw the rectangle. The documentation for this says that the width and height is 1 pixel less when the pen is null. Therefore we will - // increase the width and height by 1 since we have got the pen set to null. - Rectangle(hDC, (int)left, (int)top, (int)right + 1, (int)bottom + 1); - } -} - -void dr2d_draw_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - SelectObject(hDC, pGDIData->hStockNullPen); - SelectObject(hDC, pGDIData->hStockDCBrush); - SetDCBrushColor(hDC, RGB(color.r, color.g, color.b)); - - // Now draw the rectangle. The documentation for this says that the width and height is 1 pixel less when the pen is null. Therefore we will - // increase the width and height by 1 since we have got the pen set to null. - - Rectangle(hDC, (int)left, (int)top, (int)(left + outlineWidth + 1), (int)(bottom + 1)); // Left. - Rectangle(hDC, (int)(right - outlineWidth), (int)top, (int)(right + 1), (int)(bottom + 1)); // Right. - Rectangle(hDC, (int)(left + outlineWidth), (int)top, (int)(right - outlineWidth + 1), (int)(top + outlineWidth + 1)); // Top - Rectangle(hDC, (int)(left + outlineWidth), (int)(bottom - outlineWidth), (int)(right - outlineWidth + 1), (int)(bottom + 1)); // Bottom - } -} - -void dr2d_draw_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (int)outlineWidth, RGB(outlineColor.r, outlineColor.g, outlineColor.b)); - if (hPen != NULL) - { - SelectObject(hDC, hPen); - SelectObject(hDC, pGDIData->hStockDCBrush); - SetDCBrushColor(hDC, RGB(color.r, color.g, color.b)); - - Rectangle(hDC, (int)left, (int)top, (int)right, (int)bottom); - - DeleteObject(hPen); - } - } -} - -void dr2d_draw_round_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - SelectObject(hDC, pGDIData->hStockNullPen); - SelectObject(hDC, pGDIData->hStockDCBrush); - SetDCBrushColor(hDC, RGB(color.r, color.g, color.b)); - - RoundRect(hDC, (int)left, (int)top, (int)right + 1, (int)bottom + 1, (int)(radius*2), (int)(radius*2)); - } -} - -void dr2d_draw_round_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (int)outlineWidth, RGB(color.r, color.g, color.b)); - if (hPen != NULL) - { - SelectObject(hDC, pGDIData->hStockNullBrush); - SelectObject(hDC, hPen); - - RoundRect(hDC, (int)left, (int)top, (int)right, (int)bottom, (int)(radius*2), (int)(radius*2)); - - DeleteObject(hPen); - } - } -} - -void dr2d_draw_round_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (int)outlineWidth, RGB(outlineColor.r, outlineColor.g, outlineColor.b)); - if (hPen != NULL) - { - SelectObject(hDC, hPen); - SelectObject(hDC, pGDIData->hStockDCBrush); - SetDCBrushColor(hDC, RGB(color.r, color.g, color.b)); - - RoundRect(hDC, (int)left, (int)top, (int)right, (int)bottom, (int)(radius*2), (int)(radius*2)); - - DeleteObject(hPen); - } - } -} - -void dr2d_draw_text_gdi(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor) -{ - gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIFontData == NULL) { - return; - } - - - HDC hDC = dr2d_get_HDC(pSurface); - - HFONT hFontGDI = pGDIFontData->hFont; - if (hFontGDI != NULL) - { - // We actually want to use the W version of TextOut because otherwise unicode doesn't work properly. - - unsigned int textWLength; - wchar_t* textW = dr2d_to_wchar_gdi(pSurface->pContext, text, textSizeInBytes, &textWLength); - if (textW != NULL) - { - SelectObject(hDC, hFontGDI); - - UINT options = 0; - RECT rect = {0, 0, 0, 0}; - - if (backgroundColor.a == 0) { - SetBkMode(hDC, TRANSPARENT); - } else { - SetBkMode(hDC, OPAQUE); - SetBkColor(hDC, RGB(backgroundColor.r, backgroundColor.g, backgroundColor.b)); - - // There is an issue with the way GDI draws the background of a string of text. When ClearType is enabled, the rectangle appears - // to be wider than it is supposed to be. As a result, drawing text right next to each other results in the most recent one being - // drawn slightly on top of the previous one. To fix this we need to use ExtTextOut() with the ETO_CLIPPED parameter enabled. - options |= ETO_CLIPPED; - - SIZE textSize = {0, 0}; - GetTextExtentPoint32W(hDC, textW, textWLength, &textSize); - rect.left = (LONG)posX; - rect.top = (LONG)posY; - rect.right = (LONG)(posX + textSize.cx); - rect.bottom = (LONG)(posY + textSize.cy); - } - - SetTextColor(hDC, RGB(color.r, color.g, color.b)); - - ExtTextOutW(hDC, (int)posX, (int)posY, options, &rect, textW, textWLength, NULL); - } - } -} - -void dr2d_draw_image_gdi(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs) -{ - gdi_image_data* pGDIImageData = (gdi_image_data*)dr2d_get_image_extra_data(pImage); - if (pGDIImageData == NULL) { - return; - } - - gdi_surface_data* pGDISurfaceData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDISurfaceData == NULL) { - return; - } - - bool drawFlipped = false; - HBITMAP hSrcBitmap = NULL; - - if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) == 0 && (pArgs->options & DR2D_IMAGE_HINT_NO_ALPHA) != 0 && pArgs->foregroundTint.r == 255 && pArgs->foregroundTint.g == 255 && pArgs->foregroundTint.b == 255) - { - // Fast path. No tint, no background, no alpha. - hSrcBitmap = pGDIImageData->hSrcBitmap; - drawFlipped = true; - } - else - { - // Slow path. We need to manually change the color values of the intermediate bitmap and use that as the source when drawing it. This is also flipped. - unsigned int* pSrcBitmapData = pGDIImageData->pSrcBitmapData; - unsigned int* pDstBitmapData = pGDIImageData->pIntermediateBitmapData; - for (unsigned int iRow = 0; iRow < pImage->height; ++iRow) - { - for (unsigned int iCol = 0; iCol < pImage->width; ++iCol) - { - unsigned int srcTexel = *(pSrcBitmapData + (iRow * pImage->width) + iCol); - unsigned int* dstTexel = (pDstBitmapData + ((pImage->height - iRow - 1) * pImage->width) + iCol); - - unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24; - unsigned int srcTexelR = (unsigned int)(((srcTexel & 0x00FF0000) >> 16) * (pArgs->foregroundTint.r / 255.0f)); - unsigned int srcTexelG = (unsigned int)(((srcTexel & 0x0000FF00) >> 8) * (pArgs->foregroundTint.g / 255.0f)); - unsigned int srcTexelB = (unsigned int)(((srcTexel & 0x000000FF) >> 0) * (pArgs->foregroundTint.b / 255.0f)); - - if (srcTexelR > 255) srcTexelR = 255; - if (srcTexelG > 255) srcTexelG = 255; - if (srcTexelB > 255) srcTexelB = 255; - - if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) != 0) - { - srcTexelB += (unsigned int)(pArgs->backgroundColor.b * ((255 - srcTexelA) / 255.0f)); - srcTexelG += (unsigned int)(pArgs->backgroundColor.g * ((255 - srcTexelA) / 255.0f)); - srcTexelR += (unsigned int)(pArgs->backgroundColor.r * ((255 - srcTexelA) / 255.0f)); - srcTexelA = 0xFF; - } - - *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24); - } - } - - // Flush GDI to let it know we are finished with the bitmap object's data. - GdiFlush(); - - // If we have drawn the background manually we don't need to do an alpha blend. - if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) != 0) { - pArgs->options |= DR2D_IMAGE_HINT_NO_ALPHA; - } - - hSrcBitmap = pGDIImageData->hIntermediateBitmap; - } - - HGDIOBJ hPrevBitmap = SelectObject(pGDISurfaceData->hIntermediateDC, hSrcBitmap); - if ((pArgs->options & DR2D_IMAGE_HINT_NO_ALPHA) != 0) - { - if (drawFlipped) { - StretchBlt(pGDISurfaceData->hDC, (int)pArgs->dstX, (int)pArgs->dstY + (int)pArgs->dstHeight - 1, (int)pArgs->dstWidth, -(int)pArgs->dstHeight, pGDISurfaceData->hIntermediateDC, (int)pArgs->srcX, (int)pArgs->srcY, (int)pArgs->srcWidth, (int)pArgs->srcHeight, SRCCOPY); - } else { - StretchBlt(pGDISurfaceData->hDC, (int)pArgs->dstX, (int)pArgs->dstY, (int)pArgs->dstWidth, (int)pArgs->dstHeight, pGDISurfaceData->hIntermediateDC, (int)pArgs->srcX, (int)pArgs->srcY, (int)pArgs->srcWidth, (int)pArgs->srcHeight, SRCCOPY); - } - } - else - { - assert(drawFlipped == false); // <-- Error if this is hit. - BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - AlphaBlend(pGDISurfaceData->hDC, (int)pArgs->dstX, (int)pArgs->dstY, (int)pArgs->dstWidth, (int)pArgs->dstHeight, pGDISurfaceData->hIntermediateDC, (int)pArgs->srcX, (int)pArgs->srcY, (int)pArgs->srcWidth, (int)pArgs->srcHeight, blend); - } - SelectObject(pGDISurfaceData->hIntermediateDC, hPrevBitmap); -} - -void dr2d_set_clip_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - HDC hDC = dr2d_get_HDC(pSurface); - - SelectClipRgn(hDC, NULL); - IntersectClipRect(hDC, (int)left, (int)top, (int)right, (int)bottom); - } -} - -void dr2d_get_clip_gdi(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut) -{ - assert(pSurface != NULL); - - gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pGDIData != NULL) - { - RECT rect; - GetClipBox(dr2d_get_HDC(pSurface), &rect); - - if (pLeftOut != NULL) { - *pLeftOut = (float)rect.left; - } - if (pTopOut != NULL) { - *pTopOut = (float)rect.top; - } - if (pRightOut != NULL) { - *pRightOut = (float)rect.right; - } - if (pBottomOut != NULL) { - *pBottomOut = (float)rect.bottom; - } - } -} - - -dr2d_image_format dr2d_get_optimal_image_format_gdi(dr2d_context* pContext) -{ - (void)pContext; - return dr2d_image_format_bgra8; -} - -void* dr2d_map_image_data_gdi(dr2d_image* pImage, unsigned accessFlags) -{ - assert(pImage != NULL); - - gdi_image_data* pGDIImageData = (gdi_image_data*)dr2d_get_image_extra_data(pImage); - if (pGDIImageData == NULL) { - return NULL; - } - - assert(pGDIImageData->pMappedImageData == NULL); // This function should never be called while the image is already mapped. - - pGDIImageData->mapAccessFlags = accessFlags; - - if (pImage->format == dr2d_image_format_bgra8) - { - pGDIImageData->pMappedImageData = pGDIImageData->pSrcBitmapData; - } - else - { - pGDIImageData->pMappedImageData = malloc(pImage->width * pImage->height * 4); - if (pGDIImageData->pMappedImageData == NULL) { - return NULL; - } - - for (unsigned int iRow = 0; iRow < pImage->height; ++iRow) - { - const unsigned int iRowSrc = pImage->height - (iRow + 1); - const unsigned int iRowDst = iRow; - - for (unsigned int iCol = 0; iCol < pImage->width; ++iCol) - { - unsigned int srcTexel = ((const unsigned int*)(pGDIImageData->pSrcBitmapData))[ (iRowSrc * pImage->width) + iCol]; - unsigned int* dstTexel = (( unsigned int*)(pGDIImageData->pMappedImageData)) + (iRowDst * pImage->width) + iCol; - - unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24; - unsigned int srcTexelB = (srcTexel & 0x00FF0000) >> 16; - unsigned int srcTexelG = (srcTexel & 0x0000FF00) >> 8; - unsigned int srcTexelR = (srcTexel & 0x000000FF) >> 0; - - srcTexelB = (unsigned int)(srcTexelB * (srcTexelA / 255.0f)); - srcTexelG = (unsigned int)(srcTexelG * (srcTexelA / 255.0f)); - srcTexelR = (unsigned int)(srcTexelR * (srcTexelA / 255.0f)); - - *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24); - } - } - } - - return pGDIImageData->pMappedImageData; -} - -void dr2d_unmap_image_data_gdi(dr2d_image* pImage) -{ - assert(pImage != NULL); - - gdi_image_data* pGDIImageData = (gdi_image_data*)dr2d_get_image_extra_data(pImage); - if (pGDIImageData == NULL) { - return; - } - - assert(pGDIImageData->pMappedImageData != NULL); // This function should never be called while the image is not mapped. - - if (pImage->format == dr2d_image_format_bgra8) - { - // It's in the native format, so just do a flush. - GdiFlush(); - } - else - { - // Update the actual image data if applicable. - if (pGDIImageData->mapAccessFlags & DR2D_WRITE) { - dr2d__rgba8_bgra8_swap__premul(pGDIImageData->pMappedImageData, pGDIImageData->pSrcBitmapData, pImage->width, pImage->height, pImage->width*4, pImage->width*4); - } - - free(pGDIImageData->pMappedImageData); - } - - pGDIImageData->pMappedImageData = NULL; - pGDIImageData->mapAccessFlags = 0; -} - - -bool dr2d_get_font_metrics_gdi(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut) -{ - assert(pFont != NULL); - assert(pMetricsOut != NULL); - - gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIFontData == NULL) { - return false; - } - - *pMetricsOut = pGDIFontData->metrics; - return true; -} - -bool dr2d_get_glyph_metrics_gdi(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics) -{ - assert(pFont != NULL); - assert(pGlyphMetrics != NULL); - - gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIFontData == NULL) { - return false; - } - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext); - if (pGDIContextData == NULL) { - return false; - } - - - SelectObject(pGDIContextData->hDC, pGDIFontData->hFont); - - - const MAT2 transform = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // <-- Identity matrix - - unsigned short utf16[2]; - int utf16Len = dr2d_utf32_to_utf16(utf32, utf16); - - WCHAR glyphIndices[2]; - - GCP_RESULTSW glyphResults; - ZeroMemory(&glyphResults, sizeof(glyphResults)); - glyphResults.lStructSize = sizeof(glyphResults); - glyphResults.lpGlyphs = glyphIndices; - glyphResults.nGlyphs = 2; - if (GetCharacterPlacementW(pGDIContextData->hDC, (LPCWSTR)utf16, utf16Len, 0, &glyphResults, 0) != 0) - { - GLYPHMETRICS metrics; - DWORD bitmapBufferSize = GetGlyphOutlineW(pGDIContextData->hDC, glyphIndices[0], GGO_NATIVE | GGO_GLYPH_INDEX, &metrics, 0, NULL, &transform); - if (bitmapBufferSize != GDI_ERROR) - { - pGlyphMetrics->width = metrics.gmBlackBoxX; - pGlyphMetrics->height = metrics.gmBlackBoxY; - pGlyphMetrics->originX = metrics.gmptGlyphOrigin.x; - pGlyphMetrics->originY = metrics.gmptGlyphOrigin.y; - pGlyphMetrics->advanceX = metrics.gmCellIncX; - pGlyphMetrics->advanceY = metrics.gmCellIncY; - - return true; - } - } - - return false; -} - -bool dr2d_measure_string_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut) -{ - assert(pFont != NULL); - - gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIFontData == NULL) { - return false; - } - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext); - if (pGDIContextData == NULL) { - return false; - } - - - SelectObject(pGDIContextData->hDC, pGDIFontData->hFont); - - unsigned int textWLength; - wchar_t* textW = dr2d_to_wchar_gdi(pFont->pContext, text, textSizeInBytes, &textWLength); - if (textW != NULL) - { - SIZE sizeWin32; - if (GetTextExtentPoint32W(pGDIContextData->hDC, textW, textWLength, &sizeWin32)) - { - if (pWidthOut != NULL) { - *pWidthOut = (float)sizeWin32.cx; - } - if (pHeightOut != NULL) { - *pHeightOut = (float)sizeWin32.cy; - } - - return true; - } - } - - return false; -} - -bool dr2d_get_text_cursor_position_from_point_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut) -{ - bool successful = false; - - assert(pFont != NULL); - - gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIFontData == NULL) { - return false; - } - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext); - if (pGDIContextData == NULL) { - return false; - } - - - SelectObject(pGDIContextData->hDC, pGDIFontData->hFont); - - - GCP_RESULTSW results; - ZeroMemory(&results, sizeof(results)); - results.lStructSize = sizeof(results); - results.nGlyphs = (UINT)textSizeInBytes; - - unsigned int textWLength; - wchar_t* textW = dr2d_to_wchar_gdi(pFont->pContext, text, textSizeInBytes, &textWLength); - if (textW != NULL) - { - if (results.nGlyphs > pGDIContextData->glyphCacheSize) { - free(pGDIContextData->pGlyphCache); - pGDIContextData->pGlyphCache = (int*)malloc(sizeof(int) * results.nGlyphs); - pGDIContextData->glyphCacheSize = results.nGlyphs; - } - - results.lpCaretPos = pGDIContextData->pGlyphCache; - if (results.lpCaretPos != NULL) - { - if (GetCharacterPlacementW(pGDIContextData->hDC, textW, results.nGlyphs, (int)maxWidth, &results, GCP_MAXEXTENT | GCP_USEKERNING) != 0) - { - float textCursorPosX = 0; - unsigned int iChar; - for (iChar = 0; iChar < results.nGlyphs; ++iChar) - { - float charBoundsLeft = charBoundsLeft = (float)results.lpCaretPos[iChar]; - float charBoundsRight = 0; - if (iChar < results.nGlyphs - 1) { - charBoundsRight = (float)results.lpCaretPos[iChar + 1]; - } else { - charBoundsRight = maxWidth; - } - - if (inputPosX >= charBoundsLeft && inputPosX <= charBoundsRight) - { - // The input position is somewhere on top of this character. If it's positioned on the left side of the character, set the output - // value to the character at iChar. Otherwise it should be set to the character at iChar + 1. - float charBoundsRightHalf = charBoundsLeft + ceilf(((charBoundsRight - charBoundsLeft) / 2.0f)); - if (inputPosX <= charBoundsRightHalf) { - break; - } else { - textCursorPosX = charBoundsRight; - iChar += 1; - break; - } - } - - textCursorPosX = charBoundsRight; - } - - if (pTextCursorPosXOut) { - *pTextCursorPosXOut = textCursorPosX; - } - if (pCharacterIndexOut) { - *pCharacterIndexOut = iChar; - } - - successful = true; - } - } - } - - return successful; -} - -bool dr2d_get_text_cursor_position_from_char_gdi(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut) -{ - bool successful = false; - - assert(pFont != NULL); - - gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont); - if (pGDIFontData == NULL) { - return false; - } - - gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext); - if (pGDIContextData == NULL) { - return false; - } - - - SelectObject(pGDIContextData->hDC, pGDIFontData->hFont); - - - GCP_RESULTSW results; - ZeroMemory(&results, sizeof(results)); - results.lStructSize = sizeof(results); - results.nGlyphs = (DWORD)(characterIndex + 1); - - unsigned int textWLength; - wchar_t* textW = dr2d_to_wchar_gdi(pFont->pContext, text, (int)results.nGlyphs, &textWLength); - if (textW != NULL) - { - if (results.nGlyphs > pGDIContextData->glyphCacheSize) { - free(pGDIContextData->pGlyphCache); - pGDIContextData->pGlyphCache = (int*)malloc(sizeof(int) * results.nGlyphs); - pGDIContextData->glyphCacheSize = results.nGlyphs; - } - - results.lpCaretPos = pGDIContextData->pGlyphCache; - if (results.lpCaretPos != NULL) - { - if (GetCharacterPlacementW(pGDIContextData->hDC, textW, results.nGlyphs, 0, &results, GCP_USEKERNING) != 0) - { - if (pTextCursorPosXOut) { - *pTextCursorPosXOut = (float)results.lpCaretPos[characterIndex]; - } - - successful = true; - } - } - } - - return successful; -} - - -wchar_t* dr2d_to_wchar_gdi(dr2d_context* pContext, const char* text, size_t textSizeInBytes, unsigned int* characterCountOut) -{ - if (pContext == NULL || text == NULL) { - return NULL; - } - - gdi_context_data* pGDIData = (gdi_context_data*)dr2d_get_context_extra_data(pContext); - if (pGDIData == NULL) { - return NULL; - } - - int wcharCount = 0; - - - // We first try to copy the string into the already-allocated buffer. If it fails we fall back to the slow path which requires - // two conversions. - if (pGDIData->wcharBuffer == NULL) { - goto fallback; - } - - wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (int)textSizeInBytes, pGDIData->wcharBuffer, pGDIData->wcharBufferLength); - if (wcharCount != 0) { - if (characterCountOut) *characterCountOut = wcharCount; - return pGDIData->wcharBuffer; - } - - - -fallback:; - wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (int)textSizeInBytes, NULL, 0); - if (wcharCount == 0) { - return NULL; - } - - if (pGDIData->wcharBufferLength < (unsigned int)wcharCount + 1) { - free(pGDIData->wcharBuffer); - pGDIData->wcharBuffer = (wchar_t*)malloc(sizeof(wchar_t) * (wcharCount + 1)); - pGDIData->wcharBufferLength = wcharCount + 1; - } - - wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (int)textSizeInBytes, pGDIData->wcharBuffer, pGDIData->wcharBufferLength); - if (wcharCount == 0) { - return NULL; - } - - - if (characterCountOut != NULL) { - *characterCountOut = wcharCount; - } - - return pGDIData->wcharBuffer; -} - -#endif // GDI - - -///////////////////////////////////////////////////////////////// -// -// CAIRO 2D API -// -///////////////////////////////////////////////////////////////// -#ifndef DR2D_NO_CAIRO - -typedef struct -{ - cairo_surface_t* pCairoSurface; - cairo_t* pCairoContext; - - float clipRectLeft; - float clipRectTop; - float clipRectRight; - float clipRectBottom; - -} cairo_surface_data; - -typedef struct -{ - cairo_font_face_t* pFace; - cairo_scaled_font_t* pFont; - - // The font metrics. This is initialized when the font is created. - dr2d_font_metrics metrics; - -} cairo_font_data; - -typedef struct -{ - /// Images in Cairo are implemented as surfaces. - cairo_surface_t* pCairoSurface; - - /// A pointer to the raw data. - unsigned char* pData; - -} cairo_image_data; - -bool dr2d_on_create_context_cairo(dr2d_context* pContext, const void* pUserData); -void dr2d_on_delete_context_cairo(dr2d_context* pContext); -bool dr2d_on_create_surface_cairo(dr2d_surface* pSurface, float width, float height); -void dr2d_on_delete_surface_cairo(dr2d_surface* pSurface); -bool dr2d_on_create_font_cairo(dr2d_font* pFont); -void dr2d_on_delete_font_cairo(dr2d_font* pFont); -bool dr2d_on_create_image_cairo(dr2d_image* pImage, unsigned int stride, const void* pData); -void dr2d_on_delete_image_cairo(dr2d_image* pImage); - -void dr2d_begin_draw_cairo(dr2d_surface* pSurface); -void dr2d_end_draw_cairo(dr2d_surface* pSurface); -void dr2d_clear_cairo(dr2d_surface* pSurface, dr2d_color color); -void dr2d_draw_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color); -void dr2d_draw_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth); -void dr2d_draw_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor); -void dr2d_draw_round_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius); -void dr2d_draw_round_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth); -void dr2d_draw_round_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor); -void dr2d_draw_text_cairo(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor); -void dr2d_draw_image_cairo(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs); -void dr2d_set_clip_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom); -void dr2d_get_clip_cairo(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut); - -dr2d_image_format dr2d_get_optimal_image_format_cairo(dr2d_context* pContext); -void* dr2d_map_image_data_cairo(dr2d_image* pImage, unsigned accessFlags); -void dr2d_unmap_image_data_cairo(dr2d_image* pImage); - -bool dr2d_get_font_metrics_cairo(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut); -bool dr2d_get_glyph_metrics_cairo(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics); -bool dr2d_measure_string_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut); -bool dr2d_get_text_cursor_position_from_point_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); -bool dr2d_get_text_cursor_position_from_char_cairo(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - - -dr2d_context* dr2d_create_context_cairo() -{ - dr2d_drawing_callbacks callbacks; - callbacks.on_create_context = dr2d_on_create_context_cairo; - callbacks.on_delete_context = dr2d_on_delete_context_cairo; - callbacks.on_create_surface = dr2d_on_create_surface_cairo; - callbacks.on_delete_surface = dr2d_on_delete_surface_cairo; - callbacks.on_create_font = dr2d_on_create_font_cairo; - callbacks.on_delete_font = dr2d_on_delete_font_cairo; - callbacks.on_create_image = dr2d_on_create_image_cairo; - callbacks.on_delete_image = dr2d_on_delete_image_cairo; - - callbacks.begin_draw = dr2d_begin_draw_cairo; - callbacks.end_draw = dr2d_end_draw_cairo; - callbacks.clear = dr2d_clear_cairo; - callbacks.draw_rect = dr2d_draw_rect_cairo; - callbacks.draw_rect_outline = dr2d_draw_rect_outline_cairo; - callbacks.draw_rect_with_outline = dr2d_draw_rect_with_outline_cairo; - callbacks.draw_round_rect = dr2d_draw_round_rect_cairo; - callbacks.draw_round_rect_outline = dr2d_draw_round_rect_outline_cairo; - callbacks.draw_round_rect_with_outline = dr2d_draw_round_rect_with_outline_cairo; - callbacks.draw_text = dr2d_draw_text_cairo; - callbacks.draw_image = dr2d_draw_image_cairo; - callbacks.set_clip = dr2d_set_clip_cairo; - callbacks.get_clip = dr2d_get_clip_cairo; - - callbacks.map_image_data = dr2d_map_image_data_cairo; - callbacks.unmap_image_data = dr2d_unmap_image_data_cairo; - - callbacks.get_font_metrics = dr2d_get_font_metrics_cairo; - callbacks.get_glyph_metrics = dr2d_get_glyph_metrics_cairo; - callbacks.measure_string = dr2d_measure_string_cairo; - callbacks.get_text_cursor_position_from_point = dr2d_get_text_cursor_position_from_point_cairo; - callbacks.get_text_cursor_position_from_char = dr2d_get_text_cursor_position_from_char_cairo; - - - return dr2d_create_context(callbacks, 0, sizeof(cairo_surface_data), sizeof(cairo_font_data), sizeof(cairo_image_data), NULL); -} - -dr2d_surface* dr2d_create_surface_cairo(dr2d_context* pContext, cairo_t* cr) -{ - if (cr == NULL) { - return NULL; - } - - dr2d_surface* pSurface = dr2d_create_surface(pContext, 0, 0); - if (pSurface != NULL) { - cairo_surface_data* pCairoData = (cairo_surface_data*)dr2d_get_surface_extra_data(pSurface); - if (pCairoData != NULL) { - pCairoData->pCairoContext = cairo_reference(cr); - pCairoData->pCairoSurface = cairo_surface_reference(cairo_get_target(cr)); - } - } - - return pSurface; -} - -cairo_surface_t* dr2d_get_cairo_surface_t(dr2d_surface* pSurface) -{ - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData != NULL) { - return pCairoData->pCairoSurface; - } - - return NULL; -} - -cairo_t* dr2d_get_cairo_t(dr2d_surface* pSurface) -{ - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData != NULL) { - return pCairoData->pCairoContext; - } - - return NULL; -} - - -bool dr2d_on_create_context_cairo(dr2d_context* pContext, const void* pUserData) -{ - assert(pContext != NULL); - (void)pContext; - (void)pUserData; - - return true; -} - -void dr2d_on_delete_context_cairo(dr2d_context* pContext) -{ - assert(pContext != NULL); - (void)pContext; -} - -bool dr2d_on_create_surface_cairo(dr2d_surface* pSurface, float width, float height) -{ - assert(pSurface != NULL); - - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData == NULL) { - return false; - } - - if (width != 0 && height != 0) { - pCairoData->pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)width, (int)height); - if (pCairoData->pCairoSurface == NULL) { - return false; - } - - pCairoData->pCairoContext = cairo_create(pCairoData->pCairoSurface); - if (pCairoData->pCairoContext == NULL) { - cairo_surface_destroy(pCairoData->pCairoSurface); - return false; - } - } else { - pCairoData->pCairoSurface = NULL; - pCairoData->pCairoContext = NULL; - } - - - return true; -} - -void dr2d_on_delete_surface_cairo(dr2d_surface* pSurface) -{ - assert(pSurface != NULL); - - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData != NULL) - { - cairo_destroy(pCairoData->pCairoContext); - cairo_surface_destroy(pCairoData->pCairoSurface); - } -} - -bool dr2d_on_create_font_cairo(dr2d_font* pFont) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return false; - } - - cairo_font_slant_t cairoSlant = CAIRO_FONT_SLANT_NORMAL; - if (pFont->slant == dr2d_font_slant_italic) { - cairoSlant = CAIRO_FONT_SLANT_ITALIC; - } else if (pFont->slant == dr2d_font_slant_oblique) { - cairoSlant = CAIRO_FONT_SLANT_OBLIQUE; - } - - cairo_font_weight_t cairoWeight = CAIRO_FONT_WEIGHT_NORMAL; - if (pFont->weight == dr2d_font_weight_bold || pFont->weight == dr2d_font_weight_semi_bold || pFont->weight == dr2d_font_weight_extra_bold || pFont->weight == dr2d_font_weight_heavy) { - cairoWeight = CAIRO_FONT_WEIGHT_BOLD; - } - - pCairoFont->pFace = cairo_toy_font_face_create(pFont->family, cairoSlant, cairoWeight); - if (pCairoFont->pFace == NULL) { - return false; - } - - cairo_matrix_t fontMatrix; - cairo_matrix_init_scale(&fontMatrix, (double)pFont->size, (double)pFont->size); - cairo_matrix_rotate(&fontMatrix, pFont->rotation * (3.14159265 / 180.0)); - - cairo_matrix_t ctm; - cairo_matrix_init_identity(&ctm); - - cairo_font_options_t* options = cairo_font_options_create(); - cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL); // TODO: Control this with option flags in pFont. - - pCairoFont->pFont = cairo_scaled_font_create(pCairoFont->pFace, &fontMatrix, &ctm, options); - if (pCairoFont->pFont == NULL) { - cairo_font_face_destroy(pCairoFont->pFace); - return false; - } - - - // Metrics. - cairo_font_extents_t fontMetrics; - cairo_scaled_font_extents(pCairoFont->pFont, &fontMetrics); - - pCairoFont->metrics.ascent = fontMetrics.ascent; - pCairoFont->metrics.descent = fontMetrics.descent; - //pCairoFont->metrics.lineHeight = fontMetrics.height; - pCairoFont->metrics.lineHeight = fontMetrics.ascent + fontMetrics.descent; - - // The width of a space needs to be retrieved via glyph metrics. - const char space[] = " "; - cairo_text_extents_t spaceMetrics; - cairo_scaled_font_text_extents(pCairoFont->pFont, space, &spaceMetrics); - pCairoFont->metrics.spaceWidth = spaceMetrics.x_advance; - - return true; -} - -void dr2d_on_delete_font_cairo(dr2d_font* pFont) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return; - } - - cairo_scaled_font_destroy(pCairoFont->pFont); - cairo_font_face_destroy(pCairoFont->pFace); -} - -bool dr2d_on_create_image_cairo(dr2d_image* pImage, unsigned int stride, const void* pData) -{ - cairo_image_data* pCairoImage = dr2d_get_image_extra_data(pImage); - if (pCairoImage == NULL) { - return false; - } - - size_t dataSize = pImage->height * pImage->width * 4; - pCairoImage->pData = malloc(dataSize); - if (pCairoImage->pData == NULL) { - return false; - } - - if (pData != NULL) - { - for (unsigned int iRow = 0; iRow < pImage->height; ++iRow) - { - const unsigned int iRowSrc = iRow; //pImage->height - (iRow + 1); - const unsigned int iRowDst = iRow; - - for (unsigned int iCol = 0; iCol < pImage->width; ++iCol) - { - unsigned int srcTexel = ((const unsigned int*)(pData ))[ (iRowSrc * (stride/4)) + iCol]; - unsigned int* dstTexel = (( unsigned int*)(pCairoImage->pData)) + (iRowDst * pImage->width) + iCol; - - unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24; - unsigned int srcTexelB = (srcTexel & 0x00FF0000) >> 16; - unsigned int srcTexelG = (srcTexel & 0x0000FF00) >> 8; - unsigned int srcTexelR = (srcTexel & 0x000000FF) >> 0; - - srcTexelB = (unsigned int)(srcTexelB * (srcTexelA / 255.0f)); - srcTexelG = (unsigned int)(srcTexelG * (srcTexelA / 255.0f)); - srcTexelR = (unsigned int)(srcTexelR * (srcTexelA / 255.0f)); - - *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24); - } - } - } - - pCairoImage->pCairoSurface = cairo_image_surface_create_for_data(pCairoImage->pData, CAIRO_FORMAT_ARGB32, (int)pImage->width, (int)pImage->height, (int)pImage->width*4); - if (pCairoImage->pCairoSurface == NULL) { - free(pCairoImage->pData); - return false; - } - - return true; -} - -void dr2d_on_delete_image_cairo(dr2d_image* pImage) -{ - cairo_image_data* pCairoImage = dr2d_get_image_extra_data(pImage); - if (pCairoImage == NULL) { - return; - } - - cairo_surface_destroy(pCairoImage->pCairoSurface); - free(pCairoImage->pData); -} - - -void dr2d_begin_draw_cairo(dr2d_surface* pSurface) -{ - assert(pSurface != NULL); - - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData == NULL) { - return; - } - - cairo_set_antialias(pCairoData->pCairoContext, CAIRO_ANTIALIAS_NONE); -} - -void dr2d_end_draw_cairo(dr2d_surface* pSurface) -{ - assert(pSurface != NULL); - - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData == NULL) { - return; - } - - cairo_set_antialias(pCairoData->pCairoContext, CAIRO_ANTIALIAS_DEFAULT); -} - -void dr2d_clear_cairo(dr2d_surface* pSurface, dr2d_color color) -{ - // TODO: I forget... is this supposed to ignore the current clip? If so, this needs to be changed so that - // the clip is reset first then restored afterwards. - dr2d_draw_rect_cairo(pSurface, 0, 0, dr2d_get_surface_width(pSurface), dr2d_get_surface_height(pSurface), color); -} - -void dr2d_draw_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color) -{ - assert(pSurface != NULL); - - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData != NULL) - { - cairo_set_source_rgba(pCairoData->pCairoContext, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0); - cairo_rectangle(pCairoData->pCairoContext, left, top, (right - left), (bottom - top)); - cairo_fill(pCairoData->pCairoContext); - } -} - -void dr2d_draw_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth) -{ - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData == NULL) { - return; - } - - cairo_t* cr = pCairoData->pCairoContext; - - cairo_set_source_rgba(cr, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0); - - // We do this as 4 separate rectangles. - cairo_rectangle(cr, left, top, outlineWidth, bottom - top); // Left - cairo_fill(cr); - cairo_rectangle(cr, right - outlineWidth, top, outlineWidth, bottom - top); // Right - cairo_fill(cr); - cairo_rectangle(cr, left + outlineWidth, top, right - left - (outlineWidth*2), outlineWidth); // Top - cairo_fill(cr); - cairo_rectangle(cr, left + outlineWidth, bottom - outlineWidth, right - left - (outlineWidth*2), outlineWidth); // Bottom - cairo_fill(cr); -} - -void dr2d_draw_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor) -{ - dr2d_draw_rect_cairo(pSurface, left + outlineWidth, top + outlineWidth, right - outlineWidth, bottom - outlineWidth, color); - dr2d_draw_rect_outline_cairo(pSurface, left, top, right, bottom, outlineColor, outlineWidth); -} - -void dr2d_draw_round_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius) -{ - // FIXME: This does not draw rounded corners. - (void)radius; - - dr2d_draw_rect_cairo(pSurface, left, top, right, bottom, color); -} - -void dr2d_draw_round_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth) -{ - // FIXME: This does not draw rounded corners. - (void)radius; - - dr2d_draw_rect_outline_cairo(pSurface, left, top, right, bottom, color, outlineWidth); -} - -void dr2d_draw_round_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor) -{ - // FIXME: This does not draw rounded corners. - (void)radius; - - dr2d_draw_rect_with_outline_cairo(pSurface, left, top, right, bottom, color, outlineWidth, outlineColor); -} - -void dr2d_draw_text_cairo(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor) -{ - cairo_surface_data* pCairoSurface = dr2d_get_surface_extra_data(pSurface); - if (pCairoSurface == NULL) { - return; - } - - cairo_t* cr = pCairoSurface->pCairoContext; - - - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return; - } - - // Cairo expends null terminated strings, however the input string is not guaranteed to be null terminated. - char* textNT; - if (textSizeInBytes != (size_t)-1) { - textNT = malloc(textSizeInBytes + 1); - memcpy(textNT, text, textSizeInBytes); - textNT[textSizeInBytes] = '\0'; - } else { - textNT = (char*)text; - } - - - cairo_set_scaled_font(cr, pCairoFont->pFont); - - - - // Background. - cairo_text_extents_t textMetrics; - cairo_text_extents(cr, textNT, &textMetrics); - cairo_set_source_rgba(cr, backgroundColor.r / 255.0, backgroundColor.g / 255.0, backgroundColor.b / 255.0, backgroundColor.a / 255.0); - cairo_rectangle(cr, posX, posY, textMetrics.x_advance, pCairoFont->metrics.lineHeight); - cairo_fill(cr); - - - // Text. - cairo_move_to(cr, posX, posY + pCairoFont->metrics.ascent); - cairo_set_source_rgba(cr, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0); - cairo_show_text(cr, textNT); - - - if (textNT != text) { - free(textNT); - } -} - -void dr2d_draw_image_cairo(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs) -{ - cairo_surface_data* pCairoSurface = dr2d_get_surface_extra_data(pSurface); - if (pCairoSurface == NULL) { - return; - } - - cairo_image_data* pCairoImage = dr2d_get_image_extra_data(pImage); - if (pCairoImage == NULL) { - return; - } - - cairo_t* cr = pCairoSurface->pCairoContext; - - cairo_save(cr); - cairo_translate(cr, pArgs->dstX, pArgs->dstY); - - // Background. - if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) != 0) - { - cairo_set_source_rgba(cr, pArgs->backgroundColor.r / 255.0, pArgs->backgroundColor.g / 255.0, pArgs->backgroundColor.b / 255.0, pArgs->backgroundColor.a / 255.0); - cairo_rectangle(cr, 0, 0, pArgs->dstWidth, pArgs->dstHeight); - cairo_fill(cr); - } - - if (pArgs->foregroundTint.r == 255 && pArgs->foregroundTint.g == 255 && pArgs->foregroundTint.b == 255 && pArgs->foregroundTint.a == 255) { - cairo_scale(cr, pArgs->dstWidth / pArgs->srcWidth, pArgs->dstHeight / pArgs->srcHeight); - cairo_set_source_surface(cr, pCairoImage->pCairoSurface, pArgs->srcX, pArgs->srcY); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); - cairo_paint(cr); - } else { - // Slower path. The image needs to be tinted. We create a temporary image for this. - // NOTE: This is incorrect. It's just a temporary solution until I figure out a better way. - cairo_surface_t* pTempImageSurface = cairo_surface_create_similar_image(pCairoImage->pCairoSurface, CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_width(pCairoImage->pCairoSurface), cairo_image_surface_get_height(pCairoImage->pCairoSurface)); - if (pTempImageSurface != NULL) { - cairo_t* cr2 = cairo_create(pTempImageSurface); - - cairo_set_operator(cr2, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface(cr2, pCairoImage->pCairoSurface, 0, 0); - cairo_pattern_set_filter(cairo_get_source(cr2), CAIRO_FILTER_NEAREST); - cairo_paint(cr2); - - // Tint. - cairo_set_operator(cr2, CAIRO_OPERATOR_ATOP); - cairo_set_source_rgba(cr2, pArgs->foregroundTint.r / 255.0, pArgs->foregroundTint.g / 255.0, pArgs->foregroundTint.b / 255.0, 1); - cairo_rectangle(cr2, 0, 0, pArgs->dstWidth, pArgs->dstHeight); - cairo_fill(cr2); - - /*cairo_set_operator(cr2, CAIRO_OPERATOR_MULTIPLY); - cairo_set_source_surface(cr2, pCairoImage->pCairoSurface, 0, 0); - cairo_pattern_set_filter(cairo_get_source(cr2), CAIRO_FILTER_NEAREST); - cairo_paint(cr2);*/ - - // Draw the temporary surface onto the main surface. - cairo_scale(cr, pArgs->dstWidth / pArgs->srcWidth, pArgs->dstHeight / pArgs->srcHeight); - cairo_set_source_surface(cr, pTempImageSurface, pArgs->srcX, pArgs->srcY); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); - //cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_paint(cr); - - cairo_destroy(cr2); - cairo_surface_destroy(pTempImageSurface); - } - } - - cairo_restore(cr); -} - -void dr2d_set_clip_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom) -{ - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData == NULL) { - return; - } - - pCairoData->clipRectLeft = left; - pCairoData->clipRectTop = top; - pCairoData->clipRectRight = right; - pCairoData->clipRectBottom = bottom; - - cairo_reset_clip(pCairoData->pCairoContext); - cairo_rectangle(pCairoData->pCairoContext, left, top, right - left, bottom - top); - cairo_clip(pCairoData->pCairoContext); -} - -void dr2d_get_clip_cairo(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut) -{ - (void)pSurface; - (void)pLeftOut; - (void)pTopOut; - (void)pRightOut; - (void)pBottomOut; - - cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface); - if (pCairoData == NULL) { - return; - } - - if (pLeftOut) { *pLeftOut = pCairoData->clipRectLeft; } - if (pTopOut) { *pTopOut = pCairoData->clipRectTop; } - if (pRightOut) { *pRightOut = pCairoData->clipRectRight; } - if (pBottomOut) { *pBottomOut = pCairoData->clipRectBottom; } -} - - -dr2d_image_format dr2d_get_optimal_image_format_cairo(dr2d_context* pContext) -{ - (void)pContext; - return dr2d_image_format_argb8; -} - -void* dr2d_map_image_data_cairo(dr2d_image* pImage, unsigned accessFlags) -{ - (void)pImage; - (void)accessFlags; - return NULL; -} - -void dr2d_unmap_image_data_cairo(dr2d_image* pImage) -{ - (void)pImage; -} - - -bool dr2d_get_font_metrics_cairo(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return false; - } - - if (pMetricsOut) { - *pMetricsOut = pCairoFont->metrics; - } - - return true; -} - -static size_t dr2d__utf32_to_utf8(unsigned int utf32, char* utf8, size_t utf8Size) -{ - // NOTE: This function is untested. - - size_t utf8ByteCount = 0; - if (utf32 < 0x80) { - utf8ByteCount = 1; - } else if (utf32 < 0x800) { - utf8ByteCount = 2; - } else if (utf32 < 0x10000) { - utf8ByteCount = 3; - } else if (utf32 < 0x110000) { - utf8ByteCount = 4; - } - - if (utf8ByteCount > utf8Size) { - if (utf8 != NULL && utf8Size > 0) { - utf8[0] = '\0'; - } - return 0; - } - - utf8 += utf8ByteCount; - if (utf8ByteCount < utf8Size) { - utf8[0] = '\0'; // Null terminate. - } - - const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; - switch (utf8ByteCount) - { - case 4: *--utf8 = (char)((utf32 | 0x80) & 0xBF); utf32 >>= 6; - case 3: *--utf8 = (char)((utf32 | 0x80) & 0xBF); utf32 >>= 6; - case 2: *--utf8 = (char)((utf32 | 0x80) & 0xBF); utf32 >>= 6; - case 1: *--utf8 = (char)(utf32 | firstByteMark[utf8ByteCount]); - default: break; - } - - return utf8ByteCount; -} - -bool dr2d_get_glyph_metrics_cairo(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return false; - } - - // The UTF-32 code point needs to be converted to a UTF-8 character. - char utf8[16]; - size_t utf8len = dr2d__utf32_to_utf8(utf32, utf8, sizeof(utf8)); // This will null-terminate. - if (utf8len == 0) { - return false; // Error converting UTF-32 to UTF-8. - } - - - cairo_text_extents_t glyphExtents; - cairo_scaled_font_text_extents(pCairoFont->pFont, utf8, &glyphExtents); - - if (pGlyphMetrics) - { - pGlyphMetrics->width = glyphExtents.width; - pGlyphMetrics->height = glyphExtents.height; - pGlyphMetrics->originX = glyphExtents.x_bearing; - pGlyphMetrics->originY = glyphExtents.y_bearing; - pGlyphMetrics->advanceX = glyphExtents.x_advance; - pGlyphMetrics->advanceY = glyphExtents.y_advance; - } - - return true; -} - -bool dr2d_measure_string_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return false; - } - - - // Cairo expends null terminated strings, however the input string is not guaranteed to be null terminated. - char* textNT; - if (textSizeInBytes != (size_t)-1) { - textNT = malloc(textSizeInBytes + 1); - if (textNT == NULL) { - return false; - } - memcpy(textNT, text, textSizeInBytes); - textNT[textSizeInBytes] = '\0'; - } else { - textNT = (char*)text; - } - - - cairo_text_extents_t textMetrics; - cairo_scaled_font_text_extents(pCairoFont->pFont, textNT, &textMetrics); - - if (pWidthOut) { - *pWidthOut = textMetrics.x_advance; - } - if (pHeightOut) { - //*pHeightOut = textMetrics.height; - *pHeightOut = pCairoFont->metrics.ascent + pCairoFont->metrics.descent; - } - - - if (textNT != text) { - free(textNT); - } - - return true; -} - -bool dr2d_get_text_cursor_position_from_point_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return false; - } - - cairo_glyph_t* pGlyphs = NULL; - int glyphCount = 0; - cairo_status_t result = cairo_scaled_font_text_to_glyphs(pCairoFont->pFont, 0, 0, text, textSizeInBytes, &pGlyphs, &glyphCount, NULL, NULL, NULL); - if (result != CAIRO_STATUS_SUCCESS) { - return false; - } - - float cursorPosX = 0; - int charIndex = 0; - - // We just iterate over each glyph until we find the one sitting under . - float runningPosX = 0; - for (int iGlyph = 0; iGlyph < glyphCount; ++iGlyph) - { - cairo_text_extents_t glyphMetrics; - cairo_scaled_font_glyph_extents(pCairoFont->pFont, pGlyphs + iGlyph, 1, &glyphMetrics); - - float glyphLeft = runningPosX; - float glyphRight = glyphLeft + glyphMetrics.x_advance; - - // Are we sitting on top of inputPosX? - if (inputPosX >= glyphLeft && inputPosX <= glyphRight) - { - float glyphHalf = glyphLeft + ceilf(((glyphRight - glyphLeft) / 2.0f)); - if (inputPosX <= glyphHalf) { - cursorPosX = glyphLeft; - charIndex = iGlyph; - } else { - cursorPosX = glyphRight; - charIndex = iGlyph + 1; - } - - break; - } - else - { - // Have we moved past maxWidth? - if (glyphRight > maxWidth) - { - cursorPosX = maxWidth; - charIndex = iGlyph; - break; - } - else - { - runningPosX = glyphRight; - - cursorPosX = runningPosX; - charIndex = iGlyph; - } - } - } - - cairo_glyph_free(pGlyphs); - - if (pTextCursorPosXOut) { - *pTextCursorPosXOut = cursorPosX; - } - if (pCharacterIndexOut) { - *pCharacterIndexOut = charIndex; - } - - return true; -} - -bool dr2d_get_text_cursor_position_from_char_cairo(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut) -{ - cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont); - if (pCairoFont == NULL) { - return false; - } - - cairo_glyph_t* pGlyphs = NULL; - int glyphCount = 0; - cairo_status_t result = cairo_scaled_font_text_to_glyphs(pCairoFont->pFont, 0, 0, text, -1, &pGlyphs, &glyphCount, NULL, NULL, NULL); - if (result != CAIRO_STATUS_SUCCESS) { - return false; - } - - float cursorPosX = 0; - - // We just iterate over each glyph until we find the one sitting under . - for (int iGlyph = 0; iGlyph < glyphCount; ++iGlyph) - { - if (iGlyph == (int)characterIndex) { - break; - } - - cairo_text_extents_t glyphMetrics; - cairo_scaled_font_glyph_extents(pCairoFont->pFont, pGlyphs + iGlyph, 1, &glyphMetrics); - - cursorPosX += glyphMetrics.x_advance; - } - - cairo_glyph_free(pGlyphs); - - if (pTextCursorPosXOut) { - *pTextCursorPosXOut = cursorPosX; - } - - return true; -} -#endif // Cairo -#endif - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_audio.h b/source/engine/thirdparty/dr_libs/old/dr_audio.h deleted file mode 100644 index 87abde1..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_audio.h +++ /dev/null @@ -1,5307 +0,0 @@ -// Audio playback, recording and mixing. Public domain. See "unlicense" statement at the end of this file. -// dr_audio - v0.0 (unversioned) - Release Date TBD -// -// David Reid - mackron@gmail.com - -// !!!!! THIS IS WORK IN PROGRESS !!!!! - -// USAGE -// -// dr_audio is a single-file library. To use it, do something like the following in one .c file. -// #define DR_AUDIO_IMPLEMENTATION -// #include "dr_audio.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. -// -// dr_audio supports loading and decoding of WAV, FLAC and Vorbis streams via dr_wav, dr_flac and stb_vorbis respectively. To enable -// these all you need to do is #include "dr_audio.h" _after_ #include "dr_wav.h", #include "dr_flac.h" and #include "stb_vorbis.c" in -// the implementation file, like so: -// -// #define DR_WAV_IMPLEMENTATION -// #include "dr_wav.h" -// -// #define DR_FLAC_IMPLEMENTATION -// #include "dr_flac.h" -// -// #define STB_VORBIS_IMPLEMENTATION -// #include "stb_vorbis.c" -// -// #define DR_AUDIO_IMPLEMENTATION -// #include "dr_audio.h" -// -// dr_wav, dr_flac and stb_vorbis are entirely optional, and dr_audio will automatically detect the ones that are available without -// any additional intervention on your part. -// -// -// dr_audio has a layered API with different levels of flexibility vs simplicity. An example of the high level API follows: -// -// dra_device* pDevice; -// dra_result result = dra_device_create(NULL, dra_device_type_playback, &pDevice); -// if (result != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// dra_voice* pVoice; -// result = dra_voice_create_from_file(pDevice, "my_song.flac", &pVoice); -// if (result != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// dra_voice_play(pVoice, DR_FALSE); -// -// ... -// -// dra_voice_delete(pVoice); -// dra_device_delete(pDevice); -// -// -// An example of the low level API: -// -// dra_context context; -// dra_result result = dra_context_init(&context); // Initializes the backend (DirectSound/ALSA) -// if (result != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// unsigned int deviceID = 0; // Default device -// unsigned int channels = 2; // Stereo -// unsigned int sampleRate = 48000; -// unsigned int latencyInMilliseconds = 0; // 0 will default to DR_AUDIO_DEFAULT_LATENCY. -// dra_device device; -// result = dra_device_init_ex(&context, dra_device_type_playback, deviceID, channels, sampleRate, latencyInMilliseconds, &device); -// if (result != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// dra_voice* pVoice; -// dra_result result = dra_voice_create(pDevice, dra_format_f32, channels, sampleRate, voiceBufferSizeInBytes, pVoiceSampleData, &pVoice); -// if (result != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// ... -// -// // Sometime later you may need to update the data inside the voice's internal buffer... It's your job to handle -// // synchronization - have fun! Hint: use playback events at fixed locations to know when a region of the buffer -// // is available for updating. -// float* pVoiceData = (float*)dra_voice_get_buffer_ptr_by_sample(pVoice, sampleOffset); -// if (pVoiceData == NULL) { -// return -1; -// } -// -// memcpy(pVoiceData, pNewVoiceData, sizeof(float) * samplesToCopy); -// -// ... -// -// dra_voice_delete(pVoice); -// dra_device_uninit(pDevice); -// dra_context_uninit(pContext); -// -// In the above example the voice and device are configured to use the same number of channels and sample rate, however they are -// allowed to differ, in which case dr_audio will automatically convert the data. Note that sample rate conversion is currently -// very low quality. -// -// To handle streaming buffers, you can attach a callback that's fired when a voice's playback position reaches a certain point. -// Usually you would set this to the middle and end of the buffer, filling the previous half with new data. Use the -// dra_voice_add_playback_event() API for this. -// -// The playback position of a voice can be retrieved and set with dra_voice_get_playback_position() and dra_voice_set_playback_position() -// respctively. The playback is specified in samples. dra_voice_get_playback_position() will always return a value which is a multiple -// of the channel count. dra_voice_set_playback_position() will round the specified sample index to a multiple of the channel count. -// -// -// dr_audio has support for submixing which basically allows you to control volume (and in the future, effects) for groups of sounds -// which would typically be organized into categories. An abvious example would be in games where you may want to have separate volume -// controls for music, voices, special effects, etc. To do submixing, all you need to do is create a mixer. There is a master mixer -// associated with every device, and all newly created mixers are a child of the master mixer, by default: -// -// dra_mixer* pMusicMixer; -// dra_result result = dra_mixer_create(pDevice, &pMusicMixer); -// if (result != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// // At this point pMusicMixer is a child of the device's master mixer. To change the hierarchy, just do something like this: -// dra_mixer_attach_submixer(pSomeOtherMixer, pMusicMixer); -// -// // A voice is attached to the master mixer by default, but you can attach it to a different mixer like this: -// dra_mixer_attach_voice(pMusicMixer, pMyMusicVoice); -// -// // Control the volume of the mixer... -// dra_mixer_set_volume(pMusicMixer, 0.5f); // <-- The volume is linear, so this is half volume. -// -// -// -// dr_audio includes an abstraction for audio decoding. Built-in support is included for WAV, FLAC and Vorbis streams: -// -// dra_decoder decoder; -// if (dra_decoder_open_file(&decoder, filePath) != DRA_RESULT_SUCCESS) { -// return -1; -// } -// -// dr_uint64 samplesRead = dra_decoder_read_f32(&decoder, samplesToRead, pSamples); -// update_my_voice_data(pVoice, pSamples, samplesRead); -// -// dra_decoder_close(&decoder); -// -// Decoders can be opened/initialized from files, a block of memory, or application-defined callbacks. -// -// -// -// OPTIONS -// #define these options before including this file. -// -// #define DR_AUDIO_NO_DSOUND -// Disables the DirectSound backend. Note that this is the only backend for the Windows platform. -// -// #define DR_AUDIO_NO_ALSA -// Disables the ALSA backend. Note that this is the only backend for the Linux platform. -// -// #define DR_AUDIO_NO_STDIO -// Disables any functions that use stdio, such as dra_sound_create_from_file(). - - -#ifndef dr_audio2_h -#define dr_audio2_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifndef DR_SIZED_TYPES_DEFINED -#define DR_SIZED_TYPES_DEFINED -#if defined(_MSC_VER) && _MSC_VER < 1600 -typedef signed char dr_int8; -typedef unsigned char dr_uint8; -typedef signed short dr_int16; -typedef unsigned short dr_uint16; -typedef signed int dr_int32; -typedef unsigned int dr_uint32; -typedef signed __int64 dr_int64; -typedef unsigned __int64 dr_uint64; -#else -#include -typedef int8_t dr_int8; -typedef uint8_t dr_uint8; -typedef int16_t dr_int16; -typedef uint16_t dr_uint16; -typedef int32_t dr_int32; -typedef uint32_t dr_uint32; -typedef int64_t dr_int64; -typedef uint64_t dr_uint64; -#endif -typedef dr_int8 dr_bool8; -typedef dr_int32 dr_bool32; -#define DR_TRUE 1 -#define DR_FALSE 0 -#endif - -#ifndef DR_AUDIO_MAX_CHANNEL_COUNT -#define DR_AUDIO_MAX_CHANNEL_COUNT 16 -#endif - -#ifndef DR_AUDIO_MAX_EVENT_COUNT -#define DR_AUDIO_MAX_EVENT_COUNT 16 -#endif - -#define DR_AUDIO_EVENT_ID_STOP 0xFFFFFFFFFFFFFFFFULL -#define DR_AUDIO_EVENT_ID_PLAY 0xFFFFFFFFFFFFFFFEULL - -typedef int dra_result; -#define DRA_RESULT_SUCCESS 0 -#define DRA_RESULT_UNKNOWN_ERROR -1 -#define DRA_RESULT_INVALID_ARGS -2 -#define DRA_RESULT_OUT_OF_MEMORY -3 -#define DRA_RESULT_FAILED_TO_OPEN_FILE -4 -#define DRA_RESULT_NO_BACKEND -1024 -#define DRA_RESULT_NO_BACKEND_DEVICE -1025 -#define DRA_RESULT_NO_DECODER -1026 -#define DRA_FAILED(result) ((result) != 0) -#define DRA_SUCCEEDED(result) ((result) == 0) - -#define DRA_MIXER_FLAG_PAUSED (1 << 0) - -typedef enum -{ - dra_device_type_playback = 0, - dra_device_type_capture -} dra_device_type; - -typedef enum -{ - dra_format_u8 = 0, - dra_format_s16, - dra_format_s24, - dra_format_s32, - dra_format_f32, - dra_format_default = dra_format_f32 -} dra_format; - -typedef enum -{ - dra_src_algorithm_none, - dra_src_algorithm_linear, -} dra_src_algorithm; - -// dra_thread_event_type is used internally for thread management. -typedef enum -{ - dra_thread_event_type_none, - dra_thread_event_type_terminate, - dra_thread_event_type_play -} dra_thread_event_type; - -typedef struct dra_backend dra_backend; -typedef struct dra_backend_device dra_backend_device; - -typedef struct dra_context dra_context; -typedef struct dra_device dra_device; -typedef struct dra_mixer dra_mixer; -typedef struct dra_voice dra_voice; - -typedef void* dra_thread; -typedef void* dra_mutex; -typedef void* dra_semaphore; - -typedef void (* dra_event_proc) (dr_uint64 eventID, void* pUserData); -typedef void (* dra_samples_processed_proc)(dra_device* pDevice, const size_t sampleCount, const float* pSamples, void* pUserData); - -typedef struct -{ - dr_uint64 id; - void* pUserData; - dr_uint64 sampleIndex; - dra_event_proc proc; - dra_voice* pVoice; - dr_bool32 hasBeenSignaled; -} dra__event; - -typedef struct -{ - size_t firstEvent; - size_t eventCount; - size_t eventBufferSize; - dra__event* pEvents; - dra_mutex lock; -} dra__event_queue; - -struct dra_context -{ - dra_backend* pBackend; -}; - -struct dra_device -{ - // The context that created and owns this device. - dra_context* pContext; - - // The backend device. This is used to connect the cross-platform front-end with the backend. - dra_backend_device* pBackendDevice; - - // The main mutex for handling thread-safety. - dra_mutex mutex; - - // The main thread. For playback devices, this is the thread that waits for fragments to finish processing an then - // mixes and pushes new audio data to the hardware buffer for playback. - dra_thread thread; - - // The semaphore used by the main thread to determine whether or not an event is waiting to be processed. - dra_semaphore threadEventSem; - - // The event type of the most recent event. - dra_thread_event_type nextThreadEventType; - - // TODO: Make these booleans flags. - - // Whether or not the device owns the context. This basically just means whether or not the device was created with a null - // context and needs to delete the context itself when the device is deleted. - dr_bool32 ownsContext; - - // Whether or not the device is being closed. This is used by the thread to determine if it needs to terminate. When - // dra_device_close() is called, this flag will be set and threadEventSem released. The thread will then see this as it's - // signal to terminate. - dr_bool32 isClosed; - - // Whether or not the device is currently playing. When at least one voice is playing, this will be DR_TRUE. When there - // are no voices playing, this will be set to DR_FALSE and the background thread will sit dormant until another voice - // starts playing or the device is closed. - dr_bool32 isPlaying; - - // Whether or not the device should stop on the next fragment. This is used for stopping playback of devices that - // have no voice's playing. - dr_bool32 stopOnNextFragment; - - - // The master mixer. This is the one and only top-level mixer. - dra_mixer* pMasterMixer; - - // The number of voices currently being played. This is used to determine whether or not the device should be placed - // into a dormant state when nothing is being played. - size_t playingVoicesCount; - - - // When a playback event is scheduled it is added to this queue. Events are not posted straight away, but are instead - // placed in a queue for processing later at specific times to ensure the event is posted AFTER the device has actually - // played the sample the event is set for. - dra__event_queue eventQueue; - - // The function to call when a segment of samples has been processed. This is only really needed for capture devices, - // but can also be used to keep track of all of the audio data that's passed through a playback device. This is called - // as the read pointer moves passed each segment and again for the leftover partial segment that'll occur when the - // device is stopped. - dra_samples_processed_proc onSamplesProcessed; - void* pUserDataForOnSamplesProcessed; - - - // The number of channels being used by the device. - unsigned int channels; - - // The sample rate in seconds. - unsigned int sampleRate; -}; - -struct dra_mixer -{ - // The device that created and owns this mixer. - dra_device* pDevice; - - // Whether or not the mixer is paused. - dr_uint32 flags; - - - // The parent mixer. - dra_mixer* pParentMixer; - - // The first child mixer. - dra_mixer* pFirstChildMixer; - - // The last child mixer. - dra_mixer* pLastChildMixer; - - // The next sibling mixer. - dra_mixer* pNextSiblingMixer; - - // The previous sibling mixer. - dra_mixer* pPrevSiblingMixer; - - - // The first voice attached to the mixer. - dra_voice* pFirstVoice; - - // The last voice attached to the mixer. - dra_voice* pLastVoice; - - - // The volume of the buffer as a linear scale. A value of 0.5 means the sound is at half volume. There is no hard - // limit on the volume, however going beyond 1 may introduce clipping. - float linearVolume; - - - // Mixers output the results of the final mix into a buffer referred to as the staging buffer. A parent mixer will - // use the staging buffer when it mixes the results of it's submixers. This is an offset of pData. - float* pStagingBuffer; - - // A pointer to the buffer containing the sample data of the buffer currently being mixed, as floating point values. - // This is an offset of pData. - float* pNextSamplesToMix; - - - // The sample data for pStagingBuffer and pNextSamplesToMix. - float pData[1]; -}; - -struct dra_voice -{ - // The device that created and owns this voice. - dra_device* pDevice; - - // The mixer the voice is attached to. Should never be null. The mixer doesn't "own" the voice - the voice - // is simply attached to it. - dra_mixer* pMixer; - - - // The next voice in the linked list of voices attached to the mixer. - dra_voice* pNextVoice; - - // The previous voice in the linked list of voices attached to the mixer. - dra_voice* pPrevVoice; - - - // The format of the audio data contained within this voice. - dra_format format; - - // The number of channels. - unsigned int channels; - - // The sample rate in seconds. - unsigned int sampleRate; - - - // The volume of the voice as a linear scale. A value of 0.5 means the sound is at half volume. There is no hard - // limit on the volume, however going beyond 1 may introduce clipping. - float linearVolume; - - - - // Whether or not the voice is currently playing. - dr_bool32 isPlaying; - - // Whether or not the voice is currently looping. Whether or not the voice is looping is determined by the last - // call to dra_voice_play(). - dr_bool32 isLooping; - - - // The total number of frames in the voice. - dr_uint64 frameCount; - - // The current read position, in frames. An important detail with this is that it's based on the sample rate of the - // device, not the voice. - dr_uint64 currentReadPos; - - - // A buffer for storing converted frames. This is used by dra_voice__next_frame(). As frames are converted to - // floats, that are placed into this buffer. - float convertedFrame[DR_AUDIO_MAX_CHANNEL_COUNT]; - - - // Data for sample rate conversion. Different SRC algorithms will use different data, which will be stored in their - // own structure. - struct - { - // The sample rate conversion algorithm to use. - dra_src_algorithm algorithm; - - union - { - struct - { - dr_uint64 prevFrameIndex; - float prevFrame[DR_AUDIO_MAX_CHANNEL_COUNT]; - float nextFrame[DR_AUDIO_MAX_CHANNEL_COUNT]; - } linear; - } data; - } src; - - - // The number of playback notification events. This does not include the stop and play events. - size_t playbackEventCount; - - // A pointer to the list of playback events. - dra__event playbackEvents[DR_AUDIO_MAX_EVENT_COUNT]; - - // The event to call when the voice has stopped playing, either naturally or explicitly with dra_voice_stop(). - dra__event stopEvent; - - // The event to call when the voice starts playing. - dra__event playEvent; - - - // Application defined user data. - void* pUserData; - - - // The size of the buffer in bytes. - size_t sizeInBytes; - - // The actual buffer containing the raw audio data in it's native format. At mix time the data will be converted - // to floats. - dr_uint8 pData[1]; -}; - - -// dra_context_init() -dra_result dra_context_init(dra_context* pContext); -void dra_context_uninit(dra_context* pContext); - -// Helper for allocating and initializing a context. If you want to do your own memory management or just want to put the context -// object on the stack, just use dra_context_init() instead. -dra_result dra_context_create(dra_context** ppContext); -void dra_context_delete(dra_context* pContext); - - -// dra_device_init_ex() -// -// If deviceID is 0 the default device for the given type is used. -// format can be dra_format_default which is dra_format_s32. -// If channels is set to 0, defaults 2 channels (stereo). -// If sampleRate is set to 0, defaults to 48000. -// If latency is 0, defaults to 50 milliseconds. See notes about latency above. -// -// Concerning the DirectSound backend (From MSDN): -// Note that if your application is playing sounds as well as capturing them, capture buffer creation can fail when -// the format of the capture buffer is not the same as that of the primary buffer. The reason is that some cards have -// only a single clock and cannot support capture and playback at two different frequencies. -// -// This means you will need to keep the channels and sample rate consistent across playback and capture devices when -// using the DirectSound backend. -dra_result dra_device_init_ex(dra_context* pContext, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds, dra_device* pDevice); -dra_result dra_device_init(dra_context* pContext, dra_device_type type, dra_device* pDevice); -void dra_device_uninit(dra_device* pDevice); - -// Helper for allocating and initializing a device object. -dra_result dra_device_create_ex(dra_context* pContext, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds, dra_device** ppDevice); -dra_result dra_device_create(dra_context* pContext, dra_device_type type, dra_device** ppDevice); -void dra_device_delete(dra_device* pDevice); - -// Starts a capture device. -// -// Do not call this on a playback device - this is managed by dr_audio. This will fail for playback devices. -dra_result dra_device_start(dra_device* pDevice); - -// Stops a capture device. -// -// Do not call this on a playback device - this is managed by dr_audio. This will fail for playback devices. -dra_result dra_device_stop(dra_device* pDevice); - -// Sets the function to call when a segment of samples have been processed by the device (either captured -// or played back). Use this to keep track of the audio data that's passed to a playback device or from a -// capture device. -void dra_device_set_samples_processed_callback(dra_device* pDevice, dra_samples_processed_proc proc, void* pUserData); - - - - -// dra_mixer_create() -dra_result dra_mixer_create(dra_device* pDevice, dra_mixer** ppMixer); - -// dra_mixer_delete() -// -// Deleting a mixer will detach any attached voices and sub-mixers and attach them to the master mixer. It is -// up to the application to manage the allocation of sub-mixers and voices. Typically you'll want to delete -// child mixers and voices before deleting a mixer. -void dra_mixer_delete(dra_mixer* pMixer); - -// dra_mixer_attach_submixer() -void dra_mixer_attach_submixer(dra_mixer* pMixer, dra_mixer* pSubmixer); - -// dra_mixer_detach_submixer() -void dra_mixer_detach_submixer(dra_mixer* pMixer, dra_mixer* pSubmixer); - -// dra_mixer_detach_all_submixers() -void dra_mixer_detach_all_submixers(dra_mixer* pMixer); - -// dra_mixer_attach_voice() -void dra_mixer_attach_voice(dra_mixer* pMixer, dra_voice* pVoice); - -// dra_mixer_detach_voice() -void dra_mixer_detach_voice(dra_mixer* pMixer, dra_voice* pVoice); - -// dra_mixer_detach_all_voices() -void dra_mixer_detach_all_voices(dra_mixer* pMixer); - -// dra_voice_set_volume() -void dra_mixer_set_volume(dra_mixer* pMixer, float linearVolume); - -// dra_voice_get_volume() -float dra_mixer_get_volume(dra_mixer* pMixer); - -// Mixes the next number of frameCount and moves the playback position appropriately. -// -// pMixer [in] The mixer. -// frameCount [in] The number of frames to mix. -// -// Returns the number of frames actually mixed. -// -// The return value is used to determine whether or not there's anything left to mix in the future. When there are -// no samples left to mix, the device can be put into a dormant state to prevent unnecessary processing. -// -// Mixed samples will be placed in pMixer->pStagingBuffer. -size_t dra_mixer_mix_next_frames(dra_mixer* pMixer, size_t frameCount); - - -// Non-recursively counts the number of voices that are attached to the given mixer. -size_t dra_mixer_count_attached_voices(dra_mixer* pMixer); - -// Recursively counts the number of voices that are attached to the given mixer. -size_t dra_mixer_count_attached_voices_recursive(dra_mixer* pMixer); - -// Non-recursively gathers all of the voices that are currently attached to the given mixer. -size_t dra_mixer_gather_attached_voices(dra_mixer* pMixer, dra_voice** ppVoicesOut); - -// Recursively gathers all of the voices that are currently attached to the given mixer. -size_t dra_mixer_gather_attached_voices_recursive(dra_mixer* pMixer, dra_voice** ppVoicesOut); - - -// Marks the given mixer as paused. -void dra_mixer_pause(dra_mixer* pMixer); - -// Unmarks the given mixer as paused. -void dra_mixer_resume(dra_mixer* pMixer); - -// Determines whether or not the given mixer is paused. -dr_bool32 dra_mixer_is_paused(dra_mixer* pMixer); - - -// dra_voice_create() -dra_result dra_voice_create(dra_device* pDevice, dra_format format, unsigned int channels, unsigned int sampleRate, size_t sizeInBytes, const void* pInitialData, dra_voice** ppVoice); -dra_result dra_voice_create_compatible(dra_device* pDevice, size_t sizeInBytes, const void* pInitialData, dra_voice** ppVoice); - -// dra_voice_delete() -void dra_voice_delete(dra_voice* pVoice); - -// dra_voice_play() -// -// If the mixer the voice is attached to is not playing, the voice will be marked as playing, but won't actually play anything until -// the mixer is started again. -void dra_voice_play(dra_voice* pVoice, dr_bool32 loop); - -// dra_voice_stop() -void dra_voice_stop(dra_voice* pVoice); - -// dra_voice_is_playing() -dr_bool32 dra_voice_is_playing(dra_voice* pVoice); - -// dra_voice_is_looping() -dr_bool32 dra_voice_is_looping(dra_voice* pVoice); - - -// dra_voice_set_volume() -void dra_voice_set_volume(dra_voice* pVoice, float linearVolume); - -// dra_voice_get_volume() -float dra_voice_get_volume(dra_voice* pVoice); - - -void dra_voice_set_on_stop(dra_voice* pVoice, dra_event_proc proc, void* pUserData); -void dra_voice_set_on_play(dra_voice* pVoice, dra_event_proc proc, void* pUserData); -dr_bool32 dra_voice_add_playback_event(dra_voice* pVoice, dr_uint64 sampleIndex, dr_uint64 eventID, dra_event_proc proc, void* pUserData); -void dra_voice_remove_playback_event(dra_voice* pVoice, dr_uint64 eventID); - -// dra_voice_get_playback_position() -dr_uint64 dra_voice_get_playback_position(dra_voice* pVoice); - -// dra_voice_set_playback_position() -void dra_voice_set_playback_position(dra_voice* pVoice, dr_uint64 sampleIndex); - - -// dra_voice_get_buffer_ptr_by_sample() -void* dra_voice_get_buffer_ptr_by_sample(dra_voice* pVoice, dr_uint64 sample); - -// dra_voice_write_silence() -void dra_voice_write_silence(dra_voice* pVoice, dr_uint64 sampleOffset, dr_uint64 sampleCount); - - -//// Other APIs //// - -// Frees memory that was allocated internally by dr_audio. -void dra_free(void* p); - -// Retrieves the number of bits per sample based on the given format. -unsigned int dra_get_bits_per_sample_by_format(dra_format format); - -// Retrieves the number of bytes per sample based on the given format. -unsigned int dra_get_bytes_per_sample_by_format(dra_format format); - - -//// Decoder APIs //// - -typedef enum -{ - dra_seek_origin_start, - dra_seek_origin_current -} dra_seek_origin; - -typedef size_t (* dra_decoder_on_read_proc) (void* pUserData, void* pDataOut, size_t bytesToRead); -typedef dr_bool32 (* dra_decoder_on_seek_proc) (void* pUserData, int offset, dra_seek_origin origin); - -typedef void (* dra_decoder_on_delete_proc) (void* pBackendDecoder); -typedef dr_uint64 (* dra_decoder_on_read_samples_proc) (void* pBackendDecoder, dr_uint64 samplesToRead, float* pSamplesOut); -typedef dr_bool32 (* dra_decoder_on_seek_samples_proc) (void* pBackendDecoder, dr_uint64 sample); - -typedef struct -{ - const dr_uint8* data; - size_t dataSize; - size_t currentReadPos; -} dra__memory_stream; - -typedef struct -{ - unsigned int channels; - unsigned int sampleRate; - dr_uint64 totalSampleCount; // <-- Can be 0. - - dra_decoder_on_read_proc onRead; - dra_decoder_on_seek_proc onSeek; - void* pUserData; - - void* pBackendDecoder; - dra_decoder_on_delete_proc onDelete; - dra_decoder_on_read_samples_proc onReadSamples; - dra_decoder_on_seek_samples_proc onSeekSamples; - - // A hack to enable decoding from memory without mallocing the user data. - dra__memory_stream memoryStream; -} dra_decoder; - -// dra_decoder_open() -dra_result dra_decoder_open(dra_decoder* pDecoder, dra_decoder_on_read_proc onRead, dra_decoder_on_seek_proc onSeek, void* pUserData); -float* dra_decoder_open_and_decode_f32(dra_decoder_on_read_proc onRead, dra_decoder_on_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount); - -dra_result dra_decoder_open_memory(dra_decoder* pDecoder, const void* pData, size_t dataSize); -float* dra_decoder_open_and_decode_memory_f32(const void* pData, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount); - -#ifndef DR_AUDIO_NO_STDIO -dra_result dra_decoder_open_file(dra_decoder* pDecoder, const char* filePath); -float* dra_decoder_open_and_decode_file_f32(const char* filePath, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount); -#endif - -// dra_decoder_close() -void dra_decoder_close(dra_decoder* pDecoder); - -// dra_decoder_read_f32() -dr_uint64 dra_decoder_read_f32(dra_decoder* pDecoder, dr_uint64 samplesToRead, float* pSamplesOut); - -// dra_decoder_seek_to_sample() -dr_bool32 dra_decoder_seek_to_sample(dra_decoder* pDecoder, dr_uint64 sample); - - -//// High Level Helper APIs //// - -#ifndef DR_AUDIO_NO_STDIO -// Creates a voice from a file. -dra_result dra_voice_create_from_file(dra_device* pDevice, const char* filePath, dra_voice** ppVoice); -#endif - - -//// High Level World API //// -// -// This section is for the sound world APIs. These are high-level APIs that sit directly on top of the main API. -typedef struct dra_sound_world dra_sound_world; -typedef struct dra_sound dra_sound; -typedef struct dra_sound_desc dra_sound_desc; - -typedef void (* dra_sound_on_delete_proc) (dra_sound* pSound); -typedef dr_uint64 (* dra_sound_on_read_proc) (dra_sound* pSound, dr_uint64 samplesToRead, void* pSamplesOut); -typedef dr_bool32 (* dra_sound_on_seek_proc) (dra_sound* pSound, dr_uint64 sample); - -struct dra_sound_desc -{ - // The format of the sound. - dra_format format; - - // The number of channels in the audio data. - unsigned int channels; - - // The sample rate of the audio data. - unsigned int sampleRate; - - - // The size of the audio data in bytes. If this is 0 it is assumed the data will be streamed. - size_t dataSize; - - // A pointer to the audio data. If this is null it is assumed the audio data is streamed. - void* pData; - - - // A pointer to the function to call when the sound object is deleted. This is used to give the application an - // opportunity to do any clean up, such as closing decoders or whatnot. - dra_sound_on_delete_proc onDelete; - - // A pointer to the function to call when dr_audio needs to request a chunk of audio data. This is only used when - // streaming data. - dra_sound_on_read_proc onRead; - - // A pointer to the function to call when dr_audio needs to seek the audio data. This is only used when streaming - // data. - dra_sound_on_seek_proc onSeek; - - // A pointer to some application defined user data that can be associated with the sound. - void* pUserData; -}; - -struct dra_sound_world -{ - // The playback device. - dra_device* pPlaybackDevice; - - // Whether or not the world owns the playback device. When this is set to DR_TRUE, it will be deleted when the world is deleted. - dr_bool32 ownsPlaybackDevice; -}; - -struct dra_sound -{ - // The world that owns this sound. - dra_sound_world* pWorld; - - // The voice object for emitting audio out of the device. - dra_voice* pVoice; - - // The descriptor of the sound that was used to initialize the sound. - dra_sound_desc desc; - - // Whether or not the sound is looping. - dr_bool32 isLooping; - - // Whether or not the sound should be stopped at the end of the chunk that's currently playing. - dr_bool32 stopOnNextChunk; - - // Application defined user data. - void* pUserData; -}; - -// dra_sound_world_create() -// -// The playback device can be null, in which case a default one will be created. -dra_sound_world* dra_sound_world_create(dra_device* pPlaybackDevice); - -// dra_sound_world_delete() -// -// This will delete every sound this world owns. -void dra_sound_world_delete(dra_sound_world* pWorld); - -// dra_sound_world_play_inline() -// -// pMixer [in, optional] The mixer to attach the sound to. Can null, in which case it's attached to the master mixer. -void dra_sound_world_play_inline(dra_sound_world* pWorld, dra_sound_desc* pDesc, dra_mixer* pMixer); - -// Plays an inlined sound in 3D space. -// -// This is a placeholder function. 3D position is not yet implemented. -void dra_sound_world_play_inline_3f(dra_sound_world* pWorld, dra_sound_desc* pDesc, dra_mixer* pMixer, float xPos, float yPos, float zPos); - -// Stops playing every sound. -// -// This will stop all voices that are attached to the world's playback deviecs, including those that are not attached to a dra_sound object. -void dra_sound_world_stop_all_sounds(dra_sound_world* pWorld); - - -// Sets the position of the listener for 3D effects. -// -// This is placeholder. -void dra_sound_world_set_listener_position(dra_sound_world* pWorld, float xPos, float yPos, float zPos); - -// Sets the orientation of the listener for 3D effects. -// -// This is placeholder. -void dra_sound_world_set_listener_orientation(dra_sound_world* pWorld, float xForward, float yForward, float zForward, float xUp, float yUp, float zUp); - - - - -// dra_sound_create() -// -// The datails in "desc" can be accessed from the returned object directly. -// -// This uses the pUserData member of the internal voice. Do not overwrite this. Instead, use the pUserData member of -// the returned dra_sound object. -dra_sound* dra_sound_create(dra_sound_world* pWorld, dra_sound_desc* pDesc); - -#ifndef DR_AUDIO_NO_STDIO -// dra_sound_create_from_file() -// -// This will hold a handle to the file for the life of the sound. -dra_sound* dra_sound_create_from_file(dra_sound_world* pWorld, const char* filePath); -#endif - -// dra_sound_delete() -void dra_sound_delete(dra_sound* pSound); - - -// dra_sound_play() -void dra_sound_play(dra_sound* pSound, dr_bool32 loop); - -// dra_sound_stop() -void dra_sound_stop(dra_sound* pSound); - - -// Attaches the given sound to the given mixer. -// -// Setting pMixer to null will detach the sound from the mixer it is currently attached to and attach it -// to the master mixer. -void dra_sound_attach_to_mixer(dra_sound* pSound, dra_mixer* pMixer); - - -// dra_sound_set_on_stop() -void dra_sound_set_on_stop(dra_sound* pSound, dra_event_proc proc, void* pUserData); - -// dra_sound_set_on_play() -void dra_sound_set_on_play(dra_sound* pSound, dra_event_proc proc, void* pUserData); - - -#ifdef __cplusplus -} -#endif -#endif //dr_audio2_h - - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_AUDIO_IMPLEMENTATION -#include -#include -#include -#include // For good old printf debugging. Delete later. - -#ifdef _MSC_VER -#define DR_AUDIO_INLINE static __forceinline -#else -#define DR_AUDIO_INLINE static inline -#endif - -#define DR_AUDIO_DEFAULT_CHANNEL_COUNT 2 -#define DR_AUDIO_DEFAULT_SAMPLE_RATE 48000 -#define DR_AUDIO_DEFAULT_LATENCY 100 // Milliseconds. TODO: Test this with very low values. DirectSound appears to not signal the fragment events when it's too small. With values of about 20 it sounds crackly. -#define DR_AUDIO_DEFAULT_FRAGMENT_COUNT 3 // The hardware buffer is divided up into latency-sized blocks. This controls that number. Must be at least 2. - -#define DR_AUDIO_BACKEND_TYPE_NULL 0 -#define DR_AUDIO_BACKEND_TYPE_DSOUND 1 -#define DR_AUDIO_BACKEND_TYPE_ALSA 2 - -#ifdef dr_wav_h -#define DR_AUDIO_HAS_WAV - #ifndef DR_WAV_NO_STDIO - #define DR_AUDIO_HAS_WAV_STDIO - #endif -#endif -#ifdef dr_flac_h -#define DR_AUDIO_HAS_FLAC - #ifndef DR_FLAC_NO_STDIO - #define DR_AUDIO_HAS_FLAC_STDIO - #endif -#endif -#ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H -#define DR_AUDIO_HAS_VORBIS - #ifndef STB_VORBIS_NO_STDIO - #define DR_AUDIO_HAS_VORBIS_STDIO - #endif -#endif - -#if defined(DR_AUDIO_HAS_WAV) || \ - defined(DR_AUDIO_HAS_FLAC) || \ - defined(DR_AUDIO_HAS_VORBIS) -#define DR_AUDIO_HAS_EXTERNAL_DECODER -#endif - - -// Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 -DR_AUDIO_INLINE unsigned int dra_next_power_of_2(unsigned int x) -{ - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x++; - - return x; -} - -DR_AUDIO_INLINE unsigned int dra_prev_power_of_2(unsigned int x) -{ - return dra_next_power_of_2(x) >> 1; -} - - -DR_AUDIO_INLINE float dra_mixf(float x, float y, float a) -{ - return x*(1-a) + y*a; -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// Platform Specific -// -/////////////////////////////////////////////////////////////////////////////// - -// Every backend struct should begin with these properties. -struct dra_backend -{ -#define DR_AUDIO_BASE_BACKEND_ATTRIBS \ - unsigned int type; \ - - DR_AUDIO_BASE_BACKEND_ATTRIBS -}; - -// Every backend device struct should begin with these properties. -struct dra_backend_device -{ -#define DR_AUDIO_BASE_BACKEND_DEVICE_ATTRIBS \ - dra_backend* pBackend; \ - dra_device_type type; \ - unsigned int channels; \ - unsigned int sampleRate; \ - unsigned int fragmentCount; \ - unsigned int samplesPerFragment; \ - - DR_AUDIO_BASE_BACKEND_DEVICE_ATTRIBS -}; - - - - -// Compile-time platform detection and #includes. -#ifdef _WIN32 -#include - -//// Threading (Win32) //// -typedef DWORD (* dra_thread_entry_proc)(LPVOID pData); - -dra_thread dra_thread_create(dra_thread_entry_proc entryProc, void* pData) -{ - return (dra_thread)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)entryProc, pData, 0, NULL); -} - -void dra_thread_delete(dra_thread thread) -{ - CloseHandle((HANDLE)thread); -} - -void dra_thread_wait(dra_thread thread) -{ - WaitForSingleObject((HANDLE)thread, INFINITE); -} - - -dra_mutex dra_mutex_create() -{ - return (dra_mutex)CreateEventA(NULL, FALSE, TRUE, NULL); -} - -void dra_mutex_delete(dra_mutex mutex) -{ - CloseHandle((HANDLE)mutex); -} - -void dra_mutex_lock(dra_mutex mutex) -{ - WaitForSingleObject((HANDLE)mutex, INFINITE); -} - -void dra_mutex_unlock(dra_mutex mutex) -{ - SetEvent((HANDLE)mutex); -} - - -dra_semaphore dra_semaphore_create(int initialValue) -{ - return (void*)CreateSemaphoreA(NULL, initialValue, LONG_MAX, NULL); -} - -void dra_semaphore_delete(dra_semaphore semaphore) -{ - CloseHandle((HANDLE)semaphore); -} - -dr_bool32 dra_semaphore_wait(dra_semaphore semaphore) -{ - return WaitForSingleObject((HANDLE)semaphore, INFINITE) == WAIT_OBJECT_0; -} - -dr_bool32 dra_semaphore_release(dra_semaphore semaphore) -{ - return ReleaseSemaphore((HANDLE)semaphore, 1, NULL) != 0; -} - - - -//// DirectSound //// -#ifndef DR_AUDIO_NO_DSOUND -#define DR_AUDIO_ENABLE_DSOUND -#include -#include // WAVEFORMATEX - -GUID DR_AUDIO_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - -static GUID _g_draGUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; -static GUID _g_draGUID_IID_IDirectSoundCaptureBuffer8 = {0x00990df4, 0x0dbb, 0x4872, {0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6}}; -static GUID _g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - -#ifdef __cplusplus -static GUID g_draGUID_IID_DirectSoundNotify = _g_draGUID_IID_DirectSoundNotify; -static GUID g_draGUID_IID_IDirectSoundCaptureBuffer8 = _g_draGUID_IID_IDirectSoundCaptureBuffer8; -//static GUID g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = _g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; -#else -static GUID* g_draGUID_IID_DirectSoundNotify = &_g_draGUID_IID_DirectSoundNotify; -static GUID* g_draGUID_IID_IDirectSoundCaptureBuffer8 = &_g_draGUID_IID_IDirectSoundCaptureBuffer8; -//static GUID* g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = &_g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; -#endif - -typedef HRESULT (WINAPI * pDirectSoundCreate8Proc)(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter); -typedef HRESULT (WINAPI * pDirectSoundEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); -typedef HRESULT (WINAPI * pDirectSoundCaptureCreate8Proc)(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter); -typedef HRESULT (WINAPI * pDirectSoundCaptureEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); - -typedef struct -{ - DR_AUDIO_BASE_BACKEND_ATTRIBS - - // A handle to the dsound DLL for doing run-time linking. - HMODULE hDSoundDLL; - - pDirectSoundCreate8Proc pDirectSoundCreate8; - pDirectSoundEnumerateAProc pDirectSoundEnumerateA; - pDirectSoundCaptureCreate8Proc pDirectSoundCaptureCreate8; - pDirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA; -} dra_backend_dsound; - -typedef struct -{ - DR_AUDIO_BASE_BACKEND_DEVICE_ATTRIBS - - - // The main device object for use with DirectSound. - LPDIRECTSOUND8 pDS; - - // The DirectSound "primary buffer". It's basically just representing the connection between us and the hardware device. - LPDIRECTSOUNDBUFFER pDSPrimaryBuffer; - - // The DirectSound "secondary buffer". This is where the actual audio data will be written to by dr_audio when it's time - // to play back some audio through the speakers. This represents the hardware buffer. - LPDIRECTSOUNDBUFFER pDSSecondaryBuffer; - - - // The main capture device object for use with DirectSound. This is only used by capture devices and is created by DirectSoundCaptureCreate8(). - LPDIRECTSOUNDCAPTURE8 pDSCapture; - - // The capture buffer. This is where captured audio data will be placed. This is only used by capture devices. - LPDIRECTSOUNDCAPTUREBUFFER8 pDSCaptureBuffer; - - - // The notification object used by DirectSound to notify dr_audio that it's ready for the next fragment of audio data. - LPDIRECTSOUNDNOTIFY pDSNotify; - - // Notification events for each fragment. - HANDLE pNotifyEvents[DR_AUDIO_DEFAULT_FRAGMENT_COUNT]; - - // The event the main playback thread will wait on to determine whether or not the playback loop should terminate. - HANDLE hStopEvent; - - // The index of the fragment that is currently being played. - unsigned int currentFragmentIndex; - - // The address of the mapped fragment. This is set with IDirectSoundBuffer8::Lock() and passed to IDriectSoundBuffer8::Unlock(). - void* pLockPtr; - - // The size of the locked buffer. This is set with IDirectSoundBuffer8::Lock() and passed to IDriectSoundBuffer8::Unlock(). - DWORD lockSize; - -} dra_backend_device_dsound; - -typedef struct -{ - unsigned int deviceID; - unsigned int counter; - const GUID* pGuid; -} dra_dsound__device_enum_data; - -static BOOL CALLBACK dra_dsound__get_device_guid_by_id__callback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) -{ - (void)lpcstrDescription; - (void)lpcstrModule; - - dra_dsound__device_enum_data* pData = (dra_dsound__device_enum_data*)lpContext; - assert(pData != NULL); - - if (pData->counter == pData->deviceID) { - pData->pGuid = lpGuid; - return DR_FALSE; - } - - pData->counter += 1; - return DR_TRUE; -} - -const GUID* dra_dsound__get_playback_device_guid_by_id(dra_backend* pBackend, unsigned int deviceID) -{ - // From MSDN: - // - // The first device enumerated is always called the Primary Sound Driver, and the lpGUID parameter of the callback is - // NULL. This device represents the preferred output device set by the user in Control Panel. - if (deviceID == 0) { - return NULL; - } - - dra_backend_dsound* pBackendDS = (dra_backend_dsound*)pBackend; - if (pBackendDS == NULL) { - return NULL; - } - - // The device ID is treated as the device index. The actual ID for use by DirectSound is a GUID. We use DirectSoundEnumerateA() - // iterate over each device. This function is usually only going to be used during initialization time so it won't be a performance - // issue to not cache these. - dra_dsound__device_enum_data data = {0}; - data.deviceID = deviceID; - pBackendDS->pDirectSoundEnumerateA(dra_dsound__get_device_guid_by_id__callback, &data); - - return data.pGuid; -} - -const GUID* dra_dsound__get_capture_device_guid_by_id(dra_backend* pBackend, unsigned int deviceID) -{ - // From MSDN: - // - // The first device enumerated is always called the Primary Sound Driver, and the lpGUID parameter of the callback is - // NULL. This device represents the preferred output device set by the user in Control Panel. - if (deviceID == 0) { - return NULL; - } - - dra_backend_dsound* pBackendDS = (dra_backend_dsound*)pBackend; - if (pBackendDS == NULL) { - return NULL; - } - - // The device ID is treated as the device index. The actual ID for use by DirectSound is a GUID. We use DirectSoundEnumerateA() - // iterate over each device. This function is usually only going to be used during initialization time so it won't be a performance - // issue to not cache these. - dra_dsound__device_enum_data data = {0}; - data.deviceID = deviceID; - pBackendDS->pDirectSoundCaptureEnumerateA(dra_dsound__get_device_guid_by_id__callback, &data); - - return data.pGuid; -} - -dra_backend* dra_backend_create_dsound() -{ - dra_backend_dsound* pBackendDS = (dra_backend_dsound*)calloc(1, sizeof(*pBackendDS)); // <-- Note the calloc() - makes it easier to handle the on_error goto. - if (pBackendDS == NULL) { - return NULL; - } - - pBackendDS->type = DR_AUDIO_BACKEND_TYPE_DSOUND; - - pBackendDS->hDSoundDLL = LoadLibraryW(L"dsound.dll"); - if (pBackendDS->hDSoundDLL == NULL) { - goto on_error; - } - - pBackendDS->pDirectSoundCreate8 = (pDirectSoundCreate8Proc)GetProcAddress(pBackendDS->hDSoundDLL, "DirectSoundCreate8"); - if (pBackendDS->pDirectSoundCreate8 == NULL){ - goto on_error; - } - - pBackendDS->pDirectSoundEnumerateA = (pDirectSoundEnumerateAProc)GetProcAddress(pBackendDS->hDSoundDLL, "DirectSoundEnumerateA"); - if (pBackendDS->pDirectSoundEnumerateA == NULL){ - goto on_error; - } - - pBackendDS->pDirectSoundCaptureCreate8 = (pDirectSoundCaptureCreate8Proc)GetProcAddress(pBackendDS->hDSoundDLL, "DirectSoundCaptureCreate8"); - if (pBackendDS->pDirectSoundCaptureCreate8 == NULL){ - goto on_error; - } - - pBackendDS->pDirectSoundCaptureEnumerateA = (pDirectSoundCaptureEnumerateAProc)GetProcAddress(pBackendDS->hDSoundDLL, "DirectSoundCaptureEnumerateA"); - if (pBackendDS->pDirectSoundCaptureEnumerateA == NULL){ - goto on_error; - } - - - return (dra_backend*)pBackendDS; - -on_error: - if (pBackendDS != NULL) { - if (pBackendDS->hDSoundDLL != NULL) { - FreeLibrary(pBackendDS->hDSoundDLL); - } - - free(pBackendDS); - } - - return NULL; -} - -void dra_backend_delete_dsound(dra_backend* pBackend) -{ - dra_backend_dsound* pBackendDS = (dra_backend_dsound*)pBackend; - if (pBackendDS == NULL) { - return; - } - - if (pBackendDS->hDSoundDLL != NULL) { - FreeLibrary(pBackendDS->hDSoundDLL); - } - - free(pBackendDS); -} - -void dra_backend_device_close_dsound(dra_backend_device* pDevice) -{ - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)pDevice; - if (pDeviceDS == NULL) { - return; - } - - if (pDeviceDS->pDSNotify) IDirectSoundNotify_Release(pDeviceDS->pDSNotify); - - if (pDevice->type == dra_device_type_playback) { - if (pDeviceDS->pDSSecondaryBuffer) IDirectSoundBuffer_Release(pDeviceDS->pDSSecondaryBuffer); - if (pDeviceDS->pDSPrimaryBuffer) IDirectSoundBuffer_Release(pDeviceDS->pDSPrimaryBuffer); - if (pDeviceDS->pDS) IDirectSound_Release(pDeviceDS->pDS); - } else { - if (pDeviceDS->pDSCaptureBuffer) IDirectSoundCaptureBuffer_Release(pDeviceDS->pDSCaptureBuffer); - if (pDeviceDS->pDSCapture) IDirectSoundCapture_Release(pDeviceDS->pDSCapture); - } - - - for (int i = 0; i < DR_AUDIO_DEFAULT_FRAGMENT_COUNT; ++i) { - CloseHandle(pDeviceDS->pNotifyEvents[i]); - } - - if (pDeviceDS->hStopEvent != NULL) { - CloseHandle(pDeviceDS->hStopEvent); - } - - free(pDeviceDS); -} - -dra_backend_device* dra_backend_device_open_playback_dsound(dra_backend* pBackend, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - // These are declared at the top to stop compilations errors on GCC about goto statements skipping over variable initialization. - HRESULT hr; - WAVEFORMATEXTENSIBLE* actualFormat; - unsigned int sampleRateInMilliseconds; - unsigned int proposedFramesPerFragment; - unsigned int framesPerFragment; - size_t fragmentSize; - size_t hardwareBufferSize; - - dra_backend_dsound* pBackendDS = (dra_backend_dsound*)pBackend; - if (pBackendDS == NULL) { - return NULL; - } - - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)calloc(1, sizeof(*pDeviceDS)); - if (pDeviceDS == NULL) { - goto on_error; - } - - if (channels == 0) { - channels = DR_AUDIO_DEFAULT_CHANNEL_COUNT; - } - - pDeviceDS->pBackend = pBackend; - pDeviceDS->type = dra_device_type_playback; - pDeviceDS->channels = channels; - pDeviceDS->sampleRate = sampleRate; - - hr = pBackendDS->pDirectSoundCreate8(dra_dsound__get_playback_device_guid_by_id(pBackend, deviceID), &pDeviceDS->pDS, NULL); - if (FAILED(hr)) { - goto on_error; - } - - // The cooperative level must be set before doing anything else. - hr = IDirectSound_SetCooperativeLevel(pDeviceDS->pDS, GetForegroundWindow(), DSSCL_PRIORITY); - if (FAILED(hr)) { - goto on_error; - } - - - // The primary buffer is basically just the connection to the hardware. - DSBUFFERDESC descDSPrimary; - memset(&descDSPrimary, 0, sizeof(DSBUFFERDESC)); - descDSPrimary.dwSize = sizeof(DSBUFFERDESC); - descDSPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; - - hr = IDirectSound_CreateSoundBuffer(pDeviceDS->pDS, &descDSPrimary, &pDeviceDS->pDSPrimaryBuffer, NULL); - if (FAILED(hr)) { - goto on_error; - } - - - // If the channel count is 0 then we need to use the default. From MSDN: - // - // The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest - // supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer - // and compare the result with the format that was requested with the SetFormat method. - WAVEFORMATEXTENSIBLE wf; - memset(&wf, 0, sizeof(wf)); - wf.Format.cbSize = sizeof(wf); - wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.Format.nChannels = (WORD)channels; - wf.Format.nSamplesPerSec = (DWORD)sampleRate; - wf.Format.wBitsPerSample = sizeof(float)*8; - wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; - wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; - wf.dwChannelMask = 0; - wf.SubFormat = _g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - if (channels > 2) { - wf.dwChannelMask = ~(((DWORD)-1) << channels); - } - - hr = IDirectSoundBuffer_SetFormat(pDeviceDS->pDSPrimaryBuffer, (WAVEFORMATEX*)&wf); - if (FAILED(hr)) { - goto on_error; - } - - - // Get the ACTUAL properties of the buffer. This is silly API design... - DWORD requiredSize; - hr = IDirectSoundBuffer_GetFormat(pDeviceDS->pDSPrimaryBuffer, NULL, 0, &requiredSize); - if (FAILED(hr)) { - goto on_error; - } - - char rawdata[1024]; - actualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; - hr = IDirectSoundBuffer_GetFormat(pDeviceDS->pDSPrimaryBuffer, (WAVEFORMATEX*)actualFormat, requiredSize, NULL); - if (FAILED(hr)) { - goto on_error; - } - - pDeviceDS->channels = actualFormat->Format.nChannels; - pDeviceDS->sampleRate = actualFormat->Format.nSamplesPerSec; - - // DirectSound always has the same number of fragments. - pDeviceDS->fragmentCount = DR_AUDIO_DEFAULT_FRAGMENT_COUNT; - - - // The secondary buffer is the buffer where the real audio data will be written to and used by the hardware device. It's - // size is based on the latency, sample rate and channels. - // - // The format of the secondary buffer should exactly match the primary buffer as to avoid unnecessary data conversions. - sampleRateInMilliseconds = pDeviceDS->sampleRate / 1000; - if (sampleRateInMilliseconds == 0) { - sampleRateInMilliseconds = 1; - } - - // The size of a fragment is sized such that the number of frames contained within it is a multiple of 2. The reason for - // this is to keep it consistent with the ALSA backend. - proposedFramesPerFragment = sampleRateInMilliseconds * latencyInMilliseconds; - framesPerFragment = dra_prev_power_of_2(proposedFramesPerFragment); - if (framesPerFragment == 0) { - framesPerFragment = 2; - } - - pDeviceDS->samplesPerFragment = framesPerFragment * pDeviceDS->channels; - - fragmentSize = pDeviceDS->samplesPerFragment * sizeof(float); - hardwareBufferSize = fragmentSize * pDeviceDS->fragmentCount; - assert(hardwareBufferSize > 0); // <-- If you've triggered this is means you've got something set to 0. You haven't been setting that latency to 0 have you?! That's not allowed! - - // Meaning of dwFlags (from MSDN): - // - // DSBCAPS_CTRLPOSITIONNOTIFY - // The buffer has position notification capability. - // - // DSBCAPS_GLOBALFOCUS - // With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to - // another application, even if the new application uses DirectSound. - // - // DSBCAPS_GETCURRENTPOSITION2 - // In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated - // sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the - // application can get a more accurate play cursor. - DSBUFFERDESC descDS; - memset(&descDS, 0, sizeof(DSBUFFERDESC)); - descDS.dwSize = sizeof(DSBUFFERDESC); - descDS.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; - descDS.dwBufferBytes = (DWORD)hardwareBufferSize; - descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; - hr = IDirectSound_CreateSoundBuffer(pDeviceDS->pDS, &descDS, &pDeviceDS->pDSSecondaryBuffer, NULL); - if (FAILED(hr)) { - goto on_error; - } - - - // As DirectSound is playing back the hardware buffer it needs to notify dr_audio when it's ready for new data. This is done - // through a notification object which we retrieve from the secondary buffer. - hr = IDirectSoundBuffer8_QueryInterface(pDeviceDS->pDSSecondaryBuffer, g_draGUID_IID_DirectSoundNotify, (void**)&pDeviceDS->pDSNotify); - if (FAILED(hr)) { - goto on_error; - } - - DSBPOSITIONNOTIFY notifyPoints[DR_AUDIO_DEFAULT_FRAGMENT_COUNT]; // One notification event for each fragment. - for (int i = 0; i < DR_AUDIO_DEFAULT_FRAGMENT_COUNT; ++i) - { - pDeviceDS->pNotifyEvents[i] = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDeviceDS->pNotifyEvents[i] == NULL) { - goto on_error; - } - - notifyPoints[i].dwOffset = (DWORD)(i * fragmentSize); // <-- This is in bytes. - notifyPoints[i].hEventNotify = pDeviceDS->pNotifyEvents[i]; - } - - hr = IDirectSoundNotify_SetNotificationPositions(pDeviceDS->pDSNotify, DR_AUDIO_DEFAULT_FRAGMENT_COUNT, notifyPoints); - if (FAILED(hr)) { - goto on_error; - } - - - - // The termination event is used to determine when the playback thread should be terminated. The playback thread - // will wait on this event in addition to the notification events in it's main loop. - pDeviceDS->hStopEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDeviceDS->hStopEvent == NULL) { - goto on_error; - } - - return (dra_backend_device*)pDeviceDS; - -on_error: - dra_backend_device_close_dsound((dra_backend_device*)pDeviceDS); - return NULL; -} - -dra_backend_device* dra_backend_device_open_capture_dsound(dra_backend* pBackend, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - (void)latencyInMilliseconds; - - HRESULT hr; - unsigned int sampleRateInMilliseconds; - unsigned int proposedFramesPerFragment; - unsigned int framesPerFragment; - size_t fragmentSize; - size_t hardwareBufferSize; - - dra_backend_dsound* pBackendDS = (dra_backend_dsound*)pBackend; - if (pBackendDS == NULL) { - return NULL; - } - - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)calloc(1, sizeof(*pDeviceDS)); - if (pDeviceDS == NULL) { - goto on_error; - } - - if (channels == 0) { - channels = DR_AUDIO_DEFAULT_CHANNEL_COUNT; - } - - pDeviceDS->pBackend = pBackend; - pDeviceDS->type = dra_device_type_capture; - pDeviceDS->channels = channels; - pDeviceDS->sampleRate = sampleRate; - - hr = pBackendDS->pDirectSoundCaptureCreate8(dra_dsound__get_capture_device_guid_by_id(pBackend, deviceID), &pDeviceDS->pDSCapture, NULL); - if (FAILED(hr)) { - goto on_error; - } - - pDeviceDS->fragmentCount = DR_AUDIO_DEFAULT_FRAGMENT_COUNT; - - // The secondary buffer is the buffer where the real audio data will be written to and used by the hardware device. It's - // size is based on the latency, sample rate and channels. - // - // The format of the secondary buffer should exactly match the primary buffer as to avoid unnecessary data conversions. - sampleRateInMilliseconds = pDeviceDS->sampleRate / 1000; - if (sampleRateInMilliseconds == 0) { - sampleRateInMilliseconds = 1; - } - - // The size of a fragment is sized such that the number of frames contained within it is a multiple of 2. The reason for - // this is to keep it consistent with the ALSA backend. - proposedFramesPerFragment = sampleRateInMilliseconds * latencyInMilliseconds; - framesPerFragment = dra_prev_power_of_2(proposedFramesPerFragment); - if (framesPerFragment == 0) { - framesPerFragment = 2; - } - - pDeviceDS->samplesPerFragment = framesPerFragment * pDeviceDS->channels; - - fragmentSize = pDeviceDS->samplesPerFragment * sizeof(float); - hardwareBufferSize = fragmentSize * pDeviceDS->fragmentCount; - assert(hardwareBufferSize > 0); // <-- If you've triggered this is means you've got something set to 0. You haven't been setting that latency to 0 have you?! That's not allowed! - - - WAVEFORMATEXTENSIBLE wf; - memset(&wf, 0, sizeof(wf)); - wf.Format.cbSize = sizeof(wf); - wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.Format.nChannels = (WORD)channels; - wf.Format.nSamplesPerSec = (DWORD)sampleRate; - wf.Format.wBitsPerSample = sizeof(float)*8; - wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; - wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; - wf.dwChannelMask = 0; - wf.SubFormat = _g_draGUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - if (channels > 2) { - wf.dwChannelMask = ~(((DWORD)-1) << channels); - } - - DSCBUFFERDESC descDS; - memset(&descDS, 0, sizeof(descDS)); - descDS.dwSize = sizeof(descDS); - descDS.dwFlags = 0; - descDS.dwBufferBytes = (DWORD)hardwareBufferSize; - descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; - - LPDIRECTSOUNDCAPTUREBUFFER pDSCB_Temp; - hr = IDirectSoundCapture_CreateCaptureBuffer(pDeviceDS->pDSCapture, &descDS, &pDSCB_Temp, NULL); - if (FAILED(hr)) { - goto on_error; - } - - hr = IDirectSoundCapture_QueryInterface(pDSCB_Temp, g_draGUID_IID_IDirectSoundCaptureBuffer8, (LPVOID*)&pDeviceDS->pDSCaptureBuffer); - IDirectSoundCaptureBuffer_Release(pDSCB_Temp); - if (FAILED(hr)) { - goto on_error; // Failed to retrieve the DirectSoundCaptureBuffer8 interface. - } - - - // As DirectSound is playing back the hardware buffer it needs to notify dr_audio when it's ready for new data. This is done - // through a notification object which we retrieve from the secondary buffer. - hr = IDirectSoundCaptureBuffer8_QueryInterface(pDeviceDS->pDSCaptureBuffer, g_draGUID_IID_DirectSoundNotify, (void**)&pDeviceDS->pDSNotify); - if (FAILED(hr)) { - goto on_error; - } - - DSBPOSITIONNOTIFY notifyPoints[DR_AUDIO_DEFAULT_FRAGMENT_COUNT]; // One notification event for each fragment. - for (int i = 0; i < DR_AUDIO_DEFAULT_FRAGMENT_COUNT; ++i) - { - pDeviceDS->pNotifyEvents[i] = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDeviceDS->pNotifyEvents[i] == NULL) { - goto on_error; - } - - notifyPoints[i].dwOffset = (DWORD)(((i+1) * fragmentSize) % hardwareBufferSize); // <-- This is in bytes. - notifyPoints[i].hEventNotify = pDeviceDS->pNotifyEvents[i]; - } - - hr = IDirectSoundNotify_SetNotificationPositions(pDeviceDS->pDSNotify, DR_AUDIO_DEFAULT_FRAGMENT_COUNT, notifyPoints); - if (FAILED(hr)) { - goto on_error; - } - - - // The termination event is used to determine when the capture thread should be terminated. This thread - // will wait on this event in addition to the notification events in it's main loop. - pDeviceDS->hStopEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDeviceDS->hStopEvent == NULL) { - goto on_error; - } - - return (dra_backend_device*)pDeviceDS; - -on_error: - dra_backend_device_close_dsound((dra_backend_device*)pDeviceDS); - return NULL; -} - -dra_backend_device* dra_backend_device_open_dsound(dra_backend* pBackend, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - if (type == dra_device_type_playback) { - return dra_backend_device_open_playback_dsound(pBackend, deviceID, channels, sampleRate, latencyInMilliseconds); - } else { - return dra_backend_device_open_capture_dsound(pBackend, deviceID, channels, sampleRate, latencyInMilliseconds); - } -} - -void dra_backend_device_play(dra_backend_device* pDevice) -{ - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)pDevice; - if (pDeviceDS == NULL) { - return; - } - - if (pDevice->type == dra_device_type_playback) { - IDirectSoundBuffer_Play(pDeviceDS->pDSSecondaryBuffer, 0, 0, DSBPLAY_LOOPING); - } else { - IDirectSoundCaptureBuffer8_Start(pDeviceDS->pDSCaptureBuffer, DSCBSTART_LOOPING); - } -} - -void dra_backend_device_stop(dra_backend_device* pDevice) -{ - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)pDevice; - if (pDeviceDS == NULL) { - return; - } - - if (pDevice->type == dra_device_type_playback) { - // Don't do anything if the buffer is not already playing. - DWORD status; - IDirectSoundBuffer_GetStatus(pDeviceDS->pDSSecondaryBuffer, &status); - if ((status & DSBSTATUS_PLAYING) == 0) { - return; // The buffer is already stopped. - } - - // Stop the playback straight away to ensure output to the hardware device is stopped as soon as possible. - IDirectSoundBuffer_Stop(pDeviceDS->pDSSecondaryBuffer); - IDirectSoundBuffer_SetCurrentPosition(pDeviceDS->pDSSecondaryBuffer, 0); - } else { - // Don't do anything if the buffer is not already playing. - DWORD status; - IDirectSoundCaptureBuffer8_GetStatus(pDeviceDS->pDSCaptureBuffer, &status); - if ((status & DSBSTATUS_PLAYING) == 0) { - return; // The buffer is already stopped. - } - - // Stop capture straight away to ensure output to the hardware device is stopped as soon as possible. - //IDirectSoundCaptureBuffer8_Stop(pDeviceDS->pDSCaptureBuffer); // <-- There's actually a typo in my version of dsound.h which trigger's a compilation error here. The call below is safe, albeit slightly less intuitive. - IDirectSoundCaptureBuffer_Stop(pDeviceDS->pDSCaptureBuffer); - } - - // Now we just need to make dra_backend_device_play() return which in the case of DirectSound we do by - // simply signaling the stop event. - SetEvent(pDeviceDS->hStopEvent); -} - -dr_bool32 dra_backend_device_wait(dra_backend_device* pDevice) // <-- Returns DR_TRUE if the function has returned because it needs more data; DR_FALSE if the device has been stopped or an error has occured. -{ - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)pDevice; - if (pDeviceDS == NULL) { - return DR_FALSE; - } - - unsigned int eventCount = DR_AUDIO_DEFAULT_FRAGMENT_COUNT + 1; - HANDLE eventHandles[DR_AUDIO_DEFAULT_FRAGMENT_COUNT + 1]; // +1 for the stop event. - memcpy(eventHandles, pDeviceDS->pNotifyEvents, sizeof(HANDLE) * DR_AUDIO_DEFAULT_FRAGMENT_COUNT); - eventHandles[DR_AUDIO_DEFAULT_FRAGMENT_COUNT] = pDeviceDS->hStopEvent; - - DWORD rc = WaitForMultipleObjects(DR_AUDIO_DEFAULT_FRAGMENT_COUNT + 1, eventHandles, FALSE, INFINITE); - if (rc >= WAIT_OBJECT_0 && rc < eventCount) - { - unsigned int eventIndex = rc - WAIT_OBJECT_0; - HANDLE hEvent = eventHandles[eventIndex]; - - // Has the device been stopped? If so, need to return DR_FALSE. - if (hEvent == pDeviceDS->hStopEvent) { - return DR_FALSE; - } - - // If we get here it means the event that's been signaled represents a fragment. - pDeviceDS->currentFragmentIndex = eventIndex; - return DR_TRUE; - } - - return DR_FALSE; -} - -void* dra_backend_device_map_next_fragment(dra_backend_device* pDevice, size_t* pSamplesInFragmentOut) -{ - assert(pSamplesInFragmentOut != NULL); - - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)pDevice; - if (pDeviceDS == NULL) { - return NULL; - } - - if (pDeviceDS->pLockPtr != NULL) { - return NULL; // A fragment is already mapped. Can only have a single fragment mapped at a time. - } - - if (pDevice->type == dra_device_type_playback) { - // If the device is not currently playing, we just return the first fragment. Otherwise we return the fragment that's sitting just past the - // one that's currently playing. - DWORD dwOffset = 0; - DWORD dwBytes = pDeviceDS->samplesPerFragment * sizeof(float); - - DWORD status; - IDirectSoundBuffer_GetStatus(pDeviceDS->pDSSecondaryBuffer, &status); - if ((status & DSBSTATUS_PLAYING) != 0) { - dwOffset = (((pDeviceDS->currentFragmentIndex + 1) % pDeviceDS->fragmentCount) * pDeviceDS->samplesPerFragment) * sizeof(float); - } - - HRESULT hr = IDirectSoundBuffer_Lock(pDeviceDS->pDSSecondaryBuffer, dwOffset, dwBytes, &pDeviceDS->pLockPtr, &pDeviceDS->lockSize, NULL, NULL, 0); - if (FAILED(hr)) { - return NULL; - } - } else { - DWORD dwOffset = (pDeviceDS->currentFragmentIndex * pDeviceDS->samplesPerFragment) * sizeof(float); - DWORD dwBytes = pDeviceDS->samplesPerFragment * sizeof(float); - - HRESULT hr = IDirectSoundCaptureBuffer8_Lock(pDeviceDS->pDSCaptureBuffer, dwOffset, dwBytes, &pDeviceDS->pLockPtr, &pDeviceDS->lockSize, NULL, NULL, 0); - if (FAILED(hr)) { - return NULL; - } - } - - *pSamplesInFragmentOut = pDeviceDS->samplesPerFragment; - return pDeviceDS->pLockPtr; -} - -void dra_backend_device_unmap_next_fragment(dra_backend_device* pDevice) -{ - dra_backend_device_dsound* pDeviceDS = (dra_backend_device_dsound*)pDevice; - if (pDeviceDS == NULL) { - return; - } - - if (pDeviceDS->pLockPtr == NULL) { - return; // Nothing is mapped. - } - - if (pDevice->type == dra_device_type_playback) { - IDirectSoundBuffer_Unlock(pDeviceDS->pDSSecondaryBuffer, pDeviceDS->pLockPtr, pDeviceDS->lockSize, NULL, 0); - } else { - IDirectSoundCaptureBuffer8_Unlock(pDeviceDS->pDSCaptureBuffer, pDeviceDS->pLockPtr, pDeviceDS->lockSize, NULL, 0); - } - - pDeviceDS->pLockPtr = NULL; - pDeviceDS->lockSize = 0; -} -#endif // DR_AUDIO_NO_SOUND -#endif // _WIN32 - -#ifdef __linux__ -#include -#include -#include -#include -#include -#include - -//// Threading (POSIX) //// -typedef void* (* dra_thread_entry_proc)(void* pData); - -dra_thread dra_thread_create(dra_thread_entry_proc entryProc, void* pData) -{ - pthread_t thread; - if (pthread_create(&thread, NULL, entryProc, pData) != 0) { - return NULL; - } - - return (dra_thread)thread; -} - -void dra_thread_delete(dra_thread thread) -{ - (void)thread; -} - -void dra_thread_wait(dra_thread thread) -{ - pthread_join((pthread_t)thread, NULL); -} - - -dra_mutex dra_mutex_create() -{ - // The pthread_mutex_t object is not a void* castable handle type. Just create it on the heap and be done with it. - pthread_mutex_t* mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); - if (pthread_mutex_init(mutex, NULL) != 0) { - free(mutex); - mutex = NULL; - } - - return mutex; -} - -void dra_mutex_delete(dra_mutex mutex) -{ - pthread_mutex_destroy((pthread_mutex_t*)mutex); -} - -void dra_mutex_lock(dra_mutex mutex) -{ - pthread_mutex_lock((pthread_mutex_t*)mutex); -} - -void dra_mutex_unlock(dra_mutex mutex) -{ - pthread_mutex_unlock((pthread_mutex_t*)mutex); -} - - -dra_semaphore dra_semaphore_create(int initialValue) -{ - sem_t* semaphore = (sem_t*)malloc(sizeof(sem_t)); - if (sem_init(semaphore, 0, (unsigned int)initialValue) == -1) { - free(semaphore); - semaphore = NULL; - } - - return (dra_semaphore)semaphore; -} - -void dra_semaphore_delete(dra_semaphore semaphore) -{ - sem_close((sem_t*)semaphore); -} - -dr_bool32 dra_semaphore_wait(dra_semaphore semaphore) -{ - return sem_wait((sem_t*)semaphore) != -1; -} - -dr_bool32 dra_semaphore_release(dra_semaphore semaphore) -{ - return sem_post((sem_t*)semaphore) != -1; -} - - -//// ALSA //// - -#ifndef DR_AUDIO_NO_ALSA -#define DR_AUDIO_ENABLE_ALSA -#include - -typedef struct -{ - DR_AUDIO_BASE_BACKEND_ATTRIBS - - int unused; -} dra_backend_alsa; - -typedef struct -{ - DR_AUDIO_BASE_BACKEND_DEVICE_ATTRIBS - - // The ALSA device handle. - snd_pcm_t* deviceALSA; - - // Whether or not the device is currently playing. - dr_bool32 isPlaying; - - // Whether or not the intermediary buffer is mapped. - dr_bool32 isBufferMapped; - - // The intermediary buffer where audio data is written before being submitted to the device. - float* pIntermediaryBuffer; -} dra_backend_device_alsa; - - -static dr_bool32 dra_alsa__get_device_name_by_id(dra_backend* pBackend, unsigned int deviceID, char* deviceNameOut) -{ - assert(pBackend != NULL); - assert(deviceNameOut != NULL); - - deviceNameOut[0] = '\0'; // Safety. - - if (deviceID == 0) { - strcpy(deviceNameOut, "default"); - return DR_TRUE; - } - - - unsigned int iDevice = 0; - - char** deviceHints; - if (snd_device_name_hint(-1, "pcm", (void***)&deviceHints) < 0) { - //printf("Failed to iterate devices."); - return -1; - } - - char** nextDeviceHint = deviceHints; - while (*nextDeviceHint != NULL && iDevice < deviceID) { - nextDeviceHint += 1; - iDevice += 1; - } - - dr_bool32 result = DR_FALSE; - if (iDevice == deviceID) { - strcpy(deviceNameOut, snd_device_name_get_hint(*nextDeviceHint, "NAME")); - result = DR_TRUE; - } - - snd_device_name_free_hint((void**)deviceHints); - - - return result; -} - - -dra_backend* dra_backend_create_alsa() -{ - dra_backend_alsa* pBackendALSA = (dra_backend_alsa*)calloc(1, sizeof(*pBackendALSA)); // <-- Note the calloc() - makes it easier to handle the on_error goto. - if (pBackendALSA == NULL) { - return NULL; - } - - pBackendALSA->type = DR_AUDIO_BACKEND_TYPE_ALSA; - - - return (dra_backend*)pBackendALSA; - -#if 0 -on_error: - if (pBackendALSA != NULL) { - free(pBackendALSA); - } - - return NULL; -#endif -} - -void dra_backend_delete_alsa(dra_backend* pBackend) -{ - dra_backend_alsa* pBackendALSA = (dra_backend_alsa*)pBackend; - if (pBackendALSA == NULL) { - return; - } - - free(pBackend); -} - - -void dra_backend_device_close_alsa(dra_backend_device* pDevice) -{ - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)pDevice; - if (pDeviceALSA == NULL) { - return; - } - - if (pDeviceALSA->deviceALSA != NULL) { - snd_pcm_close(pDeviceALSA->deviceALSA); - } - - free(pDeviceALSA->pIntermediaryBuffer); - free(pDeviceALSA); -} - -dra_backend_device* dra_backend_device_open_playback_alsa(dra_backend* pBackend, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - unsigned int periods; - int dir; - size_t sampleRateInMilliseconds; - unsigned int proposedFramesPerFragment; - unsigned int framesPerFragment; - snd_pcm_sw_params_t* pSWParams; - - dra_backend_alsa* pBackendALSA = (dra_backend_alsa*)pBackend; - if (pBackendALSA == NULL) { - return NULL; - } - - snd_pcm_hw_params_t* pHWParams = NULL; - - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)calloc(1, sizeof(*pDeviceALSA)); - if (pDeviceALSA == NULL) { - goto on_error; - } - - pDeviceALSA->pBackend = pBackend; - pDeviceALSA->type = dra_device_type_playback; - pDeviceALSA->channels = channels; - pDeviceALSA->sampleRate = sampleRate; - - char deviceName[1024]; - if (!dra_alsa__get_device_name_by_id(pBackend, deviceID, deviceName)) { // <-- This will return "default" if deviceID is 0. - goto on_error; - } - - if (snd_pcm_open(&pDeviceALSA->deviceALSA, deviceName, SND_PCM_STREAM_PLAYBACK, 0) < 0) { - goto on_error; - } - - - if (snd_pcm_hw_params_malloc(&pHWParams) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_any(pDeviceALSA->deviceALSA, pHWParams) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_set_access(pDeviceALSA->deviceALSA, pHWParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_set_format(pDeviceALSA->deviceALSA, pHWParams, SND_PCM_FORMAT_FLOAT_LE) < 0) { - goto on_error; - } - - - if (snd_pcm_hw_params_set_rate_near(pDeviceALSA->deviceALSA, pHWParams, &sampleRate, 0) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_set_channels_near(pDeviceALSA->deviceALSA, pHWParams, &channels) < 0) { - goto on_error; - } - - pDeviceALSA->sampleRate = sampleRate; - pDeviceALSA->channels = channels; - - periods = DR_AUDIO_DEFAULT_FRAGMENT_COUNT; - dir = 1; - if (snd_pcm_hw_params_set_periods_near(pDeviceALSA->deviceALSA, pHWParams, &periods, &dir) < 0) { - //printf("Failed to set periods.\n"); - goto on_error; - } - - pDeviceALSA->fragmentCount = periods; - - //printf("Periods: %d | Direction: %d\n", periods, dir); - - - sampleRateInMilliseconds = pDeviceALSA->sampleRate / 1000; - if (sampleRateInMilliseconds == 0) { - sampleRateInMilliseconds = 1; - } - - - // According to the ALSA documentation, the value passed to snd_pcm_sw_params_set_avail_min() must be a power - // of 2 on some hardware. The value passed to this function is the size in frames of a fragment. Thus, to be - // as robust as possible the size of the hardware buffer should be sized based on the size of a closest power- - // of-two fragment. - // - // To calculate the size of a fragment, the first step is to determine the initial proposed size. From that - // it is dropped to the previous power of two. The reason for this is that, based on admittedly very basic - // testing, ALSA seems to have good latency characteristics, and less latency is always preferable. - proposedFramesPerFragment = sampleRateInMilliseconds * latencyInMilliseconds; - framesPerFragment = dra_prev_power_of_2(proposedFramesPerFragment); - if (framesPerFragment == 0) { - framesPerFragment = 2; - } - - pDeviceALSA->samplesPerFragment = framesPerFragment * pDeviceALSA->channels; - - if (snd_pcm_hw_params_set_buffer_size(pDeviceALSA->deviceALSA, pHWParams, framesPerFragment * pDeviceALSA->fragmentCount) < 0) { - //printf("Failed to set buffer size.\n"); - goto on_error; - } - - - if (snd_pcm_hw_params(pDeviceALSA->deviceALSA, pHWParams) < 0) { - goto on_error; - } - - snd_pcm_hw_params_free(pHWParams); - - - - // Software params. There needs to be at least fragmentSize bytes in the hardware buffer before playing it, and there needs - // be fragmentSize bytes available after every wait. - pSWParams = NULL; - if (snd_pcm_sw_params_malloc(&pSWParams) < 0) { - goto on_error; - } - - if (snd_pcm_sw_params_current(pDeviceALSA->deviceALSA, pSWParams) != 0) { - goto on_error; - } - - if (snd_pcm_sw_params_set_start_threshold(pDeviceALSA->deviceALSA, pSWParams, framesPerFragment) != 0) { - goto on_error; - } - if (snd_pcm_sw_params_set_avail_min(pDeviceALSA->deviceALSA, pSWParams, framesPerFragment) != 0) { - goto on_error; - } - - if (snd_pcm_sw_params(pDeviceALSA->deviceALSA, pSWParams) != 0) { - goto on_error; - } - snd_pcm_sw_params_free(pSWParams); - - - // The intermediary buffer that will be used for mapping/unmapping. - pDeviceALSA->isBufferMapped = DR_FALSE; - pDeviceALSA->pIntermediaryBuffer = (float*)malloc(pDeviceALSA->samplesPerFragment * sizeof(float)); - if (pDeviceALSA->pIntermediaryBuffer == NULL) { - goto on_error; - } - - return (dra_backend_device*)pDeviceALSA; - -on_error: - if (pHWParams) { - snd_pcm_hw_params_free(pHWParams); - } - - if (pDeviceALSA != NULL) { - if (pDeviceALSA->deviceALSA != NULL) { - snd_pcm_close(pDeviceALSA->deviceALSA); - } - - free(pDeviceALSA->pIntermediaryBuffer); - free(pDeviceALSA); - } - - return NULL; -} - -dra_backend_device* dra_backend_device_open_capture_alsa(dra_backend* pBackend, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - unsigned int periods; - int dir; - size_t sampleRateInMilliseconds; - unsigned int proposedFramesPerFragment; - unsigned int framesPerFragment; - snd_pcm_sw_params_t* pSWParams; - - dra_backend_alsa* pBackendALSA = (dra_backend_alsa*)pBackend; - if (pBackendALSA == NULL) { - return NULL; - } - - snd_pcm_hw_params_t* pHWParams = NULL; - - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)calloc(1, sizeof(*pDeviceALSA)); - if (pDeviceALSA == NULL) { - goto on_error; - } - - pDeviceALSA->pBackend = pBackend; - pDeviceALSA->type = dra_device_type_capture; - pDeviceALSA->channels = channels; - pDeviceALSA->sampleRate = sampleRate; - - char deviceName[1024]; - if (!dra_alsa__get_device_name_by_id(pBackend, deviceID, deviceName)) { // <-- This will return "default" if deviceID is 0. - goto on_error; - } - - if (snd_pcm_open(&pDeviceALSA->deviceALSA, deviceName, SND_PCM_STREAM_CAPTURE, 0) < 0) { - goto on_error; - } - - - if (snd_pcm_hw_params_malloc(&pHWParams) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_any(pDeviceALSA->deviceALSA, pHWParams) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_set_access(pDeviceALSA->deviceALSA, pHWParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_set_format(pDeviceALSA->deviceALSA, pHWParams, SND_PCM_FORMAT_FLOAT_LE) < 0) { - goto on_error; - } - - - if (snd_pcm_hw_params_set_rate_near(pDeviceALSA->deviceALSA, pHWParams, &sampleRate, 0) < 0) { - goto on_error; - } - - if (snd_pcm_hw_params_set_channels_near(pDeviceALSA->deviceALSA, pHWParams, &channels) < 0) { - goto on_error; - } - - pDeviceALSA->sampleRate = sampleRate; - pDeviceALSA->channels = channels; - - periods = DR_AUDIO_DEFAULT_FRAGMENT_COUNT; - dir = 1; - if (snd_pcm_hw_params_set_periods_near(pDeviceALSA->deviceALSA, pHWParams, &periods, &dir) < 0) { - //printf("Failed to set periods.\n"); - goto on_error; - } - - pDeviceALSA->fragmentCount = periods; - - //printf("Periods: %d | Direction: %d\n", periods, dir); - - - sampleRateInMilliseconds = pDeviceALSA->sampleRate / 1000; - if (sampleRateInMilliseconds == 0) { - sampleRateInMilliseconds = 1; - } - - - // According to the ALSA documentation, the value passed to snd_pcm_sw_params_set_avail_min() must be a power - // of 2 on some hardware. The value passed to this function is the size in frames of a fragment. Thus, to be - // as robust as possible the size of the hardware buffer should be sized based on the size of a closest power- - // of-two fragment. - // - // To calculate the size of a fragment, the first step is to determine the initial proposed size. From that - // it is dropped to the previous power of two. The reason for this is that, based on admittedly very basic - // testing, ALSA seems to have good latency characteristics, and less latency is always preferable. - proposedFramesPerFragment = sampleRateInMilliseconds * latencyInMilliseconds; - framesPerFragment = dra_prev_power_of_2(proposedFramesPerFragment); - if (framesPerFragment == 0) { - framesPerFragment = 2; - } - - pDeviceALSA->samplesPerFragment = framesPerFragment * pDeviceALSA->channels; - - if (snd_pcm_hw_params_set_buffer_size(pDeviceALSA->deviceALSA, pHWParams, framesPerFragment * pDeviceALSA->fragmentCount) < 0) { - //printf("Failed to set buffer size.\n"); - goto on_error; - } - - - if (snd_pcm_hw_params(pDeviceALSA->deviceALSA, pHWParams) < 0) { - goto on_error; - } - - snd_pcm_hw_params_free(pHWParams); - - - - // Software params. There needs to be at least fragmentSize bytes in the hardware buffer before playing it, and there needs - // be fragmentSize bytes available after every wait. - pSWParams = NULL; - if (snd_pcm_sw_params_malloc(&pSWParams) < 0) { - goto on_error; - } - - if (snd_pcm_sw_params_current(pDeviceALSA->deviceALSA, pSWParams) != 0) { - goto on_error; - } - - if (snd_pcm_sw_params_set_start_threshold(pDeviceALSA->deviceALSA, pSWParams, framesPerFragment) != 0) { - goto on_error; - } - if (snd_pcm_sw_params_set_avail_min(pDeviceALSA->deviceALSA, pSWParams, framesPerFragment) != 0) { - goto on_error; - } - - if (snd_pcm_sw_params(pDeviceALSA->deviceALSA, pSWParams) != 0) { - goto on_error; - } - snd_pcm_sw_params_free(pSWParams); - - // The intermediary buffer that will be used for mapping/unmapping. - pDeviceALSA->isBufferMapped = DR_FALSE; - pDeviceALSA->pIntermediaryBuffer = (float*)malloc(pDeviceALSA->samplesPerFragment * sizeof(float)); - if (pDeviceALSA->pIntermediaryBuffer == NULL) { - goto on_error; - } - - return (dra_backend_device*)pDeviceALSA; - -on_error: - dra_backend_device_close_alsa((dra_backend_device*)pDeviceALSA); - return NULL; -} - -dra_backend_device* dra_backend_device_open_alsa(dra_backend* pBackend, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - if (type == dra_device_type_playback) { - return dra_backend_device_open_playback_alsa(pBackend, deviceID, channels, sampleRate, latencyInMilliseconds); - } else { - return dra_backend_device_open_capture_alsa(pBackend, deviceID, channels, sampleRate, latencyInMilliseconds); - } -} - - -void dra_backend_device_play(dra_backend_device* pDevice) -{ - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)pDevice; - if (pDeviceALSA == NULL) { - return; - } - - snd_pcm_prepare(pDeviceALSA->deviceALSA); - pDeviceALSA->isPlaying = DR_TRUE; -} - -void dra_backend_device_stop(dra_backend_device* pDevice) -{ - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)pDevice; - if (pDeviceALSA == NULL) { - return; - } - - snd_pcm_drop(pDeviceALSA->deviceALSA); - pDeviceALSA->isPlaying = DR_FALSE; -} - -dr_bool32 dra_backend_device_wait(dra_backend_device* pDevice) -{ - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)pDevice; - if (pDeviceALSA == NULL) { - return DR_FALSE; - } - - if (!pDeviceALSA->isPlaying) { - return DR_FALSE; - } - - if (pDevice->type == dra_device_type_playback) { - int result = snd_pcm_wait(pDeviceALSA->deviceALSA, -1); - if (result > 0) { - return DR_TRUE; - } - - if (result == -EPIPE) { - // xrun. Prepare the device again and just return DR_TRUE. - snd_pcm_prepare(pDeviceALSA->deviceALSA); - return DR_TRUE; - } - } else { - snd_pcm_uframes_t frameCount = pDeviceALSA->samplesPerFragment / pDeviceALSA->channels; - snd_pcm_sframes_t framesRead = snd_pcm_readi(pDeviceALSA->deviceALSA, pDeviceALSA->pIntermediaryBuffer, frameCount); - if (framesRead > 0) { - return DR_TRUE; - } - - if (framesRead == -EPIPE) { - // xrun. Prepare the device again and just return DR_TRUE. - snd_pcm_prepare(pDeviceALSA->deviceALSA); - return DR_TRUE; - } - } - - return DR_FALSE; -} - -void* dra_backend_device_map_next_fragment(dra_backend_device* pDevice, size_t* pSamplesInFragmentOut) -{ - assert(pSamplesInFragmentOut != NULL); - - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)pDevice; - if (pDeviceALSA == NULL) { - return NULL; - } - - if (pDeviceALSA->isBufferMapped) { - return NULL; // A fragment is already mapped. Can only have a single fragment mapped at a time. - } - - //if (pDeviceALSA->type == dra_device_type_capture) { - // snd_pcm_readi(pDeviceALSA->deviceALSA, pDeviceALSA->pIntermediaryBuffer, pDeviceALSA->samplesPerFragment / pDeviceALSA->channels); - //} - - *pSamplesInFragmentOut = pDeviceALSA->samplesPerFragment; - return pDeviceALSA->pIntermediaryBuffer; -} - -void dra_backend_device_unmap_next_fragment(dra_backend_device* pDevice) -{ - dra_backend_device_alsa* pDeviceALSA = (dra_backend_device_alsa*)pDevice; - if (pDeviceALSA == NULL) { - return; - } - - if (pDeviceALSA->isBufferMapped) { - return; // Nothing is mapped. - } - - // Unammping is when the data is written to the device. - if (pDeviceALSA->type == dra_device_type_playback) { - snd_pcm_writei(pDeviceALSA->deviceALSA, pDeviceALSA->pIntermediaryBuffer, pDeviceALSA->samplesPerFragment / pDeviceALSA->channels); - } -} -#endif // DR_AUDIO_NO_ALSA -#endif // __linux__ - - -void dra_thread_wait_and_delete(dra_thread thread) -{ - dra_thread_wait(thread); - dra_thread_delete(thread); -} - - -dra_backend* dra_backend_create() -{ - dra_backend* pBackend = NULL; - -#ifdef DR_AUDIO_ENABLE_DSOUND - pBackend = dra_backend_create_dsound(); - if (pBackend != NULL) { - return pBackend; - } -#endif - -#ifdef DR_AUDIO_ENABLE_ALSA - pBackend = dra_backend_create_alsa(); - if (pBackend != NULL) { - return pBackend; - } -#endif - - // If we get here it means we couldn't find a backend. Default to a NULL backend? Returning NULL makes it clearer that an error occured. - return NULL; -} - -void dra_backend_delete(dra_backend* pBackend) -{ - if (pBackend == NULL) { - return; - } - -#ifdef DR_AUDIO_ENABLE_DSOUND - if (pBackend->type == DR_AUDIO_BACKEND_TYPE_DSOUND) { - dra_backend_delete_dsound(pBackend); - return; - } -#endif - -#ifdef DR_AUDIO_ENABLE_ALSA - if (pBackend->type == DR_AUDIO_BACKEND_TYPE_ALSA) { - dra_backend_delete_alsa(pBackend); - return; - } -#endif - - // Should never get here. If this assert is triggered it means you haven't plugged in the API in the list above. - assert(DR_FALSE); -} - - -dra_backend_device* dra_backend_device_open(dra_backend* pBackend, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds) -{ - if (pBackend == NULL) { - return NULL; - } - -#ifdef DR_AUDIO_ENABLE_DSOUND - if (pBackend->type == DR_AUDIO_BACKEND_TYPE_DSOUND) { - return dra_backend_device_open_dsound(pBackend, type, deviceID, channels, sampleRate, latencyInMilliseconds); - } -#endif - -#ifdef DR_AUDIO_ENABLE_ALSA - if (pBackend->type == DR_AUDIO_BACKEND_TYPE_ALSA) { - return dra_backend_device_open_alsa(pBackend, type, deviceID, channels, sampleRate, latencyInMilliseconds); - } -#endif - - - // Should never get here. If this assert is triggered it means you haven't plugged in the API in the list above. - assert(DR_FALSE); - return NULL; -} - -void dra_backend_device_close(dra_backend_device* pDevice) -{ - if (pDevice == NULL) { - return; - } - - assert(pDevice->pBackend != NULL); - -#ifdef DR_AUDIO_ENABLE_DSOUND - if (pDevice->pBackend->type == DR_AUDIO_BACKEND_TYPE_DSOUND) { - dra_backend_device_close_dsound(pDevice); - return; - } -#endif - -#ifdef DR_AUDIO_ENABLE_ALSA - if (pDevice->pBackend->type == DR_AUDIO_BACKEND_TYPE_ALSA) { - dra_backend_device_close_alsa(pDevice); - return; - } -#endif -} - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Cross Platform -// -/////////////////////////////////////////////////////////////////////////////// - -// Reads the next frame. -// -// Frames are retrieved with respect to the device the voice is attached to. What this basically means is -// that any data conversions will be done within this function. -// -// The return value is a pointer to the voice containing the converted samples, always as floating point. -// -// If the voice is in the same format as the device (floating point, same sample rate and channels), then -// this function will be on a fast path and will return almost immediately with a pointer that points to -// the voice's actual data without any data conversion. -// -// If an error occurs, null is returned. Null will be returned if the end of the voice's buffer is reached -// and it's non-looping. This will not return NULL if the voice is looping - it will just loop back to the -// start as one would expect. -// -// This function is not thread safe, but can be called from multiple threads if you do your own -// synchronization. Just keep in mind that the return value may point to the voice's actual internal data. -float* dra_voice__next_frame(dra_voice* pVoice); - -// dra_voice__next_frames() -size_t dra_voice__next_frames(dra_voice* pVoice, size_t frameCount, float* pSamplesOut); - - -dra_result dra_context_init(dra_context* pContext) -{ - if (pContext == NULL) return DRA_RESULT_INVALID_ARGS; - memset(pContext, 0, sizeof(*pContext)); - - // We need a backend first. - pContext->pBackend = dra_backend_create(); - if (pContext->pBackend == NULL) { - return DRA_RESULT_NO_BACKEND; // Failed to create a backend. - } - - return DRA_RESULT_SUCCESS; -} - -void dra_context_uninit(dra_context* pContext) -{ - if (pContext == NULL || pContext->pBackend == NULL) return; - dra_backend_delete(pContext->pBackend); -} - -dra_result dra_context_create(dra_context** ppContext) -{ - if (ppContext == NULL) return DRA_RESULT_INVALID_ARGS; - *ppContext = NULL; - - dra_context* pContext = (dra_context*)malloc(sizeof(*pContext)); - if (pContext == NULL) { - return DRA_RESULT_OUT_OF_MEMORY; - } - - dra_result result = dra_context_init(pContext); - if (result != DRA_RESULT_SUCCESS) { - free(pContext); - return result; - } - - *ppContext = pContext; - return DRA_RESULT_SUCCESS; -} - -void dra_context_delete(dra_context* pContext) -{ - if (pContext == NULL) return; - - dra_context_uninit(pContext); - free(pContext); -} - - -void dra_event_queue__schedule_event(dra__event_queue* pQueue, dra__event* pEvent) -{ - if (pQueue == NULL || pEvent == NULL) { - return; - } - - dra_mutex_lock(pQueue->lock); - { - if (pQueue->eventCount == pQueue->eventBufferSize) - { - // Ran out of room. Resize. - size_t newEventBufferSize = (pQueue->eventBufferSize == 0) ? 16 : pQueue->eventBufferSize*2; - dra__event* pNewEvents = (dra__event*)malloc(newEventBufferSize * sizeof(*pNewEvents)); - if (pNewEvents == NULL) { - return; - } - - for (size_t i = 0; i < pQueue->eventCount; ++i) { - pQueue->pEvents[i] = pQueue->pEvents[(pQueue->firstEvent + i) % pQueue->eventBufferSize]; - } - - pQueue->firstEvent = 0; - pQueue->eventBufferSize = newEventBufferSize; - pQueue->pEvents = pNewEvents; - } - - assert(pQueue->eventCount < pQueue->eventBufferSize); - - pQueue->pEvents[(pQueue->firstEvent + pQueue->eventCount) % pQueue->eventBufferSize] = *pEvent; - pQueue->eventCount += 1; - } - dra_mutex_unlock(pQueue->lock); -} - -void dra_event_queue__cancel_events_of_voice(dra__event_queue* pQueue, dra_voice* pVoice) -{ - if (pQueue == NULL || pVoice == NULL) { - return; - } - - dra_mutex_lock(pQueue->lock); - { - // We don't actually remove anything from the queue, but instead zero out the event's data. - for (size_t i = 0; i < pQueue->eventCount; ++i) { - dra__event* pEvent = &pQueue->pEvents[(pQueue->firstEvent + i) % pQueue->eventBufferSize]; - if (pEvent->pVoice == pVoice) { - pEvent->pVoice = NULL; - pEvent->proc = NULL; - } - } - } - dra_mutex_unlock(pQueue->lock); -} - -dr_bool32 dra_event_queue__next_event(dra__event_queue* pQueue, dra__event* pEventOut) -{ - if (pQueue == NULL || pEventOut == NULL) { - return DR_FALSE; - } - - dr_bool32 result = DR_FALSE; - dra_mutex_lock(pQueue->lock); - { - if (pQueue->eventCount > 0) { - *pEventOut = pQueue->pEvents[pQueue->firstEvent]; - pQueue->firstEvent = (pQueue->firstEvent + 1) % pQueue->eventBufferSize; - pQueue->eventCount -= 1; - result = DR_TRUE; - } - } - dra_mutex_unlock(pQueue->lock); - - return result; -} - -void dra_event_queue__post_events(dra__event_queue* pQueue) -{ - if (pQueue == NULL) { - return; - } - - dra__event nextEvent; - while (dra_event_queue__next_event(pQueue, &nextEvent)) { - if (nextEvent.proc) { - nextEvent.proc(nextEvent.id, nextEvent.pUserData); - } - } -} - - -void dra_device__post_event(dra_device* pDevice, dra_thread_event_type type) -{ - assert(pDevice != NULL); - - pDevice->nextThreadEventType = type; - dra_semaphore_release(pDevice->threadEventSem); -} - -void dra_device__lock(dra_device* pDevice) -{ - assert(pDevice != NULL); - dra_mutex_lock(pDevice->mutex); -} - -void dra_device__unlock(dra_device* pDevice) -{ - assert(pDevice != NULL); - dra_mutex_unlock(pDevice->mutex); -} - -dr_bool32 dra_device__is_playing_nolock(dra_device* pDevice) -{ - assert(pDevice != NULL); - return pDevice->isPlaying; -} - -dr_bool32 dra_device__mix_next_fragment(dra_device* pDevice) -{ - assert(pDevice != NULL); - - size_t samplesInFragment; - void* pSampleData = dra_backend_device_map_next_fragment(pDevice->pBackendDevice, &samplesInFragment); - if (pSampleData == NULL) { - dra_backend_device_stop(pDevice->pBackendDevice); - return DR_FALSE; - } - - size_t framesInFragment = samplesInFragment / pDevice->channels; - size_t framesMixed = dra_mixer_mix_next_frames(pDevice->pMasterMixer, framesInFragment); - - memcpy(pSampleData, pDevice->pMasterMixer->pStagingBuffer, (size_t)samplesInFragment * sizeof(float)); - - if (pDevice->onSamplesProcessed) { - pDevice->onSamplesProcessed(pDevice, framesMixed * pDevice->channels, (const float*)pSampleData, pDevice->pUserDataForOnSamplesProcessed); - } - - dra_backend_device_unmap_next_fragment(pDevice->pBackendDevice); - - if (framesMixed == 0) { - pDevice->stopOnNextFragment = DR_TRUE; - } - - //printf("Mixed next fragment into %p\n", pSampleData); - return DR_TRUE; -} - -void dra_device__play(dra_device* pDevice) -{ - assert(pDevice != NULL); - - dra_device__lock(pDevice); - { - // Don't do anything if the device is already playing. - if (!dra_device__is_playing_nolock(pDevice)) - { - assert(pDevice->pBackendDevice->type == dra_device_type_capture || pDevice->playingVoicesCount > 0); - - dra_device__post_event(pDevice, dra_thread_event_type_play); - pDevice->isPlaying = DR_TRUE; - pDevice->stopOnNextFragment = DR_FALSE; - } - } - dra_device__unlock(pDevice); -} - -void dra_device__stop(dra_device* pDevice) -{ - assert(pDevice != NULL); - - dra_device__lock(pDevice); - { - // Don't do anything if the device is already stopped. - if (dra_device__is_playing_nolock(pDevice)) - { - //assert(pDevice->playingVoicesCount == 0); - - dra_backend_device_stop(pDevice->pBackendDevice); - pDevice->isPlaying = DR_FALSE; - } - } - dra_device__unlock(pDevice); -} - -void dra_device__voice_playback_count_inc(dra_device* pDevice) -{ - assert(pDevice != NULL); - - dra_device__lock(pDevice); - { - pDevice->playingVoicesCount += 1; - pDevice->stopOnNextFragment = DR_FALSE; - } - dra_device__unlock(pDevice); -} - -void dra_device__voice_playback_count_dec(dra_device* pDevice) -{ - dra_device__lock(pDevice); - { - pDevice->playingVoicesCount -= 1; - } - dra_device__unlock(pDevice); -} - -// The entry point signature is slightly different depending on whether or not we're using Win32 or POSIX threads. -#ifdef _WIN32 -DWORD dra_device__thread_proc(LPVOID pData) -#else -void* dra_device__thread_proc(void* pData) -#endif -{ - dra_device* pDevice = (dra_device*)pData; - assert(pDevice != NULL); - - // The thread is always open for the life of the device. The loop below will only terminate when a terminate message is received. - for (;;) - { - // Wait for an event... - dra_semaphore_wait(pDevice->threadEventSem); - - if (pDevice->nextThreadEventType == dra_thread_event_type_terminate) { - //printf("Terminated!\n"); - break; - } - - if (pDevice->nextThreadEventType == dra_thread_event_type_play) - { - if (pDevice->pBackendDevice->type == dra_device_type_playback) { - // The backend device needs to start playing, but we first need to ensure it has an initial chunk of data available. - dra_device__mix_next_fragment(pDevice); - } - - // Start playing the backend device only after the initial fragment has been mixed, and only if it's a playback device. - dra_backend_device_play(pDevice->pBackendDevice); - - // There could be "play" events needing to be posted. - dra_event_queue__post_events(&pDevice->eventQueue); - - - // Wait for the device to request more data... - while (dra_backend_device_wait(pDevice->pBackendDevice)) { - dra_event_queue__post_events(&pDevice->eventQueue); - - if (pDevice->stopOnNextFragment) { - dra_device__stop(pDevice); // <-- Don't break from the loop here. Instead have dra_backend_device_wait() return naturally from the stop notification. - } else { - if (pDevice->pBackendDevice->type == dra_device_type_playback) { - dra_device__mix_next_fragment(pDevice); - } else { - size_t sampleCount; - void* pSampleData = dra_backend_device_map_next_fragment(pDevice->pBackendDevice, &sampleCount); - if (pSampleData != NULL) { - if (pDevice->onSamplesProcessed) { - pDevice->onSamplesProcessed(pDevice, sampleCount, (const float*)pSampleData, pDevice->pUserDataForOnSamplesProcessed); - } - - dra_backend_device_unmap_next_fragment(pDevice->pBackendDevice); - } - } - } - } - - // There could be some events needing to be posted. - dra_event_queue__post_events(&pDevice->eventQueue); - //printf("Stopped!\n"); - - // Don't fall through. - continue; - } - } - - return 0; -} - -dra_result dra_device_init_ex(dra_context* pContext, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds, dra_device* pDevice) -{ - if (pDevice == NULL) return DRA_RESULT_INVALID_ARGS; - - dr_bool32 ownsContext = DR_FALSE; - if (pContext == NULL) { - pContext = (dra_context*)malloc(sizeof(*pContext)); - if (pContext == NULL) { - return DRA_RESULT_OUT_OF_MEMORY; - } - - dra_result result = dra_context_init(pContext); - if (result != DRA_RESULT_SUCCESS) { - return result; - } - - ownsContext = DR_TRUE; - } - - if (sampleRate == 0) sampleRate = DR_AUDIO_DEFAULT_SAMPLE_RATE; - if (latencyInMilliseconds == 0) latencyInMilliseconds = DR_AUDIO_DEFAULT_LATENCY; - - - dra_result result = DRA_RESULT_SUCCESS; - - memset(pDevice, 0, sizeof(*pDevice)); - pDevice->pContext = pContext; - pDevice->ownsContext = ownsContext; - - pDevice->pBackendDevice = dra_backend_device_open(pContext->pBackend, type, deviceID, channels, sampleRate, latencyInMilliseconds); - if (pDevice->pBackendDevice == NULL) { - result = DRA_RESULT_NO_BACKEND_DEVICE; - goto on_error; - } - - pDevice->channels = pDevice->pBackendDevice->channels; - pDevice->sampleRate = pDevice->pBackendDevice->sampleRate; - - - pDevice->mutex = dra_mutex_create(); - if (pDevice->mutex == NULL) { - result = DRA_RESULT_UNKNOWN_ERROR; // TODO: Change this to the return value of dra_mutex_create(). - goto on_error; - } - - pDevice->threadEventSem = dra_semaphore_create(0); - if (pDevice->threadEventSem == NULL) { - result = DRA_RESULT_UNKNOWN_ERROR; // TODO: Change this to the return value of dra_semaphore_create(). - goto on_error; - } - - result = dra_mixer_create(pDevice, &pDevice->pMasterMixer); - if (result != DRA_RESULT_SUCCESS) { - goto on_error; - } - - - pDevice->eventQueue.lock = dra_mutex_create(); - if (pDevice->eventQueue.lock == NULL) { - result = DRA_RESULT_UNKNOWN_ERROR; // TODO: Change this to the return value of dra_mutex_create(). - goto on_error; - } - - - // Create the thread last to ensure the device is in a valid state as soon as the entry procedure is run. - pDevice->thread = dra_thread_create(dra_device__thread_proc, pDevice); - if (pDevice->thread == NULL) { - result = DRA_RESULT_UNKNOWN_ERROR; // TODO: Change this to the return value of dra_thread_create(). - goto on_error; - } - - return result; - -on_error: - if (pDevice != NULL) { - if (pDevice->pMasterMixer != NULL) dra_mixer_delete(pDevice->pMasterMixer); - if (pDevice->pBackendDevice != NULL) dra_backend_device_close(pDevice->pBackendDevice); - if (pDevice->threadEventSem != NULL) dra_semaphore_delete(pDevice->threadEventSem); - if (pDevice->mutex != NULL) dra_mutex_delete(pDevice->mutex); - - if (pDevice->ownsContext) { - dra_context_uninit(pDevice->pContext); - free(pDevice->pContext); - } - } - - return result; -} - -dra_result dra_device_init(dra_context* pContext, dra_device_type type, dra_device* pDevice) -{ - return dra_device_init_ex(pContext, type, 0, 0, DR_AUDIO_DEFAULT_SAMPLE_RATE, DR_AUDIO_DEFAULT_LATENCY, pDevice); -} - -void dra_device_uninit(dra_device* pDevice) -{ - if (pDevice == NULL || pDevice->pContext == NULL) return; - - // Mark the device as closed in order to prevent other threads from doing work after closing. - dra_device__lock(pDevice); - { - pDevice->isClosed = DR_TRUE; - } - dra_device__unlock(pDevice); - - // Stop playback before doing anything else. - dra_device__stop(pDevice); - - // The background thread needs to be terminated at this point. - dra_device__post_event(pDevice, dra_thread_event_type_terminate); - dra_thread_wait_and_delete(pDevice->thread); - - - // At this point the device is marked as closed which should prevent voice's and mixers from being created and deleted. We now need - // to delete the master mixer which in turn will delete all of the attached voices and submixers. - if (pDevice->pMasterMixer != NULL) { - dra_mixer_delete(pDevice->pMasterMixer); - } - - - if (pDevice->pBackendDevice != NULL) { - dra_backend_device_close(pDevice->pBackendDevice); - } - - if (pDevice->threadEventSem != NULL) { - dra_semaphore_delete(pDevice->threadEventSem); - } - - if (pDevice->mutex != NULL) { - dra_mutex_delete(pDevice->mutex); - } - - - if (pDevice->eventQueue.pEvents) { - free(pDevice->eventQueue.pEvents); - } - - - if (pDevice->ownsContext) { - dra_context_uninit(pDevice->pContext); - free(pDevice->pContext); - } -} - - -dra_result dra_device_create_ex(dra_context* pContext, dra_device_type type, unsigned int deviceID, unsigned int channels, unsigned int sampleRate, unsigned int latencyInMilliseconds, dra_device** ppDevice) -{ - if (ppDevice == NULL) return DRA_RESULT_INVALID_ARGS; - *ppDevice = NULL; - - dra_device* pDevice = (dra_device*)malloc(sizeof(*pDevice)); - if (pDevice == NULL) { - return DRA_RESULT_OUT_OF_MEMORY; - } - - dra_result result = dra_device_init_ex(pContext, type, deviceID, channels, sampleRate, latencyInMilliseconds, pDevice); - if (result != DRA_RESULT_SUCCESS) { - free(pDevice); - return result; - } - - *ppDevice = pDevice; - return DRA_RESULT_SUCCESS; -} - -dra_result dra_device_create(dra_context* pContext, dra_device_type type, dra_device** ppDevice) -{ - return dra_device_create_ex(pContext, type, 0, 0, DR_AUDIO_DEFAULT_SAMPLE_RATE, DR_AUDIO_DEFAULT_LATENCY, ppDevice); -} - -void dra_device_delete(dra_device* pDevice) -{ - if (pDevice == NULL) return; - - dra_device_uninit(pDevice); - free(pDevice); -} - -dra_result dra_device_start(dra_device* pDevice) -{ - if (pDevice == NULL || pDevice->pBackendDevice->type == dra_device_type_playback) return DRA_RESULT_INVALID_ARGS; - - dra_device__play(pDevice); - return DRA_RESULT_SUCCESS; -} - -dra_result dra_device_stop(dra_device* pDevice) -{ - if (pDevice == NULL || pDevice->pBackendDevice->type == dra_device_type_playback) return DRA_RESULT_INVALID_ARGS; - - dra_device__stop(pDevice); - return DRA_RESULT_SUCCESS; -} - -void dra_device_set_samples_processed_callback(dra_device* pDevice, dra_samples_processed_proc proc, void* pUserData) -{ - if (pDevice == NULL) return; - pDevice->onSamplesProcessed = proc; - pDevice->pUserDataForOnSamplesProcessed = pUserData; -} - - -dra_result dra_mixer_create(dra_device* pDevice, dra_mixer** ppMixer) -{ - if (ppMixer == NULL) return DRA_RESULT_INVALID_ARGS; - *ppMixer = NULL; - - if (pDevice == NULL) return DRA_RESULT_INVALID_ARGS; - - - // There needs to be two blocks of memory at the end of the mixer - one for the staging buffer and another for the buffer that - // will store the float32 samples of the voice currently being mixed. - size_t extraDataSize = (size_t)pDevice->pBackendDevice->samplesPerFragment * sizeof(float) * 2; - dra_mixer* pMixer = (dra_mixer*)calloc(1, sizeof(*pMixer) + extraDataSize); - if (pMixer == NULL) { - return DRA_RESULT_OUT_OF_MEMORY; - } - - pMixer->pDevice = pDevice; - pMixer->linearVolume = 1; - - pMixer->pStagingBuffer = pMixer->pData; - pMixer->pNextSamplesToMix = pMixer->pStagingBuffer + pDevice->pBackendDevice->samplesPerFragment; - - // Attach the mixer to the master mixer by default. If the master mixer is null it means we're creating the master mixer itself. - if (pDevice->pMasterMixer != NULL) { - dra_mixer_attach_submixer(pDevice->pMasterMixer, pMixer); - } - - *ppMixer = pMixer; - return DRA_RESULT_SUCCESS; -} - -void dra_mixer_delete(dra_mixer* pMixer) -{ - if (pMixer == NULL) return; - - dra_mixer_detach_all_submixers(pMixer); - dra_mixer_detach_all_voices(pMixer); - - if (pMixer->pParentMixer != NULL) { - dra_mixer_detach_submixer(pMixer->pParentMixer, pMixer); - } - - free(pMixer); -} - -void dra_mixer_attach_submixer(dra_mixer* pMixer, dra_mixer* pSubmixer) -{ - if (pMixer == NULL || pSubmixer == NULL) { - return; - } - - if (pSubmixer->pParentMixer != NULL) { - dra_mixer_detach_submixer(pSubmixer->pParentMixer, pSubmixer); - } - - - pSubmixer->pParentMixer = pMixer; - - if (pMixer->pFirstChildMixer == NULL) { - pMixer->pFirstChildMixer = pSubmixer; - pMixer->pLastChildMixer = pSubmixer; - return; - } - - assert(pMixer->pLastChildMixer != NULL); - pMixer->pLastChildMixer->pNextSiblingMixer = pSubmixer; - pSubmixer->pPrevSiblingMixer = pMixer->pLastChildMixer; - pSubmixer->pNextSiblingMixer = NULL; - pMixer->pLastChildMixer = pSubmixer; -} - -void dra_mixer_detach_submixer(dra_mixer* pMixer, dra_mixer* pSubmixer) -{ - if (pMixer == NULL || pSubmixer == NULL) { - return; - } - - if (pSubmixer->pParentMixer != pMixer) { - return; // Doesn't have the same parent. - } - - - // Detach from parent. - if (pSubmixer->pParentMixer->pFirstChildMixer == pSubmixer) { - pSubmixer->pParentMixer->pFirstChildMixer = pSubmixer->pNextSiblingMixer; - } - if (pSubmixer->pParentMixer->pLastChildMixer == pSubmixer) { - pSubmixer->pParentMixer->pLastChildMixer = pSubmixer->pPrevSiblingMixer; - } - - pSubmixer->pParentMixer = NULL; - - - // Detach from siblings. - if (pSubmixer->pPrevSiblingMixer) { - pSubmixer->pPrevSiblingMixer->pNextSiblingMixer = pSubmixer->pNextSiblingMixer; - } - if (pSubmixer->pNextSiblingMixer) { - pSubmixer->pNextSiblingMixer->pPrevSiblingMixer = pSubmixer->pPrevSiblingMixer; - } - - pSubmixer->pNextSiblingMixer = NULL; - pSubmixer->pPrevSiblingMixer = NULL; -} - -void dra_mixer_detach_all_submixers(dra_mixer* pMixer) -{ - if (pMixer == NULL) { - return; - } - - while (pMixer->pFirstChildMixer != NULL) { - dra_mixer_detach_submixer(pMixer, pMixer->pFirstChildMixer); - } -} - -void dra_mixer_attach_voice(dra_mixer* pMixer, dra_voice* pVoice) -{ - if (pMixer == NULL || pVoice == NULL) { - return; - } - - if (pVoice->pMixer != NULL) { - dra_mixer_detach_voice(pVoice->pMixer, pVoice); - } - - pVoice->pMixer = pMixer; - - if (pMixer->pFirstVoice == NULL) { - pMixer->pFirstVoice = pVoice; - pMixer->pLastVoice = pVoice; - return; - } - - // Attach the voice to the end of the list. - pVoice->pPrevVoice = pMixer->pLastVoice; - pVoice->pNextVoice = NULL; - - pMixer->pLastVoice->pNextVoice = pVoice; - pMixer->pLastVoice = pVoice; -} - -void dra_mixer_detach_voice(dra_mixer* pMixer, dra_voice* pVoice) -{ - if (pMixer == NULL || pVoice == NULL) { - return; - } - - - // Detach from mixer. - if (pMixer->pFirstVoice == pVoice) { - pMixer->pFirstVoice = pMixer->pFirstVoice->pNextVoice; - } - if (pMixer->pLastVoice == pVoice) { - pMixer->pLastVoice = pMixer->pLastVoice->pPrevVoice; - } - - pVoice->pMixer = NULL; - - - // Remove from list. - if (pVoice->pNextVoice) { - pVoice->pNextVoice->pPrevVoice = pVoice->pPrevVoice; - } - if (pVoice->pPrevVoice) { - pVoice->pPrevVoice->pNextVoice = pVoice->pNextVoice; - } - - pVoice->pNextVoice = NULL; - pVoice->pPrevVoice = NULL; - -} - -void dra_mixer_detach_all_voices(dra_mixer* pMixer) -{ - if (pMixer == NULL) { - return; - } - - while (pMixer->pFirstVoice) { - dra_mixer_detach_voice(pMixer, pMixer->pFirstVoice); - } -} - -void dra_mixer_set_volume(dra_mixer* pMixer, float linearVolume) -{ - if (pMixer == NULL) { - return; - } - - pMixer->linearVolume = linearVolume; -} - -float dra_mixer_get_volume(dra_mixer* pMixer) -{ - if (pMixer == NULL) { - return 0; - } - - return pMixer->linearVolume; -} - -size_t dra_mixer_mix_next_frames(dra_mixer* pMixer, size_t frameCount) -{ - if (pMixer == NULL) { - return 0; - } - - if (pMixer->pFirstVoice == NULL && pMixer->pFirstChildMixer == NULL) { - return 0; - } - - if (dra_mixer_is_paused(pMixer)) { - return 0; - } - - - size_t framesMixed = 0; - - // Mixing works by simply adding together the sample data of each voice and submixer. We just start at 0 and then - // just accumulate each one. - memset(pMixer->pStagingBuffer, 0, frameCount * pMixer->pDevice->channels * sizeof(float)); - - // Voices first. Doesn't really matter if we do voices or submixers first. - for (dra_voice* pVoice = pMixer->pFirstVoice; pVoice != NULL; pVoice = pVoice->pNextVoice) - { - if (pVoice->isPlaying) { - size_t framesJustRead = dra_voice__next_frames(pVoice, frameCount, pMixer->pNextSamplesToMix); - for (size_t i = 0; i < framesJustRead * pMixer->pDevice->channels; ++i) { - pMixer->pStagingBuffer[i] += (pMixer->pNextSamplesToMix[i] * pVoice->linearVolume); - } - - // Has the end of the voice's buffer been reached? - if (framesJustRead < frameCount) - { - // We'll get here if the end of the voice's buffer has been reached. The voice needs to be forcefully stopped to - // ensure the device is aware of it and is able to put itself into a dormant state if necessary. Also note that - // the playback position is moved back to start. The rationale for this is that it's a little bit more useful than - // just leaving the playback position sitting on the end. Also it allows an application to restart playback with - // a single call to dra_voice_play() without having to explicitly set the playback position. - pVoice->currentReadPos = 0; - dra_voice_stop(pVoice); - } - - if (framesMixed < framesJustRead) { - framesMixed = framesJustRead; - } - } - } - - // Submixers. - for (dra_mixer* pSubmixer = pMixer->pFirstChildMixer; pSubmixer != NULL; pSubmixer = pSubmixer->pNextSiblingMixer) - { - size_t framesJustMixed = dra_mixer_mix_next_frames(pSubmixer, frameCount); - for (size_t i = 0; i < framesJustMixed * pMixer->pDevice->channels; ++i) { - pMixer->pStagingBuffer[i] += pSubmixer->pStagingBuffer[i]; - } - - if (framesMixed < framesJustMixed) { - framesMixed = framesJustMixed; - } - } - - - // At this point the mixer's effects and volume need to be applied to each sample. - size_t samplesMixed = framesMixed * pMixer->pDevice->channels; - for (size_t i = 0; i < samplesMixed; ++i) { - pMixer->pStagingBuffer[i] *= pMixer->linearVolume; - } - - - // Finally we need to ensure every samples is clamped to -1 to 1. There are two easy ways to do this: clamp or normalize. For now I'm just - // clamping to keep it simple, but it might be valuable to make this configurable. - for (size_t i = 0; i < framesMixed * pMixer->pDevice->channels; ++i) - { - // TODO: Investigate using SSE here (MINPS/MAXPS) - // TODO: Investigate if the backends clamp the samples themselves, thus making this redundant. - if (pMixer->pStagingBuffer[i] < -1) { - pMixer->pStagingBuffer[i] = -1; - } else if (pMixer->pStagingBuffer[i] > 1) { - pMixer->pStagingBuffer[i] = 1; - } - } - - return framesMixed; -} - -size_t dra_mixer_count_attached_voices(dra_mixer* pMixer) -{ - if (pMixer == NULL) { - return 0; - } - - size_t count = 0; - for (dra_voice* pVoice = pMixer->pFirstVoice; pVoice != NULL; pVoice = pVoice->pNextVoice) { - count += 1; - } - - return count; -} - -size_t dra_mixer_count_attached_voices_recursive(dra_mixer* pMixer) -{ - if (pMixer == NULL) { - return 0; - } - - size_t count = dra_mixer_count_attached_voices(pMixer); - - // Children. - for (dra_mixer* pChildMixer = pMixer->pFirstChildMixer; pChildMixer != NULL; pChildMixer = pChildMixer->pNextSiblingMixer) { - count += dra_mixer_count_attached_voices_recursive(pChildMixer); - } - - return count; -} - -size_t dra_mixer_gather_attached_voices(dra_mixer* pMixer, dra_voice** ppVoicesOut) -{ - if (pMixer == NULL) { - return 0; - } - - if (ppVoicesOut == NULL) { - return dra_mixer_count_attached_voices(pMixer); - } - - size_t count = 0; - for (dra_voice* pVoice = pMixer->pFirstVoice; pVoice != NULL; pVoice = pVoice->pNextVoice) { - ppVoicesOut[count] = pVoice; - count += 1; - } - - return count; -} - -size_t dra_mixer_gather_attached_voices_recursive(dra_mixer* pMixer, dra_voice** ppVoicesOut) -{ - if (pMixer == NULL) { - return 0; - } - - if (ppVoicesOut == NULL) { - return dra_mixer_count_attached_voices_recursive(pMixer); - } - - size_t count = dra_mixer_gather_attached_voices(pMixer, ppVoicesOut); - - // Children. - for (dra_mixer* pChildMixer = pMixer->pFirstChildMixer; pChildMixer != NULL; pChildMixer = pChildMixer->pNextSiblingMixer) { - count += dra_mixer_gather_attached_voices_recursive(pChildMixer, ppVoicesOut + count); - } - - return count; -} - - -void dra_mixer_pause(dra_mixer* pMixer) -{ - if (pMixer == NULL) return; - pMixer->flags |= DRA_MIXER_FLAG_PAUSED; -} - -void dra_mixer_resume(dra_mixer* pMixer) -{ - if (pMixer == NULL) return; - pMixer->flags &= ~DRA_MIXER_FLAG_PAUSED; - - // When the mixer was paused it may have resulted in no audio being played which means dr_audio will have stopped the device - // to save CPU usage. We need to make sure we wake up the device. - dra_device__play(pMixer->pDevice); -} - -dr_bool32 dra_mixer_is_paused(dra_mixer* pMixer) -{ - if (pMixer == NULL) return DR_FALSE; - return (pMixer->flags & DRA_MIXER_FLAG_PAUSED) != 0; -} - - - -dra_result dra_voice_create(dra_device* pDevice, dra_format format, unsigned int channels, unsigned int sampleRate, size_t sizeInBytes, const void* pInitialData, dra_voice** ppVoice) -{ - if (ppVoice == NULL) return DRA_RESULT_INVALID_ARGS; - *ppVoice = NULL; - - if (pDevice == NULL || sizeInBytes == 0) return DRA_RESULT_INVALID_ARGS; - - - // The number of bytes must be a multiple of the size of a frame. - size_t bytesPerSample = dra_get_bytes_per_sample_by_format(format); - if ((sizeInBytes % (bytesPerSample * channels)) != 0) { - return DRA_RESULT_INVALID_ARGS; - } - - - dra_voice* pVoice = (dra_voice*)calloc(1, sizeof(*pVoice) + sizeInBytes); - if (pVoice == NULL) { - return DRA_RESULT_OUT_OF_MEMORY; - } - - pVoice->pDevice = pDevice; - pVoice->pMixer = NULL; - pVoice->format = format; - pVoice->channels = channels; - pVoice->sampleRate = sampleRate; - pVoice->linearVolume = 1; - pVoice->isPlaying = DR_FALSE; - pVoice->isLooping = DR_FALSE; - pVoice->frameCount = sizeInBytes / (bytesPerSample * channels); - pVoice->currentReadPos = 0; - pVoice->sizeInBytes = sizeInBytes; - pVoice->pNextVoice = NULL; - pVoice->pPrevVoice = NULL; - - if (pInitialData != NULL) { - memcpy(pVoice->pData, pInitialData, sizeInBytes); - } else { - //memset(pVoice->pData, 0, sizeInBytes); // <-- This is already zeroed by the calloc() above, but leaving this comment here for emphasis. - } - - - // Sample rate conversion. - if (sampleRate == pDevice->sampleRate) { - pVoice->src.algorithm = dra_src_algorithm_none; - } else { - pVoice->src.algorithm = dra_src_algorithm_linear; - } - - - // Attach the voice to the master mixer by default. - if (pDevice->pMasterMixer != NULL) { - dra_mixer_attach_voice(pDevice->pMasterMixer, pVoice); - } - - *ppVoice = pVoice; - return DRA_RESULT_SUCCESS; -} - -dra_result dra_voice_create_compatible(dra_device* pDevice, size_t sizeInBytes, const void* pInitialData, dra_voice** ppVoice) -{ - return dra_voice_create(pDevice, dra_format_f32, pDevice->channels, pDevice->sampleRate, sizeInBytes, pInitialData, ppVoice); -} - -void dra_voice_delete(dra_voice* pVoice) -{ - if (pVoice == NULL) return; - - // The voice needs to be stopped... - dra_voice_stop(pVoice); - - // ... and all pending events need to be cancelled to ensure the application isn't notified of an event of a deleted voice. - dra_event_queue__cancel_events_of_voice(&pVoice->pDevice->eventQueue, pVoice); - - if (pVoice->pMixer != NULL) { - dra_mixer_detach_voice(pVoice->pMixer, pVoice); - } - - free(pVoice); -} - -void dra_voice_play(dra_voice* pVoice, dr_bool32 loop) -{ - if (pVoice == NULL) { - return; - } - - if (!dra_voice_is_playing(pVoice)) { - dra_device__voice_playback_count_inc(pVoice->pDevice); - } else { - if (dra_voice_is_looping(pVoice) == loop) { - return; // Nothing has changed - don't need to do anything. - } - } - - pVoice->isPlaying = DR_TRUE; - pVoice->isLooping = loop; - - dra_event_queue__schedule_event(&pVoice->pDevice->eventQueue, &pVoice->playEvent); - - // When playing a voice we need to ensure the backend device is playing. - dra_device__play(pVoice->pDevice); -} - -void dra_voice_stop(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return; - } - - if (!dra_voice_is_playing(pVoice)) { - return; // The voice is already stopped. - } - - dra_device__voice_playback_count_dec(pVoice->pDevice); - - pVoice->isPlaying = DR_FALSE; - pVoice->isLooping = DR_FALSE; - - dra_event_queue__schedule_event(&pVoice->pDevice->eventQueue, &pVoice->stopEvent); -} - -dr_bool32 dra_voice_is_playing(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return DR_FALSE; - } - - return pVoice->isPlaying; -} - -dr_bool32 dra_voice_is_looping(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return DR_FALSE; - } - - return pVoice->isLooping; -} - - -void dra_voice_set_volume(dra_voice* pVoice, float linearVolume) -{ - if (pVoice == NULL) { - return; - } - - pVoice->linearVolume = linearVolume; -} - -float dra_voice_get_volume(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return 0; - } - - return pVoice->linearVolume; -} - - -void dra_f32_to_f32(float* pOut, const float* pIn, size_t sampleCount) -{ - memcpy(pOut, pIn, sampleCount * sizeof(float)); -} - -void dra_s32_to_f32(float* pOut, const dr_int32* pIn, size_t sampleCount) -{ - // TODO: Try SSE-ifying this. - for (size_t i = 0; i < sampleCount; ++i) { - pOut[i] = pIn[i] / 2147483648.0f; - } -} - -void dra_s24_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount) -{ - // TODO: Try SSE-ifying this. - for (size_t i = 0; i < sampleCount; ++i) { - dr_uint8 s0 = pIn[i*3 + 0]; - dr_uint8 s1 = pIn[i*3 + 1]; - dr_uint8 s2 = pIn[i*3 + 2]; - - dr_int32 sample32 = (dr_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); - pOut[i] = sample32 / 2147483648.0f; - } -} - -void dra_s16_to_f32(float* pOut, const dr_int16* pIn, size_t sampleCount) -{ - // TODO: Try SSE-ifying this. - for (size_t i = 0; i < sampleCount; ++i) { - pOut[i] = pIn[i] / 32768.0f; - } -} - -void dra_u8_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount) -{ - // TODO: Try SSE-ifying this. - for (size_t i = 0; i < sampleCount; ++i) { - pOut[i] = (pIn[i] / 127.5f) - 1; - } -} - - -// Generic sample format conversion function. To add basic, unoptimized support for a new format, just add it to this function. -// Format-specific optimizations need to be implemented specifically for each format, at a higher level. -void dra_to_f32(float* pOut, const void* pIn, size_t sampleCount, dra_format format) -{ - switch (format) - { - case dra_format_f32: - { - dra_f32_to_f32(pOut, (float*)pIn, sampleCount); - } break; - - case dra_format_s32: - { - dra_s32_to_f32(pOut, (dr_int32*)pIn, sampleCount); - } break; - - case dra_format_s24: - { - dra_s24_to_f32(pOut, (dr_uint8*)pIn, sampleCount); - } break; - - case dra_format_s16: - { - dra_s16_to_f32(pOut, (dr_int16*)pIn, sampleCount); - } break; - - case dra_format_u8: - { - dra_u8_to_f32(pOut, (dr_uint8*)pIn, sampleCount); - } break; - - default: break; // Unknown or unsupported format. - } -} - - -// Notes on channel shuffling. -// -// Channels are shuffled frame-by-frame by first normalizing everything to floats. Then, a shuffling function is called to -// shuffle the channels in a particular way depending on the destination and source channel assignments. -void dra_shuffle_channels__generic_inc(float* pOut, const float* pIn, unsigned int channelsOut, unsigned int channelsIn) -{ - // This is the generic function for taking a frame with a smaller number of channels and expanding it to a frame with - // a greater number of channels. This just copies the first channelsIn samples to the output and silences the remaing - // channels. - assert(channelsOut > channelsIn); - - for (unsigned int i = 0; i < channelsIn; ++i) { - pOut[i] = pIn[i]; - } - - // Silence the left over. - for (unsigned int i = channelsIn; i < channelsOut; ++i) { - pOut[i] = 0; - } -} - -void dra_shuffle_channels__generic_dec(float* pOut, const float* pIn, unsigned int channelsOut, unsigned int channelsIn) -{ - // This is the opposite of dra_shuffle_channels__generic_inc() - it decreases the number of channels in the input stream - // by simply stripping the excess channels. - assert(channelsOut < channelsIn); - (void)channelsIn; - - // Just copy the first channelsOut. - for (unsigned int i = 0; i < channelsOut; ++i) { - pOut[i] = pIn[i]; - } -} - -void dra_shuffle_channels(float* pOut, const float* pIn, unsigned int channelsOut, unsigned int channelsIn) -{ - assert(channelsOut != 0); - assert(channelsIn != 0); - - if (channelsOut == channelsIn) { - for (unsigned int i = 0; i < channelsOut; ++i) { - pOut[i] = pIn[i]; - } - } else { - switch (channelsIn) - { - case 1: - { - // Mono input. This is a simple case - just copy the value of the mono channel to every output channel. - for (unsigned int i = 0; i < channelsOut; ++i) { - pOut[i] = pIn[0]; - } - } break; - - case 2: - { - // Stereo input. - if (channelsOut == 1) - { - // For mono output, just average. - pOut[0] = (pIn[0] + pIn[1]) * 0.5f; - } - else - { - // TODO: Do a specialized implementation for all major formats, in particluar 5.1. - dra_shuffle_channels__generic_inc(pOut, pIn, channelsOut, channelsIn); - } - } break; - - default: - { - if (channelsOut == 1) - { - // For mono output, just average each sample. - float total = 0; - for (unsigned int i = 0; i < channelsIn; ++i) { - total += pIn[i]; - } - - pOut[0] = total / channelsIn; - } - else - { - if (channelsOut > channelsIn) { - dra_shuffle_channels__generic_inc(pOut, pIn, channelsOut, channelsIn); - } else { - dra_shuffle_channels__generic_dec(pOut, pIn, channelsOut, channelsIn); - } - } - } break; - } - } -} - -float dra_voice__get_sample_rate_factor(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return 1; - } - - return pVoice->pDevice->sampleRate / (float)pVoice->sampleRate; -} - -void dra_voice__unsignal_playback_events(dra_voice* pVoice) -{ - // This function will be called when the voice has looped back to the start. In this case the playback notification events need - // to be marked as unsignaled so that they're able to be fired again. - for (size_t i = 0; i < pVoice->playbackEventCount; ++i) { - pVoice->playbackEvents[i].hasBeenSignaled = DR_FALSE; - } -} - -float* dra_voice__next_frame(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return NULL; - } - - - if (pVoice->format == dra_format_f32 && pVoice->sampleRate == pVoice->pDevice->sampleRate && pVoice->channels == pVoice->pDevice->channels) - { - // Fast path. - if (!pVoice->isLooping && pVoice->currentReadPos == pVoice->frameCount) { - return NULL; // At the end of a non-looping voice. - } - - float* pOut = (float*)pVoice->pData + (pVoice->currentReadPos * pVoice->channels); - - pVoice->currentReadPos += 1; - if (pVoice->currentReadPos == pVoice->frameCount && pVoice->isLooping) { - pVoice->currentReadPos = 0; - dra_voice__unsignal_playback_events(pVoice); - } - - return pOut; - } - else - { - size_t bytesPerSample = dra_get_bytes_per_sample_by_format(pVoice->format); - - if (pVoice->sampleRate == pVoice->pDevice->sampleRate) - { - // Same sample rate. This path isn't ideal, but it's not too bad since there is no need for sample rate conversion. - if (!pVoice->isLooping && pVoice->currentReadPos == pVoice->frameCount) { - return NULL; // At the end of a non-looping voice. - } - - float* pOut = pVoice->convertedFrame; - - unsigned int channelsIn = pVoice->channels; - unsigned int channelsOut = pVoice->pDevice->channels; - float tempFrame[DR_AUDIO_MAX_CHANNEL_COUNT]; - dr_uint64 sampleOffset = pVoice->currentReadPos * channelsIn; - - // The conversion is done differently depending on the format of the voice. - if (pVoice->format == dra_format_f32) { - dra_shuffle_channels(pOut, (float*)pVoice->pData + sampleOffset, channelsOut, channelsIn); - } else { - sampleOffset = pVoice->currentReadPos * (channelsIn * bytesPerSample); - dra_to_f32(tempFrame, (dr_uint8*)pVoice->pData + sampleOffset, channelsIn, pVoice->format); - dra_shuffle_channels(pOut, tempFrame, channelsOut, channelsIn); - } - - pVoice->currentReadPos += 1; - if (pVoice->currentReadPos == pVoice->frameCount && pVoice->isLooping) { - pVoice->currentReadPos = 0; - dra_voice__unsignal_playback_events(pVoice); - } - - return pOut; - } - else - { - // Different sample rate. This is the truly slow path. - unsigned int sampleRateIn = pVoice->sampleRate; - unsigned int sampleRateOut = pVoice->pDevice->sampleRate; - unsigned int channelsIn = pVoice->channels; - unsigned int channelsOut = pVoice->pDevice->channels; - - float factor = (float)sampleRateOut / (float)sampleRateIn; - float invfactor = 1 / factor; - - if (!pVoice->isLooping && pVoice->currentReadPos >= (pVoice->frameCount * factor)) { - return NULL; // At the end of a non-looping voice. - } - - float* pOut = pVoice->convertedFrame; - - if (pVoice->src.algorithm == dra_src_algorithm_linear) { - // Linear filtering. - float timeIn = pVoice->currentReadPos * invfactor; - dr_uint64 prevFrameIndexIn = (dr_uint64)(timeIn); - dr_uint64 nextFrameIndexIn = prevFrameIndexIn + 1; - if (nextFrameIndexIn >= pVoice->frameCount) { - nextFrameIndexIn = pVoice->frameCount-1; - } - - if (prevFrameIndexIn != pVoice->src.data.linear.prevFrameIndex) - { - dr_uint64 sampleOffset = prevFrameIndexIn * (channelsIn * bytesPerSample); - dra_to_f32(pVoice->src.data.linear.prevFrame, (dr_uint8*)pVoice->pData + sampleOffset, channelsIn, pVoice->format); - - sampleOffset = nextFrameIndexIn * (channelsIn * bytesPerSample); - dra_to_f32(pVoice->src.data.linear.nextFrame, (dr_uint8*)pVoice->pData + sampleOffset, channelsIn, pVoice->format); - - pVoice->src.data.linear.prevFrameIndex = prevFrameIndexIn; - } - - float alpha = timeIn - prevFrameIndexIn; - float frame[DR_AUDIO_MAX_CHANNEL_COUNT]; - for (unsigned int i = 0; i < pVoice->channels; ++i) { - frame[i] = dra_mixf(pVoice->src.data.linear.prevFrame[i], pVoice->src.data.linear.nextFrame[i], alpha); - } - - dra_shuffle_channels(pOut, frame, channelsOut, channelsIn); - } - - - pVoice->currentReadPos += 1; - if (pVoice->currentReadPos >= (pVoice->frameCount * factor) && pVoice->isLooping) { - pVoice->currentReadPos = 0; - dra_voice__unsignal_playback_events(pVoice); - } - - return pOut; - } - } -} - -size_t dra_voice__next_frames(dra_voice* pVoice, size_t frameCount, float* pSamplesOut) -{ - // TODO: Check for the fast path and do a bulk copy rather than frame-by-frame. Don't forget playback event handling. - - size_t framesRead = 0; - - dr_uint64 prevReadPosLocal = pVoice->currentReadPos * pVoice->channels; - - float* pNextFrame = NULL; - while ((framesRead < frameCount) && (pNextFrame = dra_voice__next_frame(pVoice)) != NULL) { - memcpy(pSamplesOut, pNextFrame, pVoice->pDevice->channels * sizeof(float)); - pSamplesOut += pVoice->pDevice->channels; - framesRead += 1; - } - - float sampleRateFactor = dra_voice__get_sample_rate_factor(pVoice); - dr_uint64 totalSampleCount = (dr_uint64)((pVoice->frameCount * pVoice->channels) * sampleRateFactor); - - // Now we need to check if we've got past any notification events and post events for them if so. - dr_uint64 currentReadPosLocal = (prevReadPosLocal + (framesRead * pVoice->channels)) % totalSampleCount; - for (size_t i = 0; i < pVoice->playbackEventCount; ++i) { - dra__event* pEvent = &pVoice->playbackEvents[i]; - if (!pEvent->hasBeenSignaled && pEvent->sampleIndex*sampleRateFactor <= currentReadPosLocal) { - dra_event_queue__schedule_event(&pVoice->pDevice->eventQueue, pEvent); // <-- TODO: Check that this really needs to be scheduled. Can probably call it directly and avoid a mutex lock/unlock. - pEvent->hasBeenSignaled = DR_TRUE; - } - } - - return framesRead; -} - - -void dra_voice_set_on_stop(dra_voice* pVoice, dra_event_proc proc, void* pUserData) -{ - if (pVoice == NULL) { - return; - } - - pVoice->stopEvent.id = DR_AUDIO_EVENT_ID_STOP; - pVoice->stopEvent.pUserData = pUserData; - pVoice->stopEvent.sampleIndex = 0; - pVoice->stopEvent.proc = proc; - pVoice->stopEvent.pVoice = pVoice; -} - -void dra_voice_set_on_play(dra_voice* pVoice, dra_event_proc proc, void* pUserData) -{ - if (pVoice == NULL) { - return; - } - - pVoice->playEvent.id = DR_AUDIO_EVENT_ID_PLAY; - pVoice->playEvent.pUserData = pUserData; - pVoice->playEvent.sampleIndex = 0; - pVoice->playEvent.proc = proc; - pVoice->playEvent.pVoice = pVoice; -} - -dr_bool32 dra_voice_add_playback_event(dra_voice* pVoice, dr_uint64 sampleIndex, dr_uint64 eventID, dra_event_proc proc, void* pUserData) -{ - if (pVoice == NULL) { - return DR_FALSE; - } - - if (pVoice->playbackEventCount >= DR_AUDIO_MAX_EVENT_COUNT) { - return DR_FALSE; - } - - pVoice->playbackEvents[pVoice->playbackEventCount].id = eventID; - pVoice->playbackEvents[pVoice->playbackEventCount].pUserData = pUserData; - pVoice->playbackEvents[pVoice->playbackEventCount].sampleIndex = sampleIndex; - pVoice->playbackEvents[pVoice->playbackEventCount].proc = proc; - pVoice->playbackEvents[pVoice->playbackEventCount].pVoice = pVoice; - - pVoice->playbackEventCount += 1; - return DR_TRUE; -} - -void dra_voice_remove_playback_event(dra_voice* pVoice, dr_uint64 eventID) -{ - if (pVoice == NULL) { - return; - } - - for (size_t i = 0; i < pVoice->playbackEventCount; /* DO NOTHING */) { - if (pVoice->playbackEvents[i].id == eventID) { - memmove(&pVoice->playbackEvents[i], &pVoice->playbackEvents[i + 1], (pVoice->playbackEventCount - (i+1)) * sizeof(dra__event)); - pVoice->playbackEventCount -= 1; - } else { - i += 1; - } - } -} - - -dr_uint64 dra_voice_get_playback_position(dra_voice* pVoice) -{ - if (pVoice == NULL) { - return 0; - } - - return (dr_uint64)((pVoice->currentReadPos * pVoice->channels) / dra_voice__get_sample_rate_factor(pVoice)); -} - -void dra_voice_set_playback_position(dra_voice* pVoice, dr_uint64 sampleIndex) -{ - if (pVoice == NULL) { - return; - } - - // When setting the playback position it's important to consider sample-rate conversion. Sample rate conversion will often depend on - // previous and next frames in order to calculate the next frame. Therefore, depending on the type of SRC we're using, we'll need to - // seek a few frames earlier and then re-fill the delay-line buffer used for a particular SRC algorithm. - dr_uint64 localFramePos = sampleIndex / pVoice->channels; - pVoice->currentReadPos = (dr_uint64)(localFramePos * dra_voice__get_sample_rate_factor(pVoice)); - - if (pVoice->sampleRate != pVoice->pDevice->sampleRate) { - if (pVoice->src.algorithm == dra_src_algorithm_linear) { - // Linear filtering just requires the previous frame. However, this is handled at mixing time for linear SRC so all we need to - // do is ensure the mixing function is aware that the previous frame need to be re-read. This is done by simply resetting the - // variable the mixer uses to determine whether or not the previous frame needs to be re-read. - pVoice->src.data.linear.prevFrameIndex = 0; - } - } - - // TODO: Normalize the hasBeenSignaled properties of events. -} - - -void* dra_voice_get_buffer_ptr_by_sample(dra_voice* pVoice, dr_uint64 sample) -{ - if (pVoice == NULL) { - return NULL; - } - - dr_uint64 totalSampleCount = pVoice->frameCount * pVoice->channels; - if (sample > totalSampleCount) { - return NULL; - } - - return pVoice->pData + (sample * dra_get_bytes_per_sample_by_format(pVoice->format)); -} - -void dra_voice_write_silence(dra_voice* pVoice, dr_uint64 sampleOffset, dr_uint64 sampleCount) -{ - void* pData = dra_voice_get_buffer_ptr_by_sample(pVoice, sampleOffset); - if (pData == NULL) { - return; - } - - dr_uint64 totalSamplesRemaining = (pVoice->frameCount * pVoice->channels) - sampleOffset; - if (sampleCount > totalSamplesRemaining) { - sampleCount = totalSamplesRemaining; - } - - memset(pData, 0, (size_t)(sampleCount * dra_get_bytes_per_sample_by_format(pVoice->format))); -} - - - - - - -//// Other APIs //// - -void dra_free(void* p) -{ - free(p); -} - -unsigned int dra_get_bits_per_sample_by_format(dra_format format) -{ - unsigned int lookup[] = { - 8, // dra_format_u8 - 16, // dra_format_s16 - 24, // dra_format_s24 - 32, // dra_format_s32 - 32 // dra_format_f32 - }; - - return lookup[format]; -} - -unsigned int dra_get_bytes_per_sample_by_format(dra_format format) -{ - return dra_get_bits_per_sample_by_format(format) / 8; -} - - -//// STDIO //// - -#ifndef DR_AUDIO_NO_STDIO -static FILE* dra__fopen(const char* filePath) -{ - FILE* pFile; -#ifdef _MSC_VER - if (fopen_s(&pFile, filePath, "rb") != 0) { - return NULL; - } -#else - pFile = fopen(filePath, "rb"); - if (pFile == NULL) { - return NULL; - } -#endif - - return (FILE*)pFile; -} -#endif //DR_AUDIO_NO_STDIO - - -//// Decoder APIs //// - -#ifdef DR_AUDIO_HAS_WAV -size_t dra_decoder_on_read__wav(void* pUserData, void* pDataOut, size_t bytesToRead) -{ - dra_decoder* pDecoder = (dra_decoder*)pUserData; - assert(pDecoder != NULL); - assert(pDecoder->onRead != NULL); - - return pDecoder->onRead(pDecoder->pUserData, pDataOut, bytesToRead); -} -drwav_bool32 dra_decoder_on_seek__wav(void* pUserData, int offset, drwav_seek_origin origin) -{ - dra_decoder* pDecoder = (dra_decoder*)pUserData; - assert(pDecoder != NULL); - assert(pDecoder->onSeek != NULL); - - return pDecoder->onSeek(pDecoder->pUserData, offset, (origin == drwav_seek_origin_start) ? dra_seek_origin_start : dra_seek_origin_current); -} - -void dra_decoder_on_delete__wav(void* pBackendDecoder) -{ - drwav* pWav = (drwav*)pBackendDecoder; - assert(pWav != NULL); - - drwav_close(pWav); -} - -dr_uint64 dra_decoder_on_read_samples__wav(void* pBackendDecoder, dr_uint64 samplesToRead, float* pSamplesOut) -{ - drwav* pWav = (drwav*)pBackendDecoder; - assert(pWav != NULL); - - return drwav_read_f32(pWav, samplesToRead, pSamplesOut); -} - -dr_bool32 dra_decoder_on_seek_samples__wav(void* pBackendDecoder, dr_uint64 sample) -{ - drwav* pWav = (drwav*)pBackendDecoder; - assert(pWav != NULL); - - return drwav_seek_to_sample(pWav, sample); -} - - -void dra_decoder_init__wav(dra_decoder* pDecoder, drwav* pWav) -{ - assert(pDecoder != NULL); - assert(pWav != NULL); - - pDecoder->channels = pWav->channels; - pDecoder->sampleRate = pWav->sampleRate; - pDecoder->totalSampleCount = pWav->totalSampleCount; - - pDecoder->pBackendDecoder = pWav; - pDecoder->onDelete = dra_decoder_on_delete__wav; - pDecoder->onReadSamples = dra_decoder_on_read_samples__wav; - pDecoder->onSeekSamples = dra_decoder_on_seek_samples__wav; -} - -dr_bool32 dra_decoder_open__wav(dra_decoder* pDecoder) -{ - drwav* pWav = drwav_open(dra_decoder_on_read__wav, dra_decoder_on_seek__wav, pDecoder); - if (pWav == NULL) { - return DR_FALSE; - } - - dra_decoder_init__wav(pDecoder, pWav); - return DR_TRUE; -} - -dr_bool32 dra_decoder_open_memory__wav(dra_decoder* pDecoder, const void* pData, size_t dataSize) -{ - drwav* pWav = drwav_open_memory(pData, dataSize); - if (pWav == NULL) { - return DR_FALSE; - } - - dra_decoder_init__wav(pDecoder, pWav); - return DR_TRUE; -} - -#ifdef DR_AUDIO_HAS_WAV_STDIO -dr_bool32 dra_decoder_open_file__wav(dra_decoder* pDecoder, const char* filePath) -{ - drwav* pWav = drwav_open_file(filePath); - if (pWav == NULL) { - return DR_FALSE; - } - - dra_decoder_init__wav(pDecoder, pWav); - return DR_TRUE; -} -#endif -#endif //WAV - -#ifdef DR_AUDIO_HAS_FLAC -size_t dra_decoder_on_read__flac(void* pUserData, void* pDataOut, size_t bytesToRead) -{ - dra_decoder* pDecoder = (dra_decoder*)pUserData; - assert(pDecoder != NULL); - assert(pDecoder->onRead != NULL); - - return pDecoder->onRead(pDecoder->pUserData, pDataOut, bytesToRead); -} -drflac_bool32 dra_decoder_on_seek__flac(void* pUserData, int offset, drflac_seek_origin origin) -{ - dra_decoder* pDecoder = (dra_decoder*)pUserData; - assert(pDecoder != NULL); - assert(pDecoder->onSeek != NULL); - - return pDecoder->onSeek(pDecoder->pUserData, offset, (origin == drflac_seek_origin_start) ? dra_seek_origin_start : dra_seek_origin_current); -} - -void dra_decoder_on_delete__flac(void* pBackendDecoder) -{ - drflac* pFlac = (drflac*)pBackendDecoder; - assert(pFlac != NULL); - - drflac_close(pFlac); -} - -dr_uint64 dra_decoder_on_read_samples__flac(void* pBackendDecoder, dr_uint64 samplesToRead, float* pSamplesOut) -{ - drflac* pFlac = (drflac*)pBackendDecoder; - assert(pFlac != NULL); - - dr_uint64 samplesRead = drflac_read_s32(pFlac, samplesToRead, (dr_int32*)pSamplesOut); - - dra_s32_to_f32(pSamplesOut, (dr_int32*)pSamplesOut, (size_t)samplesRead); - return samplesRead; -} - -dr_bool32 dra_decoder_on_seek_samples__flac(void* pBackendDecoder, dr_uint64 sample) -{ - drflac* pFlac = (drflac*)pBackendDecoder; - assert(pFlac != NULL); - - return drflac_seek_to_sample(pFlac, sample); -} - - -void dra_decoder_init__flac(dra_decoder* pDecoder, drflac* pFlac) -{ - assert(pDecoder != NULL); - assert(pFlac != NULL); - - pDecoder->channels = pFlac->channels; - pDecoder->sampleRate = pFlac->sampleRate; - pDecoder->totalSampleCount = pFlac->totalSampleCount; - - pDecoder->pBackendDecoder = pFlac; - pDecoder->onDelete = dra_decoder_on_delete__flac; - pDecoder->onReadSamples = dra_decoder_on_read_samples__flac; - pDecoder->onSeekSamples = dra_decoder_on_seek_samples__flac; -} - -dr_bool32 dra_decoder_open__flac(dra_decoder* pDecoder) -{ - drflac* pFlac = drflac_open(dra_decoder_on_read__flac, dra_decoder_on_seek__flac, pDecoder); - if (pFlac == NULL) { - return DR_FALSE; - } - - dra_decoder_init__flac(pDecoder, pFlac); - return DR_TRUE; -} - -dr_bool32 dra_decoder_open_memory__flac(dra_decoder* pDecoder, const void* pData, size_t dataSize) -{ - drflac* pFlac = drflac_open_memory(pData, dataSize); - if (pFlac == NULL) { - return DR_FALSE; - } - - dra_decoder_init__flac(pDecoder, pFlac); - return DR_TRUE; -} - -#ifdef DR_AUDIO_HAS_FLAC_STDIO -dr_bool32 dra_decoder_open_file__flac(dra_decoder* pDecoder, const char* filePath) -{ - drflac* pFlac = drflac_open_file(filePath); - if (pFlac == NULL) { - return DR_FALSE; - } - - dra_decoder_init__flac(pDecoder, pFlac); - return DR_TRUE; -} -#endif -#endif //FLAC - -#ifdef DR_AUDIO_HAS_VORBIS -void dra_decoder_on_delete__vorbis(void* pBackendDecoder) -{ - stb_vorbis* pVorbis = (stb_vorbis*)pBackendDecoder; - assert(pVorbis != NULL); - - stb_vorbis_close(pVorbis); -} - -dr_uint64 dra_decoder_on_read_samples__vorbis(void* pBackendDecoder, dr_uint64 samplesToRead, float* pSamplesOut) -{ - stb_vorbis* pVorbis = (stb_vorbis*)pBackendDecoder; - assert(pVorbis != NULL); - - stb_vorbis_info info = stb_vorbis_get_info(pVorbis); - return (dr_uint64)stb_vorbis_get_samples_float_interleaved(pVorbis, info.channels, pSamplesOut, (int)samplesToRead) * info.channels; -} - -dr_bool32 dra_decoder_on_seek_samples__vorbis(void* pBackendDecoder, dr_uint64 sample) -{ - stb_vorbis* pVorbis = (stb_vorbis*)pBackendDecoder; - assert(pVorbis != NULL); - - return stb_vorbis_seek(pVorbis, (unsigned int)sample) != 0; -} - - -void dra_decoder_init__vorbis(dra_decoder* pDecoder, stb_vorbis* pVorbis) -{ - assert(pDecoder != NULL); - assert(pVorbis != NULL); - - stb_vorbis_info info = stb_vorbis_get_info(pVorbis); - - pDecoder->channels = info.channels; - pDecoder->sampleRate = info.sample_rate; - pDecoder->totalSampleCount = stb_vorbis_stream_length_in_samples(pVorbis) * info.channels; - - pDecoder->pBackendDecoder = pVorbis; - pDecoder->onDelete = dra_decoder_on_delete__vorbis; - pDecoder->onReadSamples = dra_decoder_on_read_samples__vorbis; - pDecoder->onSeekSamples = dra_decoder_on_seek_samples__vorbis; -} - -dr_bool32 dra_decoder_open__vorbis(dra_decoder* pDecoder) -{ - // TODO: Add support for the push API. - - // Not currently supporting callback based decoding. - (void)pDecoder; - return DR_FALSE; -} - -dr_bool32 dra_decoder_open_memory__vorbis(dra_decoder* pDecoder, const void* pData, size_t dataSize) -{ - stb_vorbis* pVorbis = stb_vorbis_open_memory((const unsigned char*)pData, (int)dataSize, NULL, NULL); - if (pVorbis == NULL) { - return DR_FALSE; - } - - dra_decoder_init__vorbis(pDecoder, pVorbis); - return DR_TRUE; -} - -#ifdef DR_AUDIO_HAS_VORBIS_STDIO -dr_bool32 dra_decoder_open_file__vorbis(dra_decoder* pDecoder, const char* filePath) -{ - stb_vorbis* pVorbis = stb_vorbis_open_filename(filePath, NULL, NULL); - if (pVorbis == NULL) { - return DR_FALSE; - } - - dra_decoder_init__vorbis(pDecoder, pVorbis); - return DR_TRUE; -} -#endif -#endif //Vorbis - -dra_result dra_decoder_open(dra_decoder* pDecoder, dra_decoder_on_read_proc onRead, dra_decoder_on_seek_proc onSeek, void* pUserData) -{ - if (pDecoder == NULL) return DRA_RESULT_INVALID_ARGS; - memset(pDecoder, 0, sizeof(*pDecoder)); - - if (onRead == NULL || onSeek == NULL) return DRA_RESULT_INVALID_ARGS; - - pDecoder->onRead = onRead; - pDecoder->onSeek = onSeek; - pDecoder->pUserData = pUserData; - -#ifdef DR_AUDIO_HAS_WAV_STDIO - if (dra_decoder_open__wav(pDecoder)) { - return DRA_RESULT_SUCCESS; - } - onSeek(pUserData, 0, dra_seek_origin_start); -#endif -#ifdef DR_AUDIO_HAS_FLAC_STDIO - if (dra_decoder_open__flac(pDecoder)) { - return DRA_RESULT_SUCCESS; - } - onSeek(pUserData, 0, dra_seek_origin_start); -#endif -#ifdef DR_AUDIO_HAS_VORBIS_STDIO - if (dra_decoder_open__vorbis(pDecoder)) { - return DRA_RESULT_SUCCESS; - } - onSeek(pUserData, 0, dra_seek_origin_start); -#endif - - // If we get here it means we were unable to open a decoder. - return DRA_RESULT_NO_DECODER; -} - - -size_t dra_decoder__on_read_memory(void* pUserData, void* pDataOut, size_t bytesToRead) -{ - dra__memory_stream* memoryStream = (dra__memory_stream*)pUserData; - assert(memoryStream != NULL); - assert(memoryStream->dataSize >= memoryStream->currentReadPos); - - size_t bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; - if (bytesToRead > bytesRemaining) { - bytesToRead = bytesRemaining; - } - - if (bytesToRead > 0) { - memcpy(pDataOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); - memoryStream->currentReadPos += bytesToRead; - } - - return bytesToRead; -} -dr_bool32 dra_decoder__on_seek_memory(void* pUserData, int offset, dra_seek_origin origin) -{ - dra__memory_stream* memoryStream = (dra__memory_stream*)pUserData; - assert(memoryStream != NULL); - assert(offset > 0 || (offset == 0 && origin == dra_seek_origin_start)); - - if (origin == dra_seek_origin_current) { - if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { - memoryStream->currentReadPos += offset; - } else { - memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. - } - } else { - if ((dr_uint32)offset <= memoryStream->dataSize) { - memoryStream->currentReadPos = offset; - } else { - memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. - } - } - - return DR_TRUE; -} - -dra_result dra_decoder_open_memory(dra_decoder* pDecoder, const void* pData, size_t dataSize) -{ - if (pDecoder == NULL) return DRA_RESULT_INVALID_ARGS; - memset(pDecoder, 0, sizeof(*pDecoder)); - - if (pData == NULL || dataSize == 0) return DRA_RESULT_INVALID_ARGS; - - // Prefer the backend's native APIs. -#if defined(DR_AUDIO_HAS_WAV) - if (dra_decoder_open_memory__wav(pDecoder, pData, dataSize)) { - return DRA_RESULT_SUCCESS; - } -#endif -#if defined(DR_AUDIO_HAS_FLAC) - if (dra_decoder_open_memory__flac(pDecoder, pData, dataSize)) { - return DRA_RESULT_SUCCESS; - } -#endif -#if defined(DR_AUDIO_HAS_VORBIS) - if (dra_decoder_open_memory__vorbis(pDecoder, pData, dataSize)) { - return DRA_RESULT_SUCCESS; - } -#endif - - // If we get here it means the backend does not have a native memory loader so we'll need to it ourselves. - dra__memory_stream memoryStream; - memoryStream.data = (const unsigned char*)pData; - memoryStream.dataSize = dataSize; - memoryStream.currentReadPos = 0; - dra_result result = dra_decoder_open(pDecoder, dra_decoder__on_read_memory, dra_decoder__on_seek_memory, &memoryStream); - if (result != DRA_RESULT_SUCCESS) { - return result; - } - - pDecoder->memoryStream = memoryStream; - pDecoder->pUserData = &pDecoder->memoryStream; - - return DRA_RESULT_SUCCESS; -} - - -#ifndef DR_AUDIO_NO_STDIO -size_t dra_decoder__on_read_stdio(void* pUserData, void* pDataOut, size_t bytesToRead) -{ - return fread(pDataOut, 1, bytesToRead, (FILE*)pUserData); -} -dr_bool32 dra_decoder__on_seek_stdio(void* pUserData, int offset, dra_seek_origin origin) -{ - return fseek((FILE*)pUserData, offset, (origin == dra_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; -} - -dra_result dra_decoder_open_file(dra_decoder* pDecoder, const char* filePath) -{ - if (pDecoder == NULL) return DRA_RESULT_INVALID_ARGS; - memset(pDecoder, 0, sizeof(*pDecoder)); - - if (filePath == NULL) return DR_FALSE; - - // When opening a decoder from a file it's preferrable to use the backend's native file IO APIs if it has them. -#if defined(DR_AUDIO_HAS_WAV) && defined(DR_AUDIO_HAS_WAV_STDIO) - if (dra_decoder_open_file__wav(pDecoder, filePath)) { - return DRA_RESULT_SUCCESS; - } -#endif -#if defined(DR_AUDIO_HAS_FLAC) && defined(DR_AUDIO_HAS_FLAC_STDIO) - if (dra_decoder_open_file__flac(pDecoder, filePath)) { - return DRA_RESULT_SUCCESS; - } -#endif -#if defined(DR_AUDIO_HAS_VORBIS) && defined(DR_AUDIO_HAS_VORBIS_STDIO) - if (dra_decoder_open_file__vorbis(pDecoder, filePath)) { - return DRA_RESULT_SUCCESS; - } -#endif - - // If we get here it means we were unable to open the decoder using any of the backends' native file IO - // APIs. In this case we fall back to a generic method. - FILE* pFile = dra__fopen(filePath); - if (pFile == NULL) { - return DRA_RESULT_FAILED_TO_OPEN_FILE; - } - - dra_result result = dra_decoder_open(pDecoder, dra_decoder__on_read_stdio, dra_decoder__on_seek_stdio, pFile); - if (result != DRA_RESULT_SUCCESS) { - fclose(pFile); - return result; - } - - return DRA_RESULT_SUCCESS; -} -#endif - -void dra_decoder_close(dra_decoder* pDecoder) -{ - if (pDecoder == NULL) { - return; - } - - if (pDecoder->onDelete) { - pDecoder->onDelete(pDecoder->pBackendDecoder); - } - -#ifndef DR_AUDIO_NO_STDIO - if (pDecoder->onRead == dra_decoder__on_read_stdio) { - fclose((FILE*)pDecoder->pUserData); - } -#endif -} - -dr_uint64 dra_decoder_read_f32(dra_decoder* pDecoder, dr_uint64 samplesToRead, float* pSamplesOut) -{ - if (pDecoder == NULL || pSamplesOut == NULL) { - return 0; - } - - return pDecoder->onReadSamples(pDecoder->pBackendDecoder, samplesToRead, pSamplesOut); -} - -dr_bool32 dra_decoder_seek_to_sample(dra_decoder* pDecoder, dr_uint64 sample) -{ - if (pDecoder == NULL) { - return DR_FALSE; - } - - return pDecoder->onSeekSamples(pDecoder->pBackendDecoder, sample); -} - - -float* dra_decoder__full_decode_and_close(dra_decoder* pDecoder, unsigned int* channelsOut, unsigned int* sampleRateOut, dr_uint64* totalSampleCountOut) -{ - assert(pDecoder != NULL); - - float* pSampleData = NULL; - dr_uint64 totalSampleCount = pDecoder->totalSampleCount; - - if (totalSampleCount == 0) - { - float buffer[4096]; - - size_t sampleDataBufferSize = sizeof(buffer); - pSampleData = (float*)malloc(sampleDataBufferSize); - if (pSampleData == NULL) { - goto on_error; - } - - dr_uint64 samplesRead; - while ((samplesRead = (dr_uint64)dra_decoder_read_f32(pDecoder, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0) - { - if (((totalSampleCount + samplesRead) * sizeof(float)) > sampleDataBufferSize) { - sampleDataBufferSize *= 2; - float* pNewSampleData = (float*)realloc(pSampleData, sampleDataBufferSize); - if (pNewSampleData == NULL) { - free(pSampleData); - goto on_error; - } - - pSampleData = pNewSampleData; - } - - memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(float))); - totalSampleCount += samplesRead; - } - - // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to - // protect those ears from random noise! - memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(float))); - } - else - { - dr_uint64 dataSize = totalSampleCount * sizeof(float); - if (dataSize > SIZE_MAX) { - goto on_error; // The decoded data is too big. - } - - pSampleData = (float*)malloc((size_t)dataSize); // <-- Safe cast as per the check above. - if (pSampleData == NULL) { - goto on_error; - } - - dr_uint64 samplesDecoded = dra_decoder_read_f32(pDecoder, pDecoder->totalSampleCount, pSampleData); - if (samplesDecoded != pDecoder->totalSampleCount) { - free(pSampleData); - goto on_error; // Something went wrong when decoding the FLAC stream. - } - } - - - if (channelsOut) *channelsOut = pDecoder->channels; - if (sampleRateOut) *sampleRateOut = pDecoder->sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount; - - dra_decoder_close(pDecoder); - return pSampleData; - -on_error: - dra_decoder_close(pDecoder); - return NULL; -} - -float* dra_decoder_open_and_decode_f32(dra_decoder_on_read_proc onRead, dra_decoder_on_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount) -{ - // Safety. - if (channels) *channels = 0; - if (sampleRate) *sampleRate = 0; - if (totalSampleCount) *totalSampleCount = 0; - - dra_decoder decoder; - dra_result result = dra_decoder_open(&decoder, onRead, onSeek, pUserData); - if (result != DRA_RESULT_SUCCESS) { - return NULL; - } - - return dra_decoder__full_decode_and_close(&decoder, channels, sampleRate, totalSampleCount); -} - -float* dra_decoder_open_and_decode_memory_f32(const void* pData, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount) -{ - // Safety. - if (channels) *channels = 0; - if (sampleRate) *sampleRate = 0; - if (totalSampleCount) *totalSampleCount = 0; - - dra_decoder decoder; - dra_result result = dra_decoder_open_memory(&decoder, pData, dataSize); - if (result != DRA_RESULT_SUCCESS) { - return NULL; - } - - return dra_decoder__full_decode_and_close(&decoder, channels, sampleRate, totalSampleCount); -} - -#ifndef DR_AUDIO_NO_STDIO -float* dra_decoder_open_and_decode_file_f32(const char* filePath, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount) -{ - // Safety. - if (channels) *channels = 0; - if (sampleRate) *sampleRate = 0; - if (totalSampleCount) *totalSampleCount = 0; - - dra_decoder decoder; - dra_result result = dra_decoder_open_file(&decoder, filePath); - if (result != DRA_RESULT_SUCCESS) { - return NULL; - } - - return dra_decoder__full_decode_and_close(&decoder, channels, sampleRate, totalSampleCount); -} -#endif - - - -//// High Level Helper APIs //// - -#ifndef DR_AUDIO_NO_STDIO -dra_result dra_voice_create_from_file(dra_device* pDevice, const char* filePath, dra_voice** ppVoice) -{ - if (pDevice == NULL || filePath == NULL) return DRA_RESULT_INVALID_ARGS; - - unsigned int channels; - unsigned int sampleRate; - dr_uint64 totalSampleCount; - float* pSampleData = dra_decoder_open_and_decode_file_f32(filePath, &channels, &sampleRate, &totalSampleCount); - if (pSampleData == NULL) { - return DRA_RESULT_UNKNOWN_ERROR; - } - - dra_result result = dra_voice_create(pDevice, dra_format_f32, channels, sampleRate, (size_t)totalSampleCount * sizeof(float), pSampleData, ppVoice); - - free(pSampleData); - return result; -} -#endif - - -//// High Level World APIs //// - -dra_sound_world* dra_sound_world_create(dra_device* pPlaybackDevice) -{ - dra_sound_world* pWorld = (dra_sound_world*)calloc(1, sizeof(*pWorld)); - if (pWorld == NULL) { - goto on_error; - } - - pWorld->pPlaybackDevice = pPlaybackDevice; - if (pWorld->pPlaybackDevice == NULL) { - dra_result result = dra_device_create(NULL, dra_device_type_playback, &pWorld->pPlaybackDevice); - if (result != DRA_RESULT_SUCCESS) { - return NULL; - } - - pWorld->ownsPlaybackDevice = DR_TRUE; - } - - - - - return pWorld; - - -on_error: - dra_sound_world_delete(pWorld); - return NULL; -} - -void dra_sound_world_delete(dra_sound_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - if (pWorld->ownsPlaybackDevice) { - dra_device_delete(pWorld->pPlaybackDevice); - } - - free(pWorld); -} - - -void dra_sound_world__on_inline_sound_stop(dr_uint64 eventID, void* pUserData) -{ - (void)eventID; - - dra_sound* pSound = (dra_sound*)pUserData; - assert(pSound != NULL); - - dra_sound_delete(pSound); -} - -void dra_sound_world_play_inline(dra_sound_world* pWorld, dra_sound_desc* pDesc, dra_mixer* pMixer) -{ - if (pWorld == NULL || pDesc == NULL) { - return; - } - - // An inline sound is just like any other, except it never loops and it's deleted automatically when it stops playing. Therefore what - // we need to do is attach an event handler to the voice's stop callback which is where the sound will be deleted. - dra_sound* pSound = dra_sound_create(pWorld, pDesc); - if (pSound == NULL) { - return; - } - - if (pMixer != NULL) { - dra_sound_attach_to_mixer(pSound, pMixer); - } - - dra_voice_set_on_stop(pSound->pVoice, dra_sound_world__on_inline_sound_stop, pSound); - dra_sound_play(pSound, DR_FALSE); -} - -void dra_sound_world_play_inline_3f(dra_sound_world* pWorld, dra_sound_desc* pDesc, dra_mixer* pMixer, float xPos, float yPos, float zPos) -{ - if (pWorld == NULL || pDesc == NULL) { - return; - } - - // TODO: Implement 3D positioning once the effects framework is in. - (void)xPos; - (void)yPos; - (void)zPos; - dra_sound_world_play_inline(pWorld, pDesc, pMixer); -} - -void dra_sound_world_stop_all_sounds(dra_sound_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - // When sounds are stopped the on_stop event handler will be fired. It is possible for the implementation of this event handler to - // delete the sound, so we'll first need to gather the sounds into a separate list. - size_t voiceCount = dra_mixer_count_attached_voices_recursive(pWorld->pPlaybackDevice->pMasterMixer); - if (voiceCount == 0) { - return; - } - - dra_voice** ppVoices = (dra_voice**)malloc(voiceCount * sizeof(*ppVoices)); - if (ppVoices == NULL) { - return; - } - - voiceCount = dra_mixer_gather_attached_voices_recursive(pWorld->pPlaybackDevice->pMasterMixer, ppVoices); - assert(voiceCount != 0); - - for (size_t iVoice = 0; iVoice < voiceCount; ++iVoice) { - dra_voice_stop(ppVoices[iVoice]); - } - - free(ppVoices); -} - -void dra_sound_world_set_listener_position(dra_sound_world* pWorld, float xPos, float yPos, float zPos) -{ - if (pWorld == NULL) { - return; - } - - // TODO: Implement me. - (void)xPos; - (void)yPos; - (void)zPos; -} - -void dra_sound_world_set_listener_orientation(dra_sound_world* pWorld, float xForward, float yForward, float zForward, float xUp, float yUp, float zUp) -{ - if (pWorld == NULL) { - return; - } - - // TODO: Implement me. - (void)xForward; - (void)yForward; - (void)zForward; - (void)xUp; - (void)yUp; - (void)zUp; -} - - -dr_bool32 dra_sound__is_streaming(dra_sound* pSound) -{ - assert(pSound != NULL); - return pSound->desc.dataSize == 0 || pSound->desc.pData == NULL; -} - -dr_bool32 dra_sound__read_next_chunk(dra_sound* pSound, dr_uint64 outputSampleOffset) -{ - assert(pSound != NULL); - if (pSound->desc.onRead == NULL) { - return DR_FALSE; - } - - dr_uint64 chunkSizeInSamples = (pSound->pVoice->frameCount * pSound->pVoice->channels) / 2; - assert(chunkSizeInSamples > 0); - - dr_uint64 samplesRead = pSound->desc.onRead(pSound, chunkSizeInSamples, dra_voice_get_buffer_ptr_by_sample(pSound->pVoice, outputSampleOffset)); - if (samplesRead == 0 && !pSound->isLooping) { - dra_voice_write_silence(pSound->pVoice, outputSampleOffset, chunkSizeInSamples); - return DR_FALSE; // Ran out of samples in a non-looping buffer. - } - - if (samplesRead == chunkSizeInSamples) { - return DR_TRUE; - } - - assert(samplesRead > 0); - assert(samplesRead < chunkSizeInSamples); - - // Ran out of samples. If the sound is not looping it simply means the end of the data has been reached. The remaining samples need - // to be zeroed out to create silence. - if (!pSound->isLooping) { - dra_voice_write_silence(pSound->pVoice, outputSampleOffset + samplesRead, chunkSizeInSamples - samplesRead); - return DR_TRUE; - } - - // At this point the sound will not be looping. We want to continuously loop back to the start and keep reading samples until the - // chunk is filled. - while (samplesRead < chunkSizeInSamples) { - if (!pSound->desc.onSeek(pSound, 0)) { - return DR_FALSE; - } - - dr_uint64 samplesRemaining = chunkSizeInSamples - samplesRead; - dr_uint64 samplesJustRead = pSound->desc.onRead(pSound, samplesRemaining, dra_voice_get_buffer_ptr_by_sample(pSound->pVoice, outputSampleOffset + samplesRead)); - if (samplesJustRead == 0) { - return DR_FALSE; - } - - samplesRead += samplesJustRead; - } - - return DR_TRUE; -} - -void dra_sound__on_read_next_chunk(dr_uint64 eventID, void* pUserData) -{ - dra_sound* pSound = (dra_sound*)pUserData; - assert(pSound != NULL); - - if (pSound->stopOnNextChunk) { - pSound->stopOnNextChunk = DR_FALSE; - dra_sound_stop(pSound); - return; - } - - // The event ID is the index of the sample to write to. - dr_uint64 sampleOffset = eventID; - if (!dra_sound__read_next_chunk(pSound, sampleOffset)) { - pSound->stopOnNextChunk = DR_TRUE; - } -} - - -dra_sound* dra_sound_create(dra_sound_world* pWorld, dra_sound_desc* pDesc) -{ - if (pWorld == NULL) { - return NULL; - } - - dr_bool32 isStreaming = DR_FALSE; - dra_result result = DRA_RESULT_SUCCESS; - - dra_sound* pSound = (dra_sound*)calloc(1, sizeof(*pSound)); - if (pSound == NULL) { - result = DRA_RESULT_OUT_OF_MEMORY; - goto on_error; - } - - pSound->pWorld = pWorld; - pSound->desc = *pDesc; - - isStreaming = dra_sound__is_streaming(pSound); - if (!isStreaming) { - result = dra_voice_create(pWorld->pPlaybackDevice, pDesc->format, pDesc->channels, pDesc->sampleRate, pDesc->dataSize, pDesc->pData, &pSound->pVoice); - } else { - size_t streamingBufferSize = (pDesc->sampleRate * pDesc->channels) * 2; // 2 seconds total, 1 second chunks. Keep total an even number and a multiple of the channel count. - result = dra_voice_create(pWorld->pPlaybackDevice, pDesc->format, pDesc->channels, pDesc->sampleRate, streamingBufferSize * dra_get_bytes_per_sample_by_format(pDesc->format), NULL, &pSound->pVoice); - - // Streaming buffers require 2 playback events. As one is being played, the other is filled. The event ID is set to the sample - // index of the next chunk that needs updating and is used in determining where to place new data. - dra_voice_add_playback_event(pSound->pVoice, 0, streamingBufferSize/2, dra_sound__on_read_next_chunk, pSound); - dra_voice_add_playback_event(pSound->pVoice, streamingBufferSize/2, 0, dra_sound__on_read_next_chunk, pSound); - } - - if (result != DRA_RESULT_SUCCESS) { - goto on_error; - } - - pSound->pVoice->pUserData = pSound; - - - // Streaming buffers need to have an initial chunk of data loaded before returning. This ensures the internal buffer contains valid audio data in - // preparation for being played for the first time. - if (isStreaming) { - if (!dra_sound__read_next_chunk(pSound, 0)) { - goto on_error; - } - } - - return pSound; - -on_error: - dra_sound_delete(pSound); - return NULL; -} - - - -void dra_sound__on_delete_decoder(dra_sound* pSound) -{ - dra_decoder* pDecoder = (dra_decoder*)pSound->desc.pUserData; - assert(pDecoder != NULL); - - dra_decoder_close(pDecoder); - free(pDecoder); -} - -dr_uint64 dra_sound__on_read_decoder(dra_sound* pSound, dr_uint64 samplesToRead, void* pSamplesOut) -{ - dra_decoder* pDecoder = (dra_decoder*)pSound->desc.pUserData; - assert(pDecoder != NULL); - - return dra_decoder_read_f32(pDecoder, samplesToRead, (float*)pSamplesOut); -} - -dr_bool32 dra_sound__on_seek_decoder(dra_sound* pSound, dr_uint64 sample) -{ - dra_decoder* pDecoder = (dra_decoder*)pSound->desc.pUserData; - assert(pDecoder != NULL); - - return dra_decoder_seek_to_sample(pDecoder, sample); -} - -#ifndef DR_AUDIO_NO_STDIO -dra_sound* dra_sound_create_from_file(dra_sound_world* pWorld, const char* filePath) -{ - if (pWorld == NULL || filePath == NULL) { - return NULL; - } - - dra_decoder* pDecoder = (dra_decoder*)malloc(sizeof(*pDecoder)); - if (pDecoder == NULL) { - return NULL; - } - - dra_result result = dra_decoder_open_file(pDecoder, filePath); - if (result != DRA_RESULT_SUCCESS) { - free(pDecoder); - return NULL; - } - - dra_sound_desc desc; - desc.format = dra_format_f32; - desc.channels = pDecoder->channels; - desc.sampleRate = pDecoder->sampleRate; - desc.dataSize = 0; - desc.pData = NULL; - desc.onDelete = dra_sound__on_delete_decoder; - desc.onRead = dra_sound__on_read_decoder; - desc.onSeek = dra_sound__on_seek_decoder; - desc.pUserData = pDecoder; - - dra_sound* pSound = dra_sound_create(pWorld, &desc); - - // After creating the sound, the audio data of a non-streaming voice can be deleted. - if (desc.pData != NULL) { - free(desc.pData); - } - - return pSound; -} -#endif - -void dra_sound_delete(dra_sound* pSound) -{ - if (pSound == NULL) { - return; - } - - if (pSound->pVoice != NULL) { - dra_voice_delete(pSound->pVoice); - } - - if (pSound->desc.onDelete) { - pSound->desc.onDelete(pSound); - } - - free(pSound); -} - - -void dra_sound_play(dra_sound* pSound, dr_bool32 loop) -{ - if (pSound == NULL) { - return; - } - - // The voice is always set to loop for streaming sounds. - if (dra_sound__is_streaming(pSound)) { - dra_voice_play(pSound->pVoice, DR_TRUE); - } else { - dra_voice_play(pSound->pVoice, loop); - } - - pSound->isLooping = loop; -} - -void dra_sound_stop(dra_sound* pSound) -{ - if (pSound == NULL) { - return; - } - - dra_voice_stop(pSound->pVoice); -} - - -void dra_sound_attach_to_mixer(dra_sound* pSound, dra_mixer* pMixer) -{ - if (pSound == NULL) { - return; - } - - if (pMixer == NULL) { - pMixer = pSound->pWorld->pPlaybackDevice->pMasterMixer; - } - - dra_mixer_attach_voice(pMixer, pSound->pVoice); -} - - -void dra_sound_set_on_stop(dra_sound* pSound, dra_event_proc proc, void* pUserData) -{ - dra_voice_set_on_stop(pSound->pVoice, proc, pUserData); -} - -void dra_sound_set_on_play(dra_sound* pSound, dra_event_proc proc, void* pUserData) -{ - dra_voice_set_on_play(pSound->pVoice, proc, pUserData); -} - -#endif //DR_AUDIO_IMPLEMENTATION - - -// TODO -// -// - Forward declare every backend function and document them. -// - Add support for the push API in stb_vorbis. - -// DEVELOPMENT NOTES AND BRAINSTORMING -// -// This is just random brainstorming and is likely very out of date and often just outright incorrect. -// -// -// Latency -// -// When a device is created it'll create a "hardware buffer" which is basically the buffer that the hardware -// device will read from when it needs to play audio. The hardware buffer is divided into two halves. As the -// buffer plays, it moves the playback pointer forward through the buffer and loops. When it hits the half -// way point it notifies the application that it needs more data to continue playing. Once one half starts -// playing the data within it is committed and cannot be changed. The size of each half determines the latency -// of the device. -// -// It sounds tempting to set this to something small like 1ms, but making it too small will -// increase the chance that the CPU won't be able to keep filling it with fresh data. In addition it will -// incrase overall CPU usage because operating system's scheduler will need to wake up the thread more often. -// Increasing the latency will increase memory usage and make playback of new sound sources take longer to -// begin playing. For example, if the latency was set to something like 1 second, a sound effect in a game -// may take up to a whole second to start playing. A balance needs to be made when setting the latency, and -// it can be configured when the device is created. -// -// (mention the fragments system to help avoiding the CPU running out of time to fill new audio data) -// -// -// Mixing -// -// Mixing is done via dra_mixer objects. Buffers can be attached to a mixer, but not more than one at a time. -// By default buffers are attached to a master mixer. Effects like volume can be applied on a per-buffer and -// per-mixer basis. -// -// Mixers can be chained together in a hierarchial manner. Child mixers will be mixed first with the result -// then passed on to higher level mixing. The master mixer is always the top level mixer. -// -// An obvious use case for mixers in games is to have separate volume controls for different categories of -// sounds, such as music, voices and sounds effects. Another example may be in music production where you may -// want to have separate mixers for vocal tracks, percussion tracks, etc. -// -// A mixer can be thought of as a complex buffer - it can be played/stopped/paused and have effects such as -// volume apllied to it. All of this affects all attached buffers and sub-mixers. You can, for example, pause -// every buffer attached to the mixer by simply pausing the mixer. This is an efficient and easy way to pause -// a group of audio buffers at the same time, such as when the user hits the pause button in a game. -// -// Every device includes a master mixer which is the one that buffers are automatically attached to. This one -// is intentionally hidden from the public facing API in order to keep it simpler. For basic audio playback -// using the master mixer will work just fine, however for more complex sound interactions you'll want to use -// your own mixers. Mixers, like buffers, are attached to the master mixer by default -// -// -// Thread Safety -// -// Everything in dr_audio should be thread-safe. -// -// Backends are implemented as if they are always run from a single thread. It's up to the cross-platform -// section to ensure thread-safety. This is an important property because if each backend is responsible for -// their own thread safety it increases the likelyhood of subtle backend-specific bugs. -// -// Every device has their own thread for asynchronous playback. This thread is created when the device is -// created, and deleted when the device is deleted. -// -// (Note edge cases when thread-safety may be an issue) - - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_audio_ancient.h b/source/engine/thirdparty/dr_libs/old/dr_audio_ancient.h deleted file mode 100644 index 4cb62f3..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_audio_ancient.h +++ /dev/null @@ -1,4310 +0,0 @@ -// Public domain. See "unlicense" statement at the end of this file. - -// -// QUICK NOTES -// -// If you've stumbled across this library, be aware that this is very, very early in development. A lot of APIs -// are very temporary, in particular the effects API which at the moment are tied very closely to DirectSound. -// -// Currently, the only backend available is DirectSound while I figure out the API. -// -// General -// - This library is NOT thread safe. Functions can be called from any thread, but it is up to the host application -// to do synchronization. -// - This library is only concerned with playback and recording of raw audio data. It does not load audio files -// such as WAV, OGG and MP3. -// - Before you can create an output (playback) or input (recording) device you need to first create a context. -// - Each backend (DirectSound, ALSA, etc.) has it's own context. Using draudio_create_context() will find -// a backend implementation based on the platform dr_audio has been compiled for. -// - A context for a specific backend can be created as well. For example, draudio_create_context_dsound() will -// create a context which uses DirectSound as it's backend. -// - Currently, devices are enumerated once when the context is created. Thus, when a device is plugged in or -// unplugged it will not be detected by dr_audio and the context will need to be deleted and re-created. -// - Currently, dr_audio will only consider the first DRAUDIO_MAX_DEVICE_COUNT output and input devices, which -// is currently set to 16 and should be plenty for the vast majority of cases. Feel free to increase (or decrease) -// this number to suit your own requirements. -// -// Events -// - Events are handled via callbacks. The different types of events include stop, pause, play and markers. -// - The Stop event is fired when an output buffer is stopped, either from finishing it's playback or if it was -// stopped manually. -// - The Pause event is fired when the output buffer is paused. -// - The Play event is fired when the output buffer begins being played from either a stopped or paused state. -// - A Marker event is fired when the playback position of an output buffer reaches a certain point within the -// buffer. This is useful for streaming audio data because it can tell you when a particular section of the -// buffer can be filled with new data. -// - Due to the inherent multi-threaded nature of audio playback, events can be fired from any thread. It is up -// to the application to ensure events are handled safely. -// - Currently, the maximum number of markers is set by DRAUDIO_MAX_MARKER_COUNT which is set to 4 by default. This -// can be increased, however doing so increases memory usage for each sound buffer. -// -// Performance Considerations -// - Creating and deleting buffers should be considered an expensive operation because there is quite a bit of thread -// management being performed under the hood. Prefer caching sound buffers. -// - -// -// OPTIONS -// -// #define DRAUDIO_NO_DIRECTSOUND -// Disables support for the DirectSound backend. Note that at the moment this is the only backend available for -// Windows platforms, so you will likely not want to set this. DirectSound will only be compiled on Win32 builds. -// - -// -// TODO -// -// - DirectSound: Consider using Win32 critical sections instead of events where possible. -// - DirectSound: Remove the semaphore and replace with an auto-reset event. -// - Implement a better error handling API. -// - Implement effects -// - Implement velocity -// - Implement cones -// - Implement attenuation min/max distances -// - -#ifndef dr_audio_h -#define dr_audio_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - - -#define DRAUDIO_MAX_DEVICE_COUNT 16 -#define DRAUDIO_MAX_MARKER_COUNT 4 -#define DRAUDIO_MAX_MESSAGE_QUEUE_SIZE 1024 // The maximum number of messages that can be cached in the internal message queues. - - -#if defined(_WIN32) && !defined(DRAUDIO_NO_DIRECTSOUND) -#define DRAUDIO_BUILD_DSOUND -#endif - - -#define DRAUDIO_EVENT_ID_STOP 0xFFFFFFFF -#define DRAUDIO_EVENT_ID_PAUSE 0xFFFFFFFE -#define DRAUDIO_EVENT_ID_PLAY 0xFFFFFFFD -#define DRAUDIO_EVENT_ID_MARKER 0 - -#define DRAUDIO_ENABLE_3D (1 << 0) -#define DRAUDIO_RELATIVE_3D (1 << 1) // <-- Uses relative 3D positioning by default instead of absolute. Only used if DRAUDIO_ENABLE_3D is also specified. - - -// Data formats. -typedef enum -{ - draudio_format_pcm, - draudio_format_float - -} draudio_format; - -// Playback states. -typedef enum -{ - draudio_stopped, - draudio_paused, - draudio_playing - -} draudio_playback_state; - -// Effect types. -typedef enum -{ - draudio_effect_type_none, - draudio_effect_type_i3dl2reverb, - draudio_effect_type_chorus, - draudio_effect_type_compressor, - draudio_effect_type_distortion, - draudio_effect_type_echo, - draudio_effect_type_flanger - -} draudio_effect_type; - -// 3D processing modes. -typedef enum -{ - draudio_3d_mode_absolute, - draudio_3d_mode_relative, - draudio_3d_mode_disabled - -} draudio_3d_mode; - - -typedef struct draudio_context draudio_context; -typedef struct draudio_device draudio_device; -typedef struct draudio_buffer draudio_buffer; - -typedef void (* draudio_event_callback_proc)(draudio_buffer* pBuffer, unsigned int eventID, void *pUserData); - -typedef struct -{ - /// The callback function. - draudio_event_callback_proc callback; - - /// The user data. - void* pUserData; - -} draudio_event_callback; - -typedef struct -{ - /// The description of the device. - char description[256]; - -} draudio_device_info; - -typedef struct -{ - /// Boolean flags. - /// DRAUDIO_ENABLE_3D: Enable 3D positioning - unsigned int flags; - - /// The data format. - draudio_format format; - - /// The number of channels. This should be 1 for mono, 2 for stereo. - unsigned int channels; - - /// The sample rate. - unsigned int sampleRate; - - /// The number of bits per sample. - unsigned int bitsPerSample; - - /// The size in bytes of the data. - size_t sizeInBytes; - - /// A pointer to the initial data. - void* pData; - -} draudio_buffer_desc; - -typedef struct -{ - /// The effect type. - draudio_effect_type type; - - struct - { - float room; - float roomHF; - float roomRolloffFactor; - float decayTime; - float reflections; - float reflectionsDelay; - float reverb; - float reverbDelay; - float diffusion; - float density; - float hfReference; - } i3dl2reverb; - - struct - { - int waveform; - int phase; - float depth; - float feedback; - float frequency; - float delay; - } chorus; - - struct - { - float gain; - float attack; - float release; - float threshold; - float ratio; - float predelay; - } compressor; - - struct - { - float gain; - float edge; - float postEQCenterFrequency; - float postEQBandwidth; - float preLowpassCutoff; - } distortion; - - struct - { - float wetDryMix; - float feedback; - float leftDelay; - float rightDelay; - float panDelay; - } echo; - - struct - { - float wetDryMix; - float depth; - float feedback; - float frequency; - float waveform; - float delay; - float phase; - } flanger; - -} draudio_effect; - - -/// Creates a context which chooses an appropriate backend based on the given platform. -draudio_context* draudio_create_context(); - -#ifdef DRAUDIO_BUILD_DSOUND -/// Creates a context that uses DirectSound for it's backend. -draudio_context* draudio_create_context_dsound(); -#endif - -/// Deletes the given context. -void draudio_delete_context(draudio_context* pContext); - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// OUTPUT / PLAYBACK -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -/// Retrieves the number of output devices that were enumerated when the context was created. -unsigned int draudio_get_output_device_count(draudio_context* pContext); - -/// Retrieves information about the device at the given index. -bool draudio_get_output_device_info(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut); - - -/// Creates a output device. -/// -/// @param pContext [in] A pointer to the main context. -/// @param deviceIndex [in] The index of the device. -/// -/// @remarks -/// Use a device index of 0 to use the default output device. -draudio_device* draudio_create_output_device(draudio_context* pContext, unsigned int deviceIndex); - -/// Deletes the given output device. -void draudio_delete_output_device(draudio_device* pDevice); - - -/// Create a buffer. -/// -/// @remarks -/// This will fail if 3D positioning is requested when the sound has more than 1 channel. -draudio_buffer* draudio_create_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize); - -/// Deletes the given buffer. -void draudio_delete_buffer(draudio_buffer* pBuffer); - - -/// Retrieves the size in bytes of the given buffer's extra data. -unsigned int draudio_get_buffer_extra_data_size(draudio_buffer* pBuffer); - -/// Retrieves a pointer to the given buffer's extra data. -void* draudio_get_buffer_extra_data(draudio_buffer* pBuffer); - - -/// Sets the audio data of the given buffer. -void draudio_set_buffer_data(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes); - - -/// Begins or resumes playing the given buffer. -/// -/// @remarks -/// If the sound is already playing, it will continue to play, but the \c loop setting will be replaced with that specified -/// by the most recent call. -void draudio_play(draudio_buffer* pBuffer, bool loop); - -/// Pauses playback of the given buffer. -void draudio_pause(draudio_buffer* pBuffer); - -/// Stops playback of the given buffer. -void draudio_stop(draudio_buffer* pBuffer); - -/// Retrieves the playback state of the given buffer. -draudio_playback_state draudio_get_playback_state(draudio_buffer* pBuffer); - -/// Determines whether or not the given audio buffer is looping. -bool draudio_is_looping(draudio_buffer* pBuffer); - - -/// Sets the playback position for the given buffer. -void draudio_set_playback_position(draudio_buffer* pBuffer, unsigned int position); - -/// Retrieves hte playback position of the given buffer. -unsigned int draudio_get_playback_position(draudio_buffer* pBuffer); - - -/// Sets the pan of the given buffer. -/// -/// @remarks -/// This does nothing for 3D sounds. -void draudio_set_pan(draudio_buffer* pBuffer, float pan); - -/// Retrieves the pan of the given buffer. -float draudio_get_pan(draudio_buffer* pBuffer); - - -/// Sets the volume of the given buffer. -/// -/// @param volume [in] The new volume. -/// -/// @remarks -/// Amplificiation is not currently supported, so the maximum value is 1. A value of 1 represents the volume of the original -/// data. -void draudio_set_volume(draudio_buffer* pBuffer, float volume); - -/// Retrieves the volume of the sound. -float draudio_get_volume(draudio_buffer* pBuffer); - - -/// Removes every marker. -void draudio_remove_markers(draudio_buffer* pBuffer); - -/// Registers the callback to fire when the playback position hits a certain position in the given buffer. -/// -/// @param eventID [in] The event ID that will be passed to the callback and can be used to identify a specific marker. -/// -/// @remarks -/// This will fail if the buffer is not in a stopped state. -/// @par -/// Set the event ID to DRAUDIO_EVENT_ID_MARKER + n, where "n" is your own application-specific identifier. -bool draudio_register_marker_callback(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData); - -/// Registers the callback to fire when the buffer stops playing. -/// -/// @remarks -/// This will fail if the buffer is not in a stopped state and the callback is non-null. It is fine to call this -/// with a null callback while the buffer is in the middle of playback in which case the callback will be cleared. -/// @par -/// The will replace any previous callback. -bool draudio_register_stop_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData); - -/// Registers the callback to fire when the buffer is paused. -/// -/// @remarks -/// This will fail if the buffer is not in a stopped state and the callback is non-null. It is fine to call this -/// with a null callback while the buffer is in the middle of playback in which case the callback will be cleared. -/// @par -/// The will replace any previous callback. -bool draudio_register_pause_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData); - -/// Registers the callback to fire when the buffer begins playing from either a stopped or paused state. -/// -/// @remarks -/// This will fail if the buffer is not in a stopped state and the callback is non-null. It is fine to call this -/// with a null callback while the buffer is in the middle of playback in which case the callback will be cleared. -/// @par -/// The will replace any previous callback. -bool draudio_register_play_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData); - - -/// Retrieves the callback that is currently set for the stop event. -draudio_event_callback draudio_get_stop_callback(draudio_buffer* pBuffer); - -/// Retrieves the callback that is currently set for the pause event. -draudio_event_callback draudio_get_pause_callback(draudio_buffer* pBuffer); - -/// Retrieves the callback that is currently set for the play event. -draudio_event_callback draudio_get_play_callback(draudio_buffer* pBuffer); - - -/// Sets the position of the given buffer in 3D space. -/// -/// @remarks -/// This does nothing for buffers that do not support 3D positioning. -void draudio_set_position(draudio_buffer* pBuffer, float x, float y, float z); - -/// Retrieves the position of the given buffer in 3D space. -void draudio_get_position(draudio_buffer* pBuffer, float* pPosOut); - -/// Sets the position of the listener for the given output device. -void draudio_set_listener_position(draudio_device* pDevice, float x, float y, float z); - -/// Retrieves the position of the listner for the given output device. -void draudio_get_listener_position(draudio_device* pDevice, float* pPosOut); - -/// Sets the orientation of the listener for the given output device. -void draudio_set_listener_orientation(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ); - -/// Retrieves the orientation of the listener for the given output device. -void draudio_get_listener_orientation(draudio_device* pDevice, float* pForwardOut, float* pUpOut); - - -/// Sets the 3D processing mode (absolute, relative or disabled). -/// -/// @remarks -/// This applies to position, orientation and velocity. -void draudio_set_3d_mode(draudio_buffer* pBuffer, draudio_3d_mode mode); - -/// Retrieves the 3D processing mode (absolute, relative or disabled). -draudio_3d_mode draudio_get_3d_mode(draudio_buffer* pBuffer); - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// INPUT / RECORDING -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// HIGH-LEVEL API -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -//// SYNCHRONIZATION //// - -typedef void* draudio_mutex; - -/// Creates a mutex object. -draudio_mutex draudio_create_mutex(); - -/// Deletes a mutex object. -void draudio_delete_mutex(draudio_mutex mutex); - -/// Locks the given mutex. -void draudio_lock_mutex(draudio_mutex mutex); - -/// Unlocks the given mutex. -void draudio_unlock_mutex(draudio_mutex mutex); - - - - -//// STREAMING //// -typedef int draudio_bool; - -typedef draudio_bool (* draudio_stream_read_proc)(void* pUserData, void* pDataOut, size_t bytesToRead, size_t* bytesReadOut); -typedef draudio_bool (* draudio_stream_seek_proc)(void* pUserData, size_t offsetInBytesFromStart); - -typedef struct -{ - /// A pointer to the user data to pass to each callback. - void* pUserData; - - /// A pointer to the function to call when more data needs to be read. - draudio_stream_read_proc read; - - /// Seeks source data from the beginning of the file. - draudio_stream_seek_proc seek; - -} draudio_streaming_callbacks; - - -/// Creates a buffer that's pre-configured for use for streaming audio data. -/// -/// @remarks -/// This function is just a high-level convenience wrapper. The returned buffer is just a regular buffer with pre-configured -/// markers attached to the buffer. This will attach 3 markers in total which means there is only DRAUDIO_MAX_MARKER_COUNT - 3 -/// marker slots available to the application. -/// @par -/// You must play the buffer with draudio_play_streaming_buffer() because the underlying buffer management is slightly different -/// to a regular buffer. -/// @par -/// Looping and stop callbacks may be inaccurate by up to half a second. -/// @par -/// Callback functions use bytes to determine how much data to process. This is always a multiple of samples * channels, however. -/// @par -/// The first chunk of data is not loaded until the buffer is played with draudio_play_streaming_buffer(). -draudio_buffer* draudio_create_streaming_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, draudio_streaming_callbacks callbacks, unsigned int extraDataSize); - -/// Retrieves the size of the extra data of the given streaming buffer.. -size_t draudio_get_streaming_buffer_extra_data_size(draudio_buffer* pBuffer); - -/// Retrieves a pointer to the extra data of the given streaming buffer. -void* draudio_get_streaming_buffer_extra_data(draudio_buffer* pBuffer); - -/// Begins playing the given streaming buffer. -bool draudio_play_streaming_buffer(draudio_buffer* pBuffer, bool loop); - -/// Determines whether or not the given streaming buffer is looping. -bool draudio_is_streaming_buffer_looping(draudio_buffer* pBuffer); - - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Sound World -// -// When a sound is created, whether or not it will be streamed is determined by -// whether or not a pointer to some initial data is specified when creating the -// sound. When initial data is specified, the sound data will be loaded into -// buffer once at creation time. If no data is specified, sound data will be -// loaded dynamically at playback time. -// -/////////////////////////////////////////////////////////////////////////////// - -typedef struct draudio_sound draudio_sound; -typedef struct draudio_world draudio_world; - -typedef void (* draudio_on_sound_delete_proc) (draudio_sound* pSound); -typedef bool (* draudio_on_sound_read_data_proc)(draudio_sound* pSound, void* pDataOut, size_t bytesToRead, size_t* bytesReadOut); -typedef bool (* draudio_on_sound_seek_data_proc)(draudio_sound* pSound, size_t offsetInBytesFromStart); - -/// The structure that is used for creating a sound object. -typedef struct -{ - /// Boolean flags. - /// DRAUDIO_ENABLE_3D: Enable 3D positioning - unsigned int flags; - - /// The data format. - draudio_format format; - - /// The number of channels. This should be 1 for mono, 2 for stereo. - unsigned int channels; - - /// The sample rate. - unsigned int sampleRate; - - /// The number of bits per sample. - unsigned int bitsPerSample; - - /// The size in bytes of the data. When this is non-zero, and pInitialData is non-null, the onRead and onSeek streaming - /// callbacks are not used, and instead the sound's audio data is made up exclusively with this data. - size_t sizeInBytes; - - /// A pointer to the initial data. Can be null, in which case the audio data is streamed with the onRead and onSeek - /// callbacks below. It is an error for this to be null in addition to onRead and onSeek. - void* pData; - - - /// A pointer to the function to call when the sound is being deleted. This gives the application the opportunity - /// to delete internal objects that are used for streaming or whatnot. - draudio_on_sound_delete_proc onDelete; - - /// A pointer to the function to call when dr_audio needs to request a chunk of audio data. This is only used when - /// streaming data. - draudio_on_sound_read_data_proc onRead; - - /// A pointer to the function to call when dr_audio needs to seek the audio data. This is only used when streaming - /// data. - draudio_on_sound_seek_data_proc onSeek; - - - /// The size of the extra data to associate with the sound. Extra data is how an application can link custom data to the - /// sound object. - unsigned int extraDataSize; - - /// A pointer to a buffer containing the initial extra data. This buffer is copied when the sound is initially created, - /// and can be null. - const void* pExtraData; - -} draudio_sound_desc; - -struct draudio_sound -{ - /// A pointer to the world that owns the sound. - draudio_world* pWorld; - - /// A pointer to the audio buffer for playback. - draudio_buffer* pBuffer; - - - /// [Internal Use Only] The state of the buffer's playback at the time the associated world overwrote it. - draudio_playback_state prevPlaybackState; - - /// [Internal Use Only] A pointer to the next sound in the local list. - draudio_sound* pNextSound; - - /// [Internal Use Only] A pointer ot the previous sound in the local list. - draudio_sound* pPrevSound; - - /// [Internal Use Only] Keeps track of whether or not a streaming buffer is being used. - bool isUsingStreamingBuffer; - - /// [Internal Use Only] Keeps track of whether or not the sound has been marked for deletion. This is used to - /// ensure onRead and onSeek are never called after the sound has been deleted. This scenario is possible because - /// these functions are called in response to the sound buffer hitting markers which can be slightly delayed - /// due to multi-threading synchronization. - bool markedForDeletion; - - /// [Internal Use Only] the onDelete function. Can be null. - draudio_on_sound_delete_proc onDelete; - - /// [Internal Use Only] The onRead streaming function. Can be null, in which case streaming will not be used. - draudio_on_sound_read_data_proc onRead; - - /// [Internal Use Only] The onSeek streaming function. Can be null, in which case streaming will not be used. - draudio_on_sound_seek_data_proc onSeek; -}; - -struct draudio_world -{ - /// A pointer to the dr_audio device to output audio to. - draudio_device* pDevice; - - /// The global playback state of the world. - draudio_playback_state playbackState; - - /// A pointer to the first sound in the local list of sounds. - draudio_sound* pFirstSound; - - /// Mutex for thread-safety. - draudio_mutex lock; -}; - - -/// Creates a new sound world which will output audio from the given device. -draudio_world* draudio_create_world(draudio_device* pDevice); - -/// Deletes a sound world that was previously created with draudio_create_world(). -void draudio_delete_world(draudio_world* pWorld); - - -/// Creates a sound in 3D space. -draudio_sound* draudio_create_sound(draudio_world* pWorld, draudio_sound_desc desc); - -/// Deletes a sound that was previously created with draudio_create_sound(). -void draudio_delete_sound(draudio_sound* pSound); - -/// Deletes every sound from the given world. -void draudio_delete_all_sounds(draudio_world* pWorld); - - -/// Retrieves the size in bytes of the given sound's extra data. -size_t draudio_get_sound_extra_data_size(draudio_sound* pSound); - -/// Retrieves a pointer to the buffer containing the given sound's extra data. -void* draudio_get_sound_extra_data(draudio_sound* pSound); - - -/// Plays or resumes the given sound. -void draudio_play_sound(draudio_sound* pSound, bool loop); - -/// Pauses playback the given sound. -void draudio_pause_sound(draudio_sound* pSound); - -/// Stops playback of the given sound. -void draudio_stop_sound(draudio_sound* pSound); - -/// Retrieves the playback state of the given sound. -draudio_playback_state draudio_get_sound_playback_state(draudio_sound* pSound); - -/// Determines if the given sound is looping. -bool draudio_is_sound_looping(draudio_sound* pSound); - - -/// Begins playing a sound using the given streaming callbacks. -void draudio_play_inline_sound(draudio_world* pWorld, draudio_sound_desc desc); - -/// Begins playing the given sound at the given position. -void draudio_play_inline_sound_3f(draudio_world* pWorld, draudio_sound_desc desc, float posX, float posY, float posZ); - - -/// Stops playback of all sounds in the given world. -void draudio_stop_all_sounds(draudio_world* pWorld); - -/// Pauses playback of all sounds in the given world. -void draudio_pause_all_sounds(draudio_world* pWorld); - -/// Resumes playback of all sounds in the given world. -void draudio_resume_all_sounds(draudio_world* pWorld); - - -/// Sets the callback for the stop event for the given sound. -void draudio_set_sound_stop_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData); - -/// Sets the callback for the pause event for the given sound. -void draudio_set_sound_pause_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData); - -/// Sets the callback for the play event for the given sound. -void draudio_set_sound_play_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData); - - -/// Sets the position of the given sound. -void draudio_set_sound_position(draudio_sound* pSound, float posX, float posY, float posZ); - - -/// Sets the 3D mode of the given sound (absolute positioning, relative positioning, no positioning). -void draudio_set_sound_3d_mode(draudio_sound* pSound, draudio_3d_mode mode); - -/// Retrieves the 3D mode of the given sound. -draudio_3d_mode draudio_get_sound_3d_mode(draudio_sound* pSound); - - - -#ifdef __cplusplus -} -#endif - -#endif //dr_audio_h - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_AUDIO_IMPLEMENTATION -#include -#include -#include -#include -#include - - -// Annotations -#ifndef DRAUDIO_PRIVATE -#define DRAUDIO_PRIVATE -#endif - - -//////////////////////////////////////////////////////// -// Utilities - -// strcpy() -int draudio_strcpy(char* dst, size_t dstSizeInBytes, const char* src) -{ -#if defined(_MSC_VER) - return strcpy_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - char* iDst = dst; - const char* iSrc = src; - size_t remainingSizeInBytes = dstSizeInBytes; - while (remainingSizeInBytes > 0 && iSrc[0] != '\0') - { - iDst[0] = iSrc[0]; - - iDst += 1; - iSrc += 1; - remainingSizeInBytes -= 1; - } - - if (remainingSizeInBytes > 0) { - iDst[0] = '\0'; - } else { - dst[0] = '\0'; - return ERANGE; - } - - return 0; -#endif -} - - -typedef void (* draudio_delete_context_proc)(draudio_context* pContext); -typedef draudio_device* (* draudio_create_output_device_proc)(draudio_context* pContext, unsigned int deviceIndex); -typedef void (* draudio_delete_output_device_proc)(draudio_device* pDevice); -typedef unsigned int (* draudio_get_output_device_count_proc)(draudio_context* pContext); -typedef bool (* draudio_get_output_device_info_proc)(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut); -typedef draudio_buffer* (* draudio_create_buffer_proc)(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize); -typedef void (* draudio_delete_buffer_proc)(draudio_buffer* pBuffer); -typedef unsigned int (* draudio_get_buffer_extra_data_size_proc)(draudio_buffer* pBuffer); -typedef void* (* draudio_get_buffer_extra_data_proc)(draudio_buffer* pBuffer); -typedef void (* draudio_set_buffer_data_proc)(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes); -typedef void (* draudio_play_proc)(draudio_buffer* pBuffer, bool loop); -typedef void (* draudio_pause_proc)(draudio_buffer* pBuffer); -typedef void (* draudio_stop_proc)(draudio_buffer* pBuffer); -typedef draudio_playback_state (* draudio_get_playback_state_proc)(draudio_buffer* pBuffer); -typedef void (* draudio_set_playback_position_proc)(draudio_buffer* pBuffer, unsigned int position); -typedef unsigned int (* draudio_get_playback_position_proc)(draudio_buffer* pBuffer); -typedef void (* draudio_set_pan_proc)(draudio_buffer* pBuffer, float pan); -typedef float (* draudio_get_pan_proc)(draudio_buffer* pBuffer); -typedef void (* draudio_set_volume_proc)(draudio_buffer* pBuffer, float volume); -typedef float (* draudio_get_volume_proc)(draudio_buffer* pBuffer); -typedef void (* draudio_remove_markers_proc)(draudio_buffer* pBuffer); -typedef bool (* draudio_register_marker_callback_proc)(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData); -typedef bool (* draudio_register_stop_callback_proc)(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData); -typedef bool (* draudio_register_pause_callback_proc)(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData); -typedef bool (* draudio_register_play_callback_proc)(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData); -typedef void (* draudio_set_position_proc)(draudio_buffer* pBuffer, float x, float y, float z); -typedef void (* draudio_get_position_proc)(draudio_buffer* pBuffer, float* pPosOut); -typedef void (* draudio_set_listener_position_proc)(draudio_device* pDevice, float x, float y, float z); -typedef void (* draudio_get_listener_position_proc)(draudio_device* pDevice, float* pPosOut); -typedef void (* draudio_set_listener_orientation_proc)(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ); -typedef void (* draudio_get_listener_orientation_proc)(draudio_device* pDevice, float* pForwardOut, float* pUpOut); -typedef void (* draudio_set_3d_mode_proc)(draudio_buffer* pBuffer, draudio_3d_mode mode); -typedef draudio_3d_mode (* draudio_get_3d_mode_proc)(draudio_buffer* pBuffer); - -struct draudio_context -{ - // Callbacks. - draudio_delete_context_proc delete_context; - draudio_create_output_device_proc create_output_device; - draudio_delete_output_device_proc delete_output_device; - draudio_get_output_device_count_proc get_output_device_count; - draudio_get_output_device_info_proc get_output_device_info; - draudio_create_buffer_proc create_buffer; - draudio_delete_buffer_proc delete_buffer; - draudio_get_buffer_extra_data_size_proc get_buffer_extra_data_size; - draudio_get_buffer_extra_data_proc get_buffer_extra_data; - draudio_set_buffer_data_proc set_buffer_data; - draudio_play_proc play; - draudio_pause_proc pause; - draudio_stop_proc stop; - draudio_get_playback_state_proc get_playback_state; - draudio_set_playback_position_proc set_playback_position; - draudio_get_playback_position_proc get_playback_position; - draudio_set_pan_proc set_pan; - draudio_get_pan_proc get_pan; - draudio_set_volume_proc set_volume; - draudio_get_volume_proc get_volume; - draudio_remove_markers_proc remove_markers; - draudio_register_marker_callback_proc register_marker_callback; - draudio_register_stop_callback_proc register_stop_callback; - draudio_register_pause_callback_proc register_pause_callback; - draudio_register_play_callback_proc register_play_callback; - draudio_set_position_proc set_position; - draudio_get_position_proc get_position; - draudio_set_listener_position_proc set_listener_position; - draudio_get_listener_position_proc get_listener_position; - draudio_set_listener_orientation_proc set_listener_orientation; - draudio_get_listener_orientation_proc get_listener_orientation; - draudio_set_3d_mode_proc set_3d_mode; - draudio_get_3d_mode_proc get_3d_mode; -}; - -struct draudio_device -{ - /// The context that owns this device. - draudio_context* pContext; - - /// Whether or not the device is marked for deletion. A device is not always deleted straight away, so we use this - /// to determine whether or not it has been marked for deletion. - bool markedForDeletion; -}; - -struct draudio_buffer -{ - /// The device that owns this buffer. - draudio_device* pDevice; - - /// The stop callback. - draudio_event_callback stopCallback; - - /// The pause callback. - draudio_event_callback pauseCallback; - - /// The play callback. - draudio_event_callback playCallback; - - /// Whether or not playback is looping. - bool isLooping; - - /// Whether or not the buffer is marked for deletion. A buffer is not always deleted straight away, so we use this - /// to determine whether or not it has been marked for deletion. - bool markedForDeletion; -}; - - -draudio_context* draudio_create_context() -{ - draudio_context* pContext = NULL; - -#ifdef DRAUDIO_BUILD_DSOUND - pContext = draudio_create_context_dsound(); - if (pContext != NULL) { - return pContext; - } -#endif - - - // If we get here it means we weren't able to create a context, so return NULL. Later on we're going to have a null implementation so that - // we don't ever need to return NULL here. - assert(pContext == NULL); - return pContext; -} - -void draudio_delete_context(draudio_context* pContext) -{ - if (pContext == NULL) { - return; - } - - pContext->delete_context(pContext); -} - - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// OUTPUT -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -unsigned int draudio_get_output_device_count(draudio_context* pContext) -{ - if (pContext == NULL) { - return 0; - } - - return pContext->get_output_device_count(pContext); -} - -bool draudio_get_output_device_info(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut) -{ - if (pContext == NULL) { - return false; - } - - if (pInfoOut == NULL) { - return false; - } - - return pContext->get_output_device_info(pContext, deviceIndex, pInfoOut); -} - - -draudio_device* draudio_create_output_device(draudio_context* pContext, unsigned int deviceIndex) -{ - if (pContext == NULL) { - return NULL; - } - - draudio_device* pDevice = pContext->create_output_device(pContext, deviceIndex); - if (pDevice != NULL) - { - pDevice->markedForDeletion = false; - } - - return pDevice; -} - -void draudio_delete_output_device(draudio_device* pDevice) -{ - if (pDevice == NULL) { - return; - } - - // If the device is already marked for deletion we just return straight away. However, this is an erroneous case so we trigger a failed assertion in this case. - if (pDevice->markedForDeletion) { - assert(false); - return; - } - - pDevice->markedForDeletion = true; - - assert(pDevice->pContext != NULL); - pDevice->pContext->delete_output_device(pDevice); -} - - -draudio_buffer* draudio_create_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize) -{ - if (pDevice == NULL) { - return NULL; - } - - if (pBufferDesc == NULL) { - return NULL; - } - - assert(pDevice->pContext != NULL); - - draudio_buffer* pBuffer = pDevice->pContext->create_buffer(pDevice, pBufferDesc, extraDataSize); - if (pBuffer != NULL) - { - draudio_event_callback nullcb = {NULL, NULL}; - - pBuffer->pDevice = pDevice; - pBuffer->stopCallback = nullcb; - pBuffer->pauseCallback = nullcb; - pBuffer->playCallback = nullcb; - pBuffer->isLooping = false; - pBuffer->markedForDeletion = false; - } - - return pBuffer; -} - -void draudio_delete_buffer(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return; - } - - // We don't want to do anything if the buffer is marked for deletion. - if (pBuffer->markedForDeletion) { - assert(false); - return; - } - - pBuffer->markedForDeletion = true; - - - // The sound needs to be stopped first. - draudio_stop(pBuffer); - - // Now we need to remove every event. - draudio_remove_markers(pBuffer); - draudio_register_stop_callback(pBuffer, NULL, NULL); - draudio_register_pause_callback(pBuffer, NULL, NULL); - draudio_register_play_callback(pBuffer, NULL, NULL); - - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->delete_buffer(pBuffer); -} - - -unsigned int draudio_get_buffer_extra_data_size(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return 0; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_buffer_extra_data_size(pBuffer); -} - -void* draudio_get_buffer_extra_data(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return NULL; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_buffer_extra_data(pBuffer); -} - - -void draudio_set_buffer_data(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes) -{ - if (pBuffer == NULL) { - return; - } - - if (pData == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->set_buffer_data(pBuffer, offset, pData, dataSizeInBytes); -} - -void draudio_play(draudio_buffer* pBuffer, bool loop) -{ - if (pBuffer == NULL) { - return; - } - - pBuffer->isLooping = loop; - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->play(pBuffer, loop); -} - -void draudio_pause(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->pause(pBuffer); -} - -void draudio_stop(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->stop(pBuffer); -} - -draudio_playback_state draudio_get_playback_state(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return draudio_stopped; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_playback_state(pBuffer); -} - -bool draudio_is_looping(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return false; - } - - return pBuffer->isLooping; -} - - -void draudio_set_playback_position(draudio_buffer* pBuffer, unsigned int position) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->set_playback_position(pBuffer, position); -} - -unsigned int draudio_get_playback_position(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return 0; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_playback_position(pBuffer); -} - - -void draudio_set_pan(draudio_buffer* pBuffer, float pan) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->set_pan(pBuffer, pan); -} - -float draudio_get_pan(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return 0.0f; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_pan(pBuffer); -} - - -void draudio_set_volume(draudio_buffer* pBuffer, float volume) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->set_volume(pBuffer, volume); -} - -float draudio_get_volume(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return 1.0f; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_volume(pBuffer); -} - - -void draudio_remove_markers(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->remove_markers(pBuffer); -} - -bool draudio_register_marker_callback(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData) -{ - if (pBuffer == NULL) { - return false; - } - - if (eventID == DRAUDIO_EVENT_ID_STOP || - eventID == DRAUDIO_EVENT_ID_PAUSE || - eventID == DRAUDIO_EVENT_ID_PLAY) - { - return false; - } - - if (draudio_get_playback_state(pBuffer) != draudio_stopped) { - return false; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->register_marker_callback(pBuffer, offsetInBytes, callback, eventID, pUserData); -} - -bool draudio_register_stop_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData) -{ - if (pBuffer == NULL) { - return false; - } - - if (callback != NULL && draudio_get_playback_state(pBuffer) != draudio_stopped) { - return false; - } - - pBuffer->stopCallback.callback = callback; - pBuffer->stopCallback.pUserData = pUserData; - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->register_stop_callback(pBuffer, callback, pUserData); -} - -bool draudio_register_pause_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData) -{ - if (pBuffer == NULL) { - return false; - } - - if (callback != NULL && draudio_get_playback_state(pBuffer) != draudio_stopped) { - return false; - } - - pBuffer->pauseCallback.callback = callback; - pBuffer->pauseCallback.pUserData = pUserData; - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->register_pause_callback(pBuffer, callback, pUserData); -} - -bool draudio_register_play_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData) -{ - if (pBuffer == NULL) { - return false; - } - - if (callback != NULL && draudio_get_playback_state(pBuffer) != draudio_stopped) { - return false; - } - - pBuffer->playCallback.callback = callback; - pBuffer->playCallback.pUserData = pUserData; - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->register_play_callback(pBuffer, callback, pUserData); -} - - -draudio_event_callback draudio_get_stop_callback(draudio_buffer* pBuffer) -{ - if (pBuffer != NULL) { - return pBuffer->stopCallback; - } else { - draudio_event_callback result = {NULL, NULL}; - return result; - } -} - -draudio_event_callback draudio_get_pause_callback(draudio_buffer* pBuffer) -{ - if (pBuffer != NULL) { - return pBuffer->pauseCallback; - } else { - draudio_event_callback result = {NULL, NULL}; - return result; - } -} - -draudio_event_callback draudio_get_play_callback(draudio_buffer* pBuffer) -{ - if (pBuffer != NULL) { - return pBuffer->playCallback; - } else { - draudio_event_callback result = {NULL, NULL}; - return result; - } -} - - -void draudio_set_position(draudio_buffer* pBuffer, float x, float y, float z) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->set_position(pBuffer, x, y, z); -} - -void draudio_get_position(draudio_buffer* pBuffer, float* pPosOut) -{ - if (pBuffer == NULL) { - return; - } - - if (pPosOut == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->get_position(pBuffer, pPosOut); -} - - -void draudio_set_listener_position(draudio_device* pDevice, float x, float y, float z) -{ - if (pDevice == NULL) { - return; - } - - pDevice->pContext->set_listener_position(pDevice, x, y, z); -} - -void draudio_get_listener_position(draudio_device* pDevice, float* pPosOut) -{ - if (pDevice == NULL || pPosOut == NULL) { - return; - } - - pDevice->pContext->get_listener_position(pDevice, pPosOut); -} - -void draudio_set_listener_orientation(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ) -{ - if (pDevice == NULL) { - return; - } - - pDevice->pContext->set_listener_orientation(pDevice, forwardX, forwardY, forwardZ, upX, upY, upZ); -} - -void draudio_get_listener_orientation(draudio_device* pDevice, float* pForwardOut, float* pUpOut) -{ - if (pDevice == NULL) { - return; - } - - pDevice->pContext->get_listener_orientation(pDevice, pForwardOut, pUpOut); -} - - -void draudio_set_3d_mode(draudio_buffer* pBuffer, draudio_3d_mode mode) -{ - if (pBuffer == NULL) { - return; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - pBuffer->pDevice->pContext->set_3d_mode(pBuffer, mode); -} - -draudio_3d_mode draudio_get_3d_mode(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return draudio_3d_mode_disabled; - } - - assert(pBuffer->pDevice != NULL); - assert(pBuffer->pDevice->pContext != NULL); - return pBuffer->pDevice->pContext->get_3d_mode(pBuffer); -} - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// INPUT -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - - - - - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// HIGH-LEVEL API -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -//// SYNCHRONIZATION //// - -#if defined(_WIN32) -#include - -draudio_mutex draudio_create_mutex() -{ - draudio_mutex mutex = malloc(sizeof(CRITICAL_SECTION)); - if (mutex != NULL) - { - InitializeCriticalSection((LPCRITICAL_SECTION)mutex); - } - - return mutex; -} - -void draudio_delete_mutex(draudio_mutex mutex) -{ - DeleteCriticalSection((LPCRITICAL_SECTION)mutex); - free(mutex); -} - -void draudio_lock_mutex(draudio_mutex mutex) -{ - EnterCriticalSection((LPCRITICAL_SECTION)mutex); -} - -void draudio_unlock_mutex(draudio_mutex mutex) -{ - LeaveCriticalSection((LPCRITICAL_SECTION)mutex); -} -#else -#include - -draudio_mutex draudio_create_mutex() -{ - pthread_mutex_t* mutex = malloc(sizeof(pthread_mutex_t)); - if (pthread_mutex_init(mutex, NULL) != 0) { - free(mutex); - mutex = NULL; - } - - return mutex; -} - -void draudio_delete_mutex(draudio_mutex mutex) -{ - pthread_mutex_destroy(mutex); -} - -void draudio_lock_mutex(draudio_mutex mutex) -{ - pthread_mutex_lock(mutex); -} - -void draudio_unlock_mutex(draudio_mutex mutex) -{ - pthread_mutex_unlock(mutex); -} -#endif - - - -//// STREAMING //// - -#define DRAUDIO_STREAMING_MARKER_0 DRAUDIO_EVENT_ID_MARKER + 0 -#define DRAUDIO_STREAMING_MARKER_1 DRAUDIO_EVENT_ID_MARKER + 1 - -#define DRAUDIO_STREAMING_CHUNK_INVALID 0 - -typedef struct -{ - /// The steaming buffer callbacks. - draudio_streaming_callbacks callbacks; - - /// Keeps track of whether or not we are at the start of the playback. - bool atStart; - - /// Keeps track of whether or not we should stop at the end of the next chunk. - bool stopAtEndOfCurrentChunk; - - /// Keeps track of whether or not the sound should loop. - bool isLoopingEnabled; - - /// The size of the extra data. - size_t extraDataSize; - - /// The size of an individual chunk. A chunk is half the size of the buffer. - size_t chunkSize; - - /// A pointer to the temporary buffer for loading chunk data. - unsigned char pTempChunkData[1]; - -} ea_streaming_buffer_data; - - -bool ea_streaming_buffer_load_next_chunk(draudio_buffer* pBuffer, ea_streaming_buffer_data* pStreamingData, size_t offset, size_t chunkSize) -{ - assert(pStreamingData != NULL); - assert(pStreamingData->callbacks.read != NULL); - assert(pStreamingData->callbacks.seek != NULL); - assert(pStreamingData->chunkSize >= chunkSize); - - // A chunk size of 0 is valid, but we just return immediately. - if (chunkSize == 0) { - return true; - } - - size_t bytesRead; - if (!pStreamingData->callbacks.read(pStreamingData->callbacks.pUserData, pStreamingData->pTempChunkData, chunkSize, &bytesRead)) - { - // There was an error reading the data. We might have run out of data. - return false; - } - - - pStreamingData->stopAtEndOfCurrentChunk = false; - - draudio_set_buffer_data(pBuffer, offset, pStreamingData->pTempChunkData, bytesRead); - - if (chunkSize > bytesRead) - { - // The number of bytes read is less than our chunk size. This is our cue that we've reached the end of the steam. If we're looping, we - // just seek back to the start and read more data. There is a chance the data total size of the streaming data is smaller than our - // chunk, so we actually want to do this recursively. - // - // If we're not looping, we fill the remaining data with silence. - if (pStreamingData->isLoopingEnabled) - { - pStreamingData->callbacks.seek(pStreamingData->callbacks.pUserData, 0); - return ea_streaming_buffer_load_next_chunk(pBuffer, pStreamingData, offset + bytesRead, chunkSize - bytesRead); - } - else - { - memset(pStreamingData->pTempChunkData + bytesRead, 0, chunkSize - bytesRead); - draudio_set_buffer_data(pBuffer, offset + bytesRead, pStreamingData->pTempChunkData + bytesRead, chunkSize - bytesRead); - - pStreamingData->stopAtEndOfCurrentChunk = true; - } - } - - return true; -} - -void ea_steaming_buffer_marker_callback(draudio_buffer* pBuffer, unsigned int eventID, void *pUserData) -{ - ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)pUserData; - assert(pStreamingData != NULL); - - size_t offset = 0; - if (eventID == DRAUDIO_STREAMING_MARKER_0) { - offset = pStreamingData->chunkSize; - } - - if (pStreamingData->stopAtEndOfCurrentChunk) - { - if (!pStreamingData->atStart) { - draudio_stop(pBuffer); - } - } - else - { - ea_streaming_buffer_load_next_chunk(pBuffer, pStreamingData, offset, pStreamingData->chunkSize); - } - - pStreamingData->atStart = false; -} - - -draudio_buffer* draudio_create_streaming_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, draudio_streaming_callbacks callbacks, unsigned int extraDataSize) -{ - if (callbacks.read == NULL) { - return NULL; - } - - if (pBufferDesc == NULL) { - return NULL; - } - - - // We are determining for ourselves what the size of the buffer should be. We need to create our own copy rather than modify the input descriptor. - draudio_buffer_desc bufferDesc = *pBufferDesc; - bufferDesc.sizeInBytes = pBufferDesc->sampleRate * pBufferDesc->channels * (pBufferDesc->bitsPerSample / 8); - bufferDesc.pData = NULL; - - size_t chunkSize = bufferDesc.sizeInBytes / 2; - - draudio_buffer* pBuffer = draudio_create_buffer(pDevice, &bufferDesc, sizeof(ea_streaming_buffer_data) - sizeof(unsigned char) + chunkSize + extraDataSize); - if (pBuffer == NULL) { - return NULL; - } - - - ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer); - assert(pStreamingData != NULL); - - pStreamingData->callbacks = callbacks; - pStreamingData->atStart = true; - pStreamingData->stopAtEndOfCurrentChunk = false; - pStreamingData->isLoopingEnabled = false; - pStreamingData->chunkSize = chunkSize; - - // Register two markers - one for the first half and another for the second half. When a half is finished playing we need to - // replace it with new data. - draudio_register_marker_callback(pBuffer, 0, ea_steaming_buffer_marker_callback, DRAUDIO_STREAMING_MARKER_0, pStreamingData); - draudio_register_marker_callback(pBuffer, chunkSize, ea_steaming_buffer_marker_callback, DRAUDIO_STREAMING_MARKER_1, pStreamingData); - - - return pBuffer; -} - - -size_t draudio_get_streaming_buffer_extra_data_size(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return 0; - } - - ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer); - assert(pStreamingData != NULL); - - return pStreamingData->extraDataSize; -} - -void* draudio_get_streaming_buffer_extra_data(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return NULL; - } - - ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer); - assert(pStreamingData != NULL); - - return ((char*)pStreamingData->pTempChunkData) + pStreamingData->chunkSize; -} - - -bool draudio_play_streaming_buffer(draudio_buffer* pBuffer, bool loop) -{ - if (pBuffer == NULL) { - return false; - } - - - ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer); - assert(pStreamingData != NULL); - - // If the buffer was previously in a paused state, we just play like normal. If it was in a stopped state we need to start from the beginning. - if (draudio_get_playback_state(pBuffer) == draudio_stopped) - { - // We need to load some initial data into the first chunk. - pStreamingData->atStart = true; - pStreamingData->callbacks.seek(pStreamingData->callbacks.pUserData, 0); - - if (!ea_streaming_buffer_load_next_chunk(pBuffer, pStreamingData, 0, pStreamingData->chunkSize)) - { - // There was an error loading the initial data. - return false; - } - } - - - pStreamingData->isLoopingEnabled = loop; - draudio_play(pBuffer, true); // <-- Always loop on a streaming buffer. Actual looping is done a bit differently for streaming buffers. - - return true; -} - -bool draudio_is_streaming_buffer_looping(draudio_buffer* pBuffer) -{ - if (pBuffer == NULL) { - return false; - } - - ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer); - assert(pStreamingData != NULL); - - return pStreamingData->isLoopingEnabled; -} - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Sound World -// -/////////////////////////////////////////////////////////////////////////////// - -DRAUDIO_PRIVATE draudio_bool draudio_on_sound_read_callback(void* pUserData, void* pDataOut, size_t bytesToRead, size_t* bytesReadOut) -{ - draudio_sound* pSound = (draudio_sound*)pUserData; - assert(pSound != NULL); - assert(pSound->onRead != NULL); - - bool result = false; - draudio_lock_mutex(pSound->pWorld->lock); - { - if (!pSound->markedForDeletion) { - result = pSound->onRead(pSound, pDataOut, bytesToRead, bytesReadOut); - } - } - draudio_unlock_mutex(pSound->pWorld->lock); - - return result; -} - -DRAUDIO_PRIVATE static draudio_bool draudio_on_sound_seek_callback(void* pUserData, size_t offsetInBytesFromStart) -{ - draudio_sound* pSound = (draudio_sound*)pUserData; - assert(pSound != NULL); - assert(pSound->onRead != NULL); - - bool result = false; - draudio_lock_mutex(pSound->pWorld->lock); - { - if (!pSound->markedForDeletion) { - result = pSound->onSeek(pSound, offsetInBytesFromStart); - } - } - draudio_unlock_mutex(pSound->pWorld->lock); - - return result; -} - - -DRAUDIO_PRIVATE static void draudio_inline_sound_stop_callback(draudio_buffer* pBuffer, unsigned int eventID, void *pUserData) -{ - (void)pBuffer; - (void)eventID; - - assert(pBuffer != NULL); - assert(eventID == DRAUDIO_EVENT_ID_STOP); - assert(pUserData != NULL); - - draudio_sound* pSound = (draudio_sound*)pUserData; - draudio_delete_sound(pSound); -} - - -DRAUDIO_PRIVATE void draudio_prepend_sound(draudio_sound* pSound) -{ - assert(pSound != NULL); - assert(pSound->pWorld != NULL); - assert(pSound->pPrevSound == NULL); - - draudio_lock_mutex(pSound->pWorld->lock); - { - pSound->pNextSound = pSound->pWorld->pFirstSound; - - if (pSound->pNextSound != NULL) { - pSound->pNextSound->pPrevSound = pSound; - } - - pSound->pWorld->pFirstSound = pSound; - } - draudio_unlock_mutex(pSound->pWorld->lock); -} - -DRAUDIO_PRIVATE void draudio_remove_sound_nolock(draudio_sound* pSound) -{ - assert(pSound != NULL); - assert(pSound->pWorld != NULL); - - if (pSound == pSound->pWorld->pFirstSound) { - pSound->pWorld->pFirstSound = pSound->pNextSound; - } - - if (pSound->pNextSound != NULL) { - pSound->pNextSound->pPrevSound = pSound->pPrevSound; - } - - if (pSound->pPrevSound != NULL) { - pSound->pPrevSound->pNextSound = pSound->pNextSound; - } -} - - -DRAUDIO_PRIVATE bool draudio_is_inline_sound(draudio_sound* pSound) -{ - assert(pSound != NULL); - return draudio_get_stop_callback(pSound->pBuffer).callback == draudio_inline_sound_stop_callback; -} - - -draudio_world* draudio_create_world(draudio_device* pDevice) -{ - draudio_world* pWorld = (draudio_world*)malloc(sizeof(*pWorld)); - if (pWorld != NULL) - { - pWorld->pDevice = pDevice; - pWorld->playbackState = draudio_playing; - pWorld->pFirstSound = NULL; - pWorld->lock = draudio_create_mutex(); - } - - return pWorld; -} - -void draudio_delete_world(draudio_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - // Delete every sound first. - draudio_delete_all_sounds(pWorld); - - // Delete the lock after deleting every sound because we still need thread-safety at this point. - draudio_delete_mutex(pWorld->lock); - - // Free the world last. - free(pWorld); -} - - -draudio_sound* draudio_create_sound(draudio_world* pWorld, draudio_sound_desc desc) -{ - if (pWorld == NULL) { - return NULL; - } - - if ((desc.pData == NULL || desc.sizeInBytes == 0) && (desc.onRead == NULL || desc.onSeek == NULL)) { - // When streaming is not being used, the initial data must be valid at creation time. - return NULL; - } - - draudio_sound* pSound = (draudio_sound*)malloc(sizeof(*pSound)); - if (pSound == NULL) { - return NULL; - } - - pSound->pWorld = pWorld; - pSound->prevPlaybackState = draudio_stopped; - pSound->pNextSound = NULL; - pSound->pPrevSound = NULL; - pSound->isUsingStreamingBuffer = desc.sizeInBytes == 0 || desc.pData == NULL; - pSound->markedForDeletion = false; - pSound->onDelete = desc.onDelete; - pSound->onRead = desc.onRead; - pSound->onSeek = desc.onSeek; - - draudio_buffer_desc bufferDesc; - bufferDesc.flags = desc.flags; - bufferDesc.format = desc.format; - bufferDesc.channels = desc.channels; - bufferDesc.sampleRate = desc.sampleRate; - bufferDesc.bitsPerSample = desc.bitsPerSample; - bufferDesc.sizeInBytes = desc.sizeInBytes; - bufferDesc.pData = desc.pData; - - if (pSound->isUsingStreamingBuffer) - { - draudio_streaming_callbacks streamingCallbacks; - streamingCallbacks.pUserData = pSound; - streamingCallbacks.read = draudio_on_sound_read_callback; - streamingCallbacks.seek = draudio_on_sound_seek_callback; - - pSound->pBuffer = draudio_create_streaming_buffer(pWorld->pDevice, &bufferDesc, streamingCallbacks, desc.extraDataSize); - if (pSound->pBuffer != NULL && desc.pExtraData != NULL) - { - memcpy(draudio_get_streaming_buffer_extra_data(pSound->pBuffer), desc.pExtraData, desc.extraDataSize); - } - } - else - { - pSound->pBuffer = draudio_create_buffer(pWorld->pDevice, &bufferDesc, desc.extraDataSize); - if (pSound->pBuffer != NULL && desc.pExtraData != NULL) - { - memcpy(draudio_get_buffer_extra_data(pSound->pBuffer), desc.pExtraData, desc.extraDataSize); - } - } - - - // Return NULL if we failed to create the internal audio buffer. - if (pSound->pBuffer == NULL) { - free(pSound); - return NULL; - } - - - // Only attach the sound to the internal list at the end when we know everything has worked. - draudio_prepend_sound(pSound); - - return pSound; -} - -void draudio_delete_sound(draudio_sound* pSound) -{ - if (pSound == NULL) { - return; - } - - - draudio_lock_mutex(pSound->pWorld->lock); - { - if (pSound->markedForDeletion) { - assert(false); - return; - } - - pSound->markedForDeletion = true; - - - // Remove the sound from the internal list first. - draudio_remove_sound_nolock(pSound); - - - // If we're deleting an inline sound, we want to remove the stop event callback. If we don't do this, we'll end up trying to delete - // the sound twice. - if (draudio_is_inline_sound(pSound)) { - draudio_register_stop_callback(pSound->pBuffer, NULL, NULL); - } - - - // Let the application know that the sound is being deleted. We want to do this after removing the stop event just to be sure the - // application doesn't try to explicitly stop the sound in this callback - that would be a problem for inlined sounds because they - // are configured to delete themselves upon stopping which we are already in the process of doing. - if (pSound->onDelete != NULL) { - pSound->onDelete(pSound); - } - - - // Delete the internal audio buffer before letting the host application know about the deletion. - draudio_delete_buffer(pSound->pBuffer); - } - draudio_unlock_mutex(pSound->pWorld->lock); - - - // Only free the sound after the application has been made aware the sound is being deleted. - free(pSound); -} - -void draudio_delete_all_sounds(draudio_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - while (pWorld->pFirstSound != NULL) { - draudio_delete_sound(pWorld->pFirstSound); - } -} - - -size_t draudio_get_sound_extra_data_size(draudio_sound* pSound) -{ - if (pSound == NULL) { - return 0; - } - - if (pSound->isUsingStreamingBuffer) { - return draudio_get_streaming_buffer_extra_data_size(pSound->pBuffer); - } else { - return draudio_get_buffer_extra_data_size(pSound->pBuffer); - } -} - -void* draudio_get_sound_extra_data(draudio_sound* pSound) -{ - if (pSound == NULL) { - return NULL; - } - - if (pSound->isUsingStreamingBuffer) { - return draudio_get_streaming_buffer_extra_data(pSound->pBuffer); - } else { - return draudio_get_buffer_extra_data(pSound->pBuffer); - } -} - - -void draudio_play_sound(draudio_sound* pSound, bool loop) -{ - if (pSound != NULL) { - if (pSound->isUsingStreamingBuffer) { - draudio_play_streaming_buffer(pSound->pBuffer, loop); - } else { - draudio_play(pSound->pBuffer, loop); - } - } -} - -void draudio_pause_sound(draudio_sound* pSound) -{ - if (pSound != NULL) { - draudio_pause(pSound->pBuffer); - } -} - -void draudio_stop_sound(draudio_sound* pSound) -{ - if (pSound != NULL) { - draudio_stop(pSound->pBuffer); - } -} - -draudio_playback_state draudio_get_sound_playback_state(draudio_sound* pSound) -{ - if (pSound == NULL) { - return draudio_stopped; - } - - return draudio_get_playback_state(pSound->pBuffer); -} - -bool draudio_is_sound_looping(draudio_sound* pSound) -{ - if (pSound == NULL) { - return false; - } - - if (pSound->isUsingStreamingBuffer) { - return draudio_is_streaming_buffer_looping(pSound->pBuffer); - } else { - return draudio_is_looping(pSound->pBuffer); - } -} - - - -void draudio_play_inline_sound(draudio_world* pWorld, draudio_sound_desc desc) -{ - if (pWorld == NULL) { - return; - } - - // We need to explicitly ensure 3D positioning is disabled. - desc.flags &= ~DRAUDIO_ENABLE_3D; - - draudio_sound* pSound = draudio_create_sound(pWorld, desc); - if (pSound != NULL) - { - // For inline sounds we set a callback for when the sound is stopped. When this callback is fired, the sound is deleted. - draudio_set_sound_stop_callback(pSound, draudio_inline_sound_stop_callback, pSound); - - // Start playing the sound once everything else has been set up. - draudio_play_sound(pSound, false); - } -} - -void draudio_play_inline_sound_3f(draudio_world* pWorld, draudio_sound_desc desc, float posX, float posY, float posZ) -{ - if (pWorld == NULL) { - return; - } - - draudio_sound* pSound = draudio_create_sound(pWorld, desc); - if (pSound != NULL) - { - // For inline sounds we set a callback for when the sound is stopped. When this callback is fired, the sound is deleted. - draudio_set_sound_stop_callback(pSound, draudio_inline_sound_stop_callback, pSound); - - // Set the position before playing anything. - draudio_set_sound_position(pSound, posX, posY, posZ); - - // Start playing the sound once everything else has been set up. - draudio_play_sound(pSound, false); - } -} - - -void draudio_stop_all_sounds(draudio_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - bool wasPlaying = pWorld->playbackState == draudio_playing; - if (pWorld->playbackState != draudio_stopped) - { - // We need to loop over every sound and stop them. We also need to keep track of their previous playback state - // so that when resume_all_sounds() is called, it can be restored correctly. - for (draudio_sound* pSound = pWorld->pFirstSound; pSound != NULL; pSound = pSound->pNextSound) - { - if (wasPlaying) { - pSound->prevPlaybackState = draudio_get_sound_playback_state(pSound); - } - - draudio_stop_sound(pSound); - } - } -} - -void draudio_pause_all_sounds(draudio_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - if (pWorld->playbackState == draudio_playing) - { - // We need to loop over every sound and stop them. We also need to keep track of their previous playback state - // so that when resume_all_sounds() is called, it can be restored correctly. - for (draudio_sound* pSound = pWorld->pFirstSound; pSound != NULL; pSound = pSound->pNextSound) - { - pSound->prevPlaybackState = draudio_get_sound_playback_state(pSound); - draudio_pause_sound(pSound); - } - } -} - -void draudio_resume_all_sounds(draudio_world* pWorld) -{ - if (pWorld == NULL) { - return; - } - - if (pWorld->playbackState != draudio_playing) - { - // When resuming playback, we use the previous playback state to determine how to resume. - for (draudio_sound* pSound = pWorld->pFirstSound; pSound != NULL; pSound = pSound->pNextSound) - { - if (pSound->prevPlaybackState == draudio_playing) { - draudio_play_sound(pSound, draudio_is_sound_looping(pSound)); - } - } - } -} - - -void draudio_set_sound_stop_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData) -{ - if (pSound != NULL) { - draudio_register_stop_callback(pSound->pBuffer, callback, pUserData); - } -} - -void draudio_set_sound_pause_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData) -{ - if (pSound != NULL) { - draudio_register_pause_callback(pSound->pBuffer, callback, pUserData); - } -} - -void draudio_set_sound_play_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData) -{ - if (pSound != NULL) { - draudio_register_play_callback(pSound->pBuffer, callback, pUserData); - } -} - - -void draudio_set_sound_position(draudio_sound* pSound, float posX, float posY, float posZ) -{ - if (pSound != NULL) { - draudio_set_position(pSound->pBuffer, posX, posY, posZ); - } -} - - -void draudio_set_sound_3d_mode(draudio_sound* pSound, draudio_3d_mode mode) -{ - if (pSound != NULL) { - draudio_set_3d_mode(pSound->pBuffer, mode); - } -} - -draudio_3d_mode draudio_get_sound_3d_mode(draudio_sound* pSound) -{ - if (pSound == NULL) { - return draudio_3d_mode_disabled; - } - - return draudio_get_3d_mode(pSound->pBuffer); -} - - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// BACKENDS -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// -// DirectSound -// -// The DirectSound backend is mostly simple, except for event handling. Events -// are achieved through the use of Win32 event objects and waiting on them to -// be put into a signaled state by DirectSound. Due to this mechanic we need to -// create a worker thread that waits on each event. -// -// The worker thread waits on three general types of events. The first is an -// event that is signaled when the thread needs to be terminated. The second -// is an event that is signaled when a new set of events need to be waited on. -// The third is a set of events that correspond to an output buffer event (such -// as stop, pause, play and marker events.) -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DRAUDIO_BUILD_DSOUND -#include -#include -#include -#include // For testing and debugging with printf(). Delete this later. - -// Define a NULL GUID for use later on. If we don't do this and use GUID_NULL we'll end -// up with a link error. -GUID DRAUDIO_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - - -//// Message Queue //// - -#define DRAUDIO_MESSAGE_ID_UNKNOWN 0 -#define DRAUDIO_MESSAGE_ID_EVENT 1 -#define DRAUDIO_MESSAGE_ID_DELETE_BUFFER 2 -#define DRAUDIO_MESSAGE_ID_DELETE_DEVICE 3 -#define DRAUDIO_MESSAGE_ID_TERMINATE_THREAD 4 - -/// Structure representing an individual message -typedef struct -{ - /// The message ID. - int id; - - /// A pointer to the relevant buffer. - draudio_buffer* pBuffer; - - - // The message-specific data. - union - { - struct - { - /// A pointer to the callback function. - draudio_event_callback_proc callback; - - /// The event ID. - unsigned int eventID; - - /// The callback user data. - void* pUserData; - - } callback_event; - - - struct - { - /// A pointer to the DirectSound buffer object. - LPDIRECTSOUNDBUFFER8 pDSBuffer; - - /// A pointer to the 3D DirectSound buffer object. This will be NULL if 3D positioning is disabled for the buffer. - LPDIRECTSOUND3DBUFFER pDSBuffer3D; - - /// A pointer to the object for handling notification events. - LPDIRECTSOUNDNOTIFY pDSNotify; - - } delete_buffer; - - - struct - { - /// A pointer to the DIRECTSOUND object that was created with DirectSoundCreate8(). - LPDIRECTSOUND8 pDS; - - /// A pointer to the DIRECTSOUNDBUFFER object for the primary buffer. - LPDIRECTSOUNDBUFFER pDSPrimaryBuffer; - - /// A pointer to the DIRECTSOUND3DLISTENER8 object associated with the device. - LPDIRECTSOUND3DLISTENER pDSListener; - - /// A pointer to the device object being deleted. - draudio_device* pDevice; - - } delete_device; - - } data; - -} draudio_message_dsound; - - -/// Structure representing the main message queue. -/// -/// The message queue is implemented as a fixed-sized cyclic array which means there should be no significant data -/// movement and fast pushing and popping. -typedef struct -{ - /// The buffer containing the list of events. - draudio_message_dsound messages[DRAUDIO_MAX_MESSAGE_QUEUE_SIZE]; - - /// The number of active messages in the queue. - unsigned int messageCount; - - /// The index of the first message in the queue. - unsigned int iFirstMessage; - - /// The mutex for synchronizing access to message pushing and popping. - draudio_mutex queueLock; - - /// The semaphore that's used for blocking draudio_next_message_dsound(). The maximum value is set to DRAUDIO_MAX_MESSAGE_QUEUE_SIZE. - HANDLE hMessageSemaphore; - - /// The message handling thread. - HANDLE hMessageHandlingThread; - - /// Keeps track of whether or not the queue is deleted. We use this to ensure a thread does not try to post an event. - bool isDeleted; - -} draudio_message_queue_dsound; - - -/// The function to run on the message handling thread. This is implemented down the bottom. -DWORD WINAPI MessageHandlingThread_DSound(draudio_message_queue_dsound* pQueue); - -/// Posts a new message. This is thread safe. -void draudio_post_message_dsound(draudio_message_queue_dsound* pQueue, draudio_message_dsound msg); - - - -/// Initializes the given mesasge queue. -bool draudio_init_message_queue_dsound(draudio_message_queue_dsound* pQueue) -{ - if (pQueue == NULL) { - return false; - } - - pQueue->messageCount = 0; - pQueue->iFirstMessage = 0; - - pQueue->queueLock = draudio_create_mutex(); - if (pQueue->queueLock == NULL) { - return false; - } - - pQueue->hMessageSemaphore = CreateSemaphoreA(NULL, 0, DRAUDIO_MAX_MESSAGE_QUEUE_SIZE, NULL); - if (pQueue->hMessageSemaphore == NULL) - { - draudio_delete_mutex(pQueue->queueLock); - return false; - } - - pQueue->hMessageHandlingThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageHandlingThread_DSound, pQueue, 0, NULL); - if (pQueue->hMessageHandlingThread == NULL) - { - CloseHandle(pQueue->hMessageSemaphore); - draudio_delete_mutex(pQueue->queueLock); - return false; - } - - pQueue->isDeleted = false; - - return true; -} - -/// Uninitializes the given message queue. -void draudio_uninit_message_queue_dsound(draudio_message_queue_dsound* pQueue) -{ - // We need to make sure the thread is closed properly before returning from here. To do this we just post an DRAUDIO_MESSAGE_ID_TERMINATE_THREAD - // event to the message queue and wait for the thread to finish. - draudio_message_dsound msg; - msg.id = DRAUDIO_MESSAGE_ID_TERMINATE_THREAD; - draudio_post_message_dsound(pQueue, msg); - - - // Once we posted the event we just wait for the thread to process it and terminate. - WaitForSingleObject(pQueue->hMessageHandlingThread, INFINITE); - - // At this point the thread has been terminated and we can clear everything. - CloseHandle(pQueue->hMessageHandlingThread); - pQueue->hMessageHandlingThread = NULL; - - CloseHandle(pQueue->hMessageSemaphore); - pQueue->hMessageSemaphore = NULL; - - - pQueue->isDeleted = true; - draudio_lock_mutex(pQueue->queueLock); - { - pQueue->messageCount = 0; - pQueue->iFirstMessage = 0; - } - draudio_unlock_mutex(pQueue->queueLock); - - draudio_delete_mutex(pQueue->queueLock); - pQueue->queueLock = NULL; -} - - -void draudio_post_message_dsound(draudio_message_queue_dsound* pQueue, draudio_message_dsound msg) -{ - assert(pQueue != NULL); - - if (pQueue->isDeleted) { - return; - } - - draudio_lock_mutex(pQueue->queueLock); - { - if (pQueue->messageCount < DRAUDIO_MAX_MESSAGE_QUEUE_SIZE) - { - pQueue->messages[(pQueue->iFirstMessage + pQueue->messageCount) % DRAUDIO_MAX_MESSAGE_QUEUE_SIZE] = msg; - pQueue->messageCount += 1; - - ReleaseSemaphore(pQueue->hMessageSemaphore, 1, NULL); - } - } - draudio_unlock_mutex(pQueue->queueLock); -} - - -/// Retrieves the next message in the queue. -/// -/// @remarks -/// This blocks until a message is available. This will return false when it receives the DRAUDIO_MESSAGE_ID_TERMINATE_THREAD message. -bool draudio_next_message_dsound(draudio_message_queue_dsound* pQueue, draudio_message_dsound* pMsgOut) -{ - if (WaitForSingleObject(pQueue->hMessageSemaphore, INFINITE) == WAIT_OBJECT_0) // Wait for a message to become available. - { - draudio_message_dsound msg; - msg.id = DRAUDIO_MESSAGE_ID_UNKNOWN; - - draudio_lock_mutex(pQueue->queueLock); - { - assert(pQueue->messageCount > 0); - - msg = pQueue->messages[pQueue->iFirstMessage]; - - pQueue->iFirstMessage = (pQueue->iFirstMessage + 1) % DRAUDIO_MAX_MESSAGE_QUEUE_SIZE; - pQueue->messageCount -= 1; - } - draudio_unlock_mutex(pQueue->queueLock); - - - if (pMsgOut != NULL) { - pMsgOut[0] = msg; - } - - return msg.id != DRAUDIO_MESSAGE_ID_TERMINATE_THREAD; - } - - return false; -} - - -DWORD WINAPI MessageHandlingThread_DSound(draudio_message_queue_dsound* pQueue) -{ - assert(pQueue != NULL); - - draudio_message_dsound msg; - while (draudio_next_message_dsound(pQueue, &msg)) - { - assert(msg.id != DRAUDIO_MESSAGE_ID_TERMINATE_THREAD); // <-- draudio_next_message_dsound() will return false when it receives DRAUDIO_MESSAGE_ID_TERMINATE_THREAD. - - switch (msg.id) - { - case DRAUDIO_MESSAGE_ID_EVENT: - { - assert(msg.data.callback_event.callback != NULL); - - msg.data.callback_event.callback(msg.pBuffer, msg.data.callback_event.eventID, msg.data.callback_event.pUserData); - break; - } - - case DRAUDIO_MESSAGE_ID_DELETE_BUFFER: - { - if (msg.data.delete_buffer.pDSNotify != NULL) { - IDirectSoundNotify_Release(msg.data.delete_buffer.pDSNotify); - } - - if (msg.data.delete_buffer.pDSBuffer3D != NULL) { - IDirectSound3DBuffer_Release(msg.data.delete_buffer.pDSBuffer3D); - } - - if (msg.data.delete_buffer.pDSBuffer != NULL) { - IDirectSoundBuffer8_Release(msg.data.delete_buffer.pDSBuffer); - } - - free(msg.pBuffer); - break; - } - - case DRAUDIO_MESSAGE_ID_DELETE_DEVICE: - { - if (msg.data.delete_device.pDSListener != NULL) { - IDirectSound3DListener_Release(msg.data.delete_device.pDSListener); - } - - if (msg.data.delete_device.pDSPrimaryBuffer != NULL) { - IDirectSoundBuffer_Release(msg.data.delete_device.pDSPrimaryBuffer); - } - - if (msg.data.delete_device.pDS != NULL) { - IDirectSound_Release(msg.data.delete_device.pDS); - } - - free(msg.data.delete_device.pDevice); - break; - } - - default: - { - // Should never hit this. - assert(false); - break; - } - } - } - - return 0; -} - - - - -/// Deactivates (but does not delete) every event associated with the given buffer. -void draudio_deactivate_buffer_events_dsound(draudio_buffer* pBuffer); - - -//// Event Management //// - -typedef struct draudio_event_manager_dsound draudio_event_manager_dsound; -typedef struct draudio_event_dsound draudio_event_dsound; - -struct draudio_event_dsound -{ - /// A pointer to the event manager that owns this event. - draudio_event_manager_dsound* pEventManager; - - /// The event. - HANDLE hEvent; - - /// The callback. - draudio_event_callback_proc callback; - - /// A pointer to the applicable buffer. - draudio_buffer* pBuffer; - - /// The event ID. For on_stop events, this will be set to DRAUDIO_EVENT_STOP - unsigned int eventID; - - /// A pointer to the user data. - void* pUserData; - - /// The marker offset. Only used for marker events. Should be set to 0 for non-markers. - DWORD markerOffset; - - /// Events are stored in a linked list. This is a pointer to the next event in the list. - draudio_event_dsound* pNextEvent; - - /// A pointer to the previous event. - draudio_event_dsound* pPrevEvent; -}; - -struct draudio_event_manager_dsound -{ - /// A pointer to the message queue where messages will be posted for event processing. - draudio_message_queue_dsound* pMessageQueue; - - - /// A handle to the event worker thread. - HANDLE hThread; - - /// A handle to the terminator event object. - HANDLE hTerminateEvent; - - /// A handle to the refresher event object. - HANDLE hRefreshEvent; - - /// The mutex to use when refreshing the worker thread. This is used to ensure only one refresh is done at a time. - draudio_mutex refreshMutex; - - /// The synchronization lock. - draudio_mutex mainLock; - - /// The event object for notifying dr_audio when an event has finished being handled by the event handling thread. - HANDLE hEventCompletionLock; - - - /// The first event in a list. - draudio_event_dsound* pFirstEvent; - - /// The last event in the list of events. - draudio_event_dsound* pLastEvent; -}; - - -/// Locks the event manager. -void draudio_lock_events_dsound(draudio_event_manager_dsound* pEventManager) -{ - draudio_lock_mutex(pEventManager->mainLock); -} - -/// Unlocks the event manager. -void draudio_unlock_events_dsound(draudio_event_manager_dsound* pEventManager) -{ - draudio_unlock_mutex(pEventManager->mainLock); -} - - -/// Removes the given event from the event lists. -/// -/// @remarks -/// This will be used when moving the event to a new location in the list or when it is being deleted. -void draudio_remove_event_dsound_nolock(draudio_event_dsound* pEvent) -{ - assert(pEvent != NULL); - - draudio_event_manager_dsound* pEventManager = pEvent->pEventManager; - assert(pEventManager != NULL); - - if (pEventManager->pFirstEvent == pEvent) { - pEventManager->pFirstEvent = pEvent->pNextEvent; - } - - if (pEventManager->pLastEvent == pEvent) { - pEventManager->pLastEvent = pEvent->pPrevEvent; - } - - - if (pEvent->pPrevEvent != NULL) { - pEvent->pPrevEvent->pNextEvent = pEvent->pNextEvent; - } - - if (pEvent->pNextEvent != NULL) { - pEvent->pNextEvent->pPrevEvent = pEvent->pPrevEvent; - } - - pEvent->pNextEvent = NULL; - pEvent->pPrevEvent = NULL; -} - -/// @copydoc draudio_remove_event_dsound_nolock() -void draudio_remove_event_dsound(draudio_event_dsound* pEvent) -{ - assert(pEvent != NULL); - - draudio_event_manager_dsound* pEventManager = pEvent->pEventManager; - draudio_lock_events_dsound(pEventManager); - { - draudio_remove_event_dsound_nolock(pEvent); - } - draudio_unlock_events_dsound(pEventManager); -} - -/// Adds the given event to the end of the internal list. -void draudio_append_event_dsound(draudio_event_dsound* pEvent) -{ - assert(pEvent != NULL); - - draudio_event_manager_dsound* pEventManager = pEvent->pEventManager; - draudio_lock_events_dsound(pEventManager); - { - draudio_remove_event_dsound_nolock(pEvent); - - assert(pEvent->pNextEvent == NULL); - - if (pEventManager->pLastEvent != NULL) { - pEvent->pPrevEvent = pEventManager->pLastEvent; - pEvent->pPrevEvent->pNextEvent = pEvent; - } - - if (pEventManager->pFirstEvent == NULL) { - pEventManager->pFirstEvent = pEvent; - } - - pEventManager->pLastEvent = pEvent; - } - draudio_unlock_events_dsound(pEventManager); -} - -void draudio_refresh_worker_thread_event_queue(draudio_event_manager_dsound* pEventManager) -{ - assert(pEventManager != NULL); - - // To refresh the worker thread we just need to signal the refresh event. We then just need to wait for - // processing to finish which we can do by waiting on another event to become signaled. - - draudio_lock_mutex(pEventManager->refreshMutex); - { - // Signal a refresh. - SetEvent(pEventManager->hRefreshEvent); - - // Wait for refreshing to complete. - WaitForSingleObject(pEventManager->hEventCompletionLock, INFINITE); - } - draudio_unlock_mutex(pEventManager->refreshMutex); -} - - -/// Closes the Win32 event handle of the given event. -void draudio_close_win32_event_handle_dsound(draudio_event_dsound* pEvent) -{ - assert(pEvent != NULL); - assert(pEvent->pEventManager != NULL); - - - // At the time of calling this function, pEvent should have been removed from the internal list. The issue is that - // the event notification thread is waiting on it. Thus, we need to refresh the worker thread to ensure the event - // have been flushed from that queue. To do this we just signal a special event that's used to trigger a refresh. - draudio_refresh_worker_thread_event_queue(pEvent->pEventManager); - - // The worker thread should not be waiting on the event so we can go ahead and close the handle now. - CloseHandle(pEvent->hEvent); - pEvent->hEvent = NULL; -} - - -/// Updates the given event to use the given callback and user data. -void draudio_update_event_dsound(draudio_event_dsound* pEvent, draudio_event_callback_proc callback, void* pUserData) -{ - assert(pEvent != NULL); - - pEvent->callback = callback; - pEvent->pUserData = pUserData; - - draudio_refresh_worker_thread_event_queue(pEvent->pEventManager); -} - -/// Creates a new event, but does not activate it. -/// -/// @remarks -/// When an event is created, it just sits dormant and will never be triggered until it has been -/// activated with draudio_activate_event_dsound(). -draudio_event_dsound* draudio_create_event_dsound(draudio_event_manager_dsound* pEventManager, draudio_event_callback_proc callback, draudio_buffer* pBuffer, unsigned int eventID, void* pUserData) -{ - draudio_event_dsound* pEvent = (draudio_event_dsound*)malloc(sizeof(draudio_event_dsound)); - if (pEvent != NULL) - { - pEvent->pEventManager = pEventManager; - pEvent->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - pEvent->callback = NULL; - pEvent->pBuffer = pBuffer; - pEvent->eventID = eventID; - pEvent->pUserData = NULL; - pEvent->markerOffset = 0; - pEvent->pNextEvent = NULL; - pEvent->pPrevEvent = NULL; - - // Append the event to the internal list. - draudio_append_event_dsound(pEvent); - - // This roundabout way of setting the callback and user data is to ensure the worker thread is made aware that it needs - // to refresh it's local event data. - draudio_update_event_dsound(pEvent, callback, pUserData); - } - - return pEvent; -} - -/// Deletes an event, and deactivates it. -/// -/// @remarks -/// This will not return until the event has been deleted completely. -void draudio_delete_event_dsound(draudio_event_dsound* pEvent) -{ - assert(pEvent != NULL); - - // Set everything to NULL so the worker thread is aware that the event is about to get deleted. - pEvent->pBuffer = NULL; - pEvent->callback = NULL; - pEvent->eventID = 0; - pEvent->pUserData = NULL; - pEvent->markerOffset = 0; - - // Remove the event from the list. - draudio_remove_event_dsound(pEvent); - - // Close the Win32 event handle. - if (pEvent->hEvent != NULL) { - draudio_close_win32_event_handle_dsound(pEvent); - } - - - // At this point everything has been closed so we can safely free the memory and return. - free(pEvent); -} - - -/// Gathers the event handles and callback data for all of the relevant buffer events. -unsigned int draudio_gather_events_dsound(draudio_event_manager_dsound *pEventManager, HANDLE* pHandlesOut, draudio_event_dsound** ppEventsOut, unsigned int outputBufferSize) -{ - assert(pEventManager != NULL); - assert(pHandlesOut != NULL); - assert(ppEventsOut != NULL); - assert(outputBufferSize >= 2); - - unsigned int i = 2; - draudio_lock_events_dsound(pEventManager); - { - pHandlesOut[0] = pEventManager->hTerminateEvent; - ppEventsOut[0] = NULL; - - pHandlesOut[1] = pEventManager->hRefreshEvent; - ppEventsOut[1] = NULL; - - - draudio_event_dsound* pEvent = pEventManager->pFirstEvent; - while (i < outputBufferSize && pEvent != NULL) - { - if (pEvent->hEvent != NULL) - { - pHandlesOut[i] = pEvent->hEvent; - ppEventsOut[i] = pEvent; - - i += 1; - } - - pEvent = pEvent->pNextEvent; - } - } - draudio_unlock_events_dsound(pEventManager); - - return i; -} - -/// The entry point to the event worker thread. -DWORD WINAPI DSound_EventWorkerThreadProc(draudio_event_manager_dsound *pEventManager) -{ - if (pEventManager != NULL) - { - HANDLE hTerminateEvent = pEventManager->hTerminateEvent; - HANDLE hRefreshEvent = pEventManager->hRefreshEvent; - - HANDLE eventHandles[1024]; - draudio_event_dsound* events[1024]; - unsigned int eventCount = draudio_gather_events_dsound(pEventManager, eventHandles, events, 1024); // <-- Initial gather. - - bool requestedRefresh = false; - for (;;) - { - if (requestedRefresh) - { - eventCount = draudio_gather_events_dsound(pEventManager, eventHandles, events, 1024); - - // Refreshing is done, so now we need to let other threads know about it. - SetEvent(pEventManager->hEventCompletionLock); - requestedRefresh = false; - } - - - - DWORD rc = WaitForMultipleObjects(eventCount, eventHandles, FALSE, INFINITE); - if (rc >= WAIT_OBJECT_0 && rc < eventCount) - { - const unsigned int eventIndex = rc - WAIT_OBJECT_0; - HANDLE hEvent = eventHandles[eventIndex]; - - if (hEvent == hTerminateEvent) - { - // The terminator event was signaled. We just return from the thread immediately. - return 0; - } - - if (hEvent == hRefreshEvent) - { - assert(hRefreshEvent == pEventManager->hRefreshEvent); - - // This event will get signaled when a new set of events need to be waited on, such as when a new event has been registered on a buffer. - requestedRefresh = true; - continue; - } - - - // If we get here if means we have hit a callback event. - draudio_event_dsound* pEvent = events[eventIndex]; - if (pEvent->callback != NULL) - { - assert(pEvent->hEvent == hEvent); - - // The stop event will be signaled by DirectSound when IDirectSoundBuffer::Stop() is called. The problem is that we need to call that when the - // sound is paused as well. Thus, we need to check if we got the stop event, and if so DON'T call the callback function if it is in a non-stopped - // state. - bool isStopEventButNotStopped = pEvent->eventID == DRAUDIO_EVENT_ID_STOP && draudio_get_playback_state(pEvent->pBuffer) != draudio_stopped; - if (!isStopEventButNotStopped) - { - // We don't call the callback directly. Instead we post a message to the message handling thread for processing later. - draudio_message_dsound msg; - msg.id = DRAUDIO_MESSAGE_ID_EVENT; - msg.pBuffer = pEvent->pBuffer; - msg.data.callback_event.callback = pEvent->callback; - msg.data.callback_event.eventID = pEvent->eventID; - msg.data.callback_event.pUserData = pEvent->pUserData; - draudio_post_message_dsound(pEventManager->pMessageQueue, msg); - } - } - } - } - } - - return 0; -} - - -/// Initializes the event manager by creating the thread and event objects. -bool draudio_init_event_manager_dsound(draudio_event_manager_dsound* pEventManager, draudio_message_queue_dsound* pMessageQueue) -{ - assert(pEventManager != NULL); - assert(pMessageQueue != NULL); - - pEventManager->pMessageQueue = pMessageQueue; - - HANDLE hTerminateEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (hTerminateEvent == NULL) { - return false; - } - - HANDLE hRefreshEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (hRefreshEvent == NULL) - { - CloseHandle(hTerminateEvent); - return false; - } - - draudio_mutex refreshMutex = draudio_create_mutex(); - if (refreshMutex == NULL) - { - CloseHandle(hTerminateEvent); - CloseHandle(hRefreshEvent); - return false; - } - - draudio_mutex mainLock = draudio_create_mutex(); - if (mainLock == NULL) - { - CloseHandle(hTerminateEvent); - CloseHandle(hRefreshEvent); - draudio_delete_mutex(refreshMutex); - return false; - } - - HANDLE hEventCompletionLock = CreateEventA(NULL, FALSE, FALSE, NULL); - if (hEventCompletionLock == NULL) - { - CloseHandle(hTerminateEvent); - CloseHandle(hRefreshEvent); - draudio_delete_mutex(refreshMutex); - draudio_delete_mutex(mainLock); - return false; - } - - - HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DSound_EventWorkerThreadProc, pEventManager, 0, NULL); - if (hThread == NULL) - { - CloseHandle(hTerminateEvent); - CloseHandle(hRefreshEvent); - draudio_delete_mutex(refreshMutex); - draudio_delete_mutex(mainLock); - CloseHandle(hEventCompletionLock); - return false; - } - - - pEventManager->hTerminateEvent = hTerminateEvent; - pEventManager->hRefreshEvent = hRefreshEvent; - pEventManager->refreshMutex = refreshMutex; - pEventManager->mainLock = mainLock; - pEventManager->hEventCompletionLock = hEventCompletionLock; - pEventManager->hThread = hThread; - - pEventManager->pFirstEvent = NULL; - pEventManager->pLastEvent = NULL; - - return true; -} - -/// Shuts down the event manager by closing the thread and event objects. -/// -/// @remarks -/// This does not return until the worker thread has been terminated completely. -/// @par -/// This will delete every event, so any pointers to events will be made invalid upon calling this function. -void draudio_uninit_event_manager_dsound(draudio_event_manager_dsound* pEventManager) -{ - assert(pEventManager != NULL); - - - // Cleanly delete every event first. - while (pEventManager->pFirstEvent != NULL) { - draudio_delete_event_dsound(pEventManager->pFirstEvent); - } - - - - // Terminate the thread and wait for the thread to finish executing before freeing the context for real. - SignalObjectAndWait(pEventManager->hTerminateEvent, pEventManager->hThread, INFINITE, FALSE); - - // Only delete the thread after it has returned naturally. - CloseHandle(pEventManager->hThread); - pEventManager->hThread = NULL; - - - // Once the thread has been terminated we can delete the terminator and refresher events. - CloseHandle(pEventManager->hTerminateEvent); - pEventManager->hTerminateEvent = NULL; - - CloseHandle(pEventManager->hRefreshEvent); - pEventManager->hRefreshEvent = NULL; - - draudio_delete_mutex(pEventManager->refreshMutex); - pEventManager->refreshMutex = NULL; - - draudio_delete_mutex(pEventManager->mainLock); - pEventManager->mainLock = NULL; - - - CloseHandle(pEventManager->hEventCompletionLock); - pEventManager->hEventCompletionLock = NULL; -} - - -//// End Event Management //// - -static GUID _g_DSListenerGUID = {0x279AFA84, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}}; -static GUID _g_DirectSoundBuffer8GUID = {0x6825a449, 0x7524, 0x4d82, {0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e}}; -static GUID _g_DirectSound3DBuffer8GUID = {0x279AFA86, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}}; -static GUID _g_DirectSoundNotifyGUID = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; -static GUID _g_KSDATAFORMAT_SUBTYPE_PCM_GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -static GUID _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - -#ifdef __cplusplus -static GUID g_DSListenerGUID = _g_DSListenerGUID; -static GUID g_DirectSoundBuffer8GUID = _g_DirectSoundBuffer8GUID; -static GUID g_DirectSound3DBuffer8GUID = _g_DirectSound3DBuffer8GUID; -static GUID g_DirectSoundNotifyGUID = _g_DirectSoundNotifyGUID; -static GUID g_KSDATAFORMAT_SUBTYPE_PCM_GUID = _g_KSDATAFORMAT_SUBTYPE_PCM_GUID; -static GUID g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID = _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID; -#else -static GUID* g_DSListenerGUID = &_g_DSListenerGUID; -static GUID* g_DirectSoundBuffer8GUID = &_g_DirectSoundBuffer8GUID; -static GUID* g_DirectSound3DBuffer8GUID = &_g_DirectSound3DBuffer8GUID; -static GUID* g_DirectSoundNotifyGUID = &_g_DirectSoundNotifyGUID; -static GUID* g_KSDATAFORMAT_SUBTYPE_PCM_GUID = &_g_KSDATAFORMAT_SUBTYPE_PCM_GUID; -static GUID* g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID = &_g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID; -#endif - - -typedef HRESULT (WINAPI * pDirectSoundCreate8Proc)(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter); -typedef HRESULT (WINAPI * pDirectSoundEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); -typedef HRESULT (WINAPI * pDirectSoundCaptureCreate8Proc)(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter); -typedef HRESULT (WINAPI * pDirectSoundCaptureEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); - -typedef struct -{ - /// A pointer to the GUID of the device. This will be set to all zeros for the default device. - GUID guid; - - /// The description of the device. - char description[256]; - - /// The module name of the DirectSound driver corresponding to this device. - char moduleName[256]; - -} draudio_device_info_dsound; - -typedef struct -{ - /// The base context data. This must always be the first item in the struct. - draudio_context base; - - /// A handle to the dsound.dll file that was loaded by LoadLibrary(). - HMODULE hDSoundDLL; - - // DirectSound APIs. - pDirectSoundCreate8Proc pDirectSoundCreate8; - pDirectSoundEnumerateAProc pDirectSoundEnumerateA; - pDirectSoundCaptureCreate8Proc pDirectSoundCaptureCreate8; - pDirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA; - - - /// The number of output devices that were iterated when the context was created. This is static, so if the user was to unplug - /// a device one would need to re-create the context. - unsigned int outputDeviceCount; - - /// The buffer containing the list of enumerated output devices. - draudio_device_info_dsound outputDeviceInfo[DRAUDIO_MAX_DEVICE_COUNT]; - - - /// The number of capture devices that were iterated when the context was created. This is static, so if the user was to unplug - /// a device one would need to re-create the context. - unsigned int inputDeviceCount; - - /// The buffer containing the list of enumerated input devices. - draudio_device_info_dsound inputDeviceInfo[DRAUDIO_MAX_DEVICE_COUNT]; - - - /// The event manager. - draudio_event_manager_dsound eventManager; - - - /// The message queue. - draudio_message_queue_dsound messageQueue; - -} draudio_context_dsound; - -typedef struct -{ - /// The base device data. This must always be the first item in the struct. - draudio_device base; - - /// A pointer to the DIRECTSOUND object that was created with DirectSoundCreate8(). - LPDIRECTSOUND8 pDS; - - /// A pointer to the DIRECTSOUNDBUFFER object for the primary buffer. - LPDIRECTSOUNDBUFFER pDSPrimaryBuffer; - - /// A pointer to the DIRECTSOUND3DLISTENER8 object associated with the device. - LPDIRECTSOUND3DLISTENER pDSListener; - -} draudio_device_dsound; - -typedef struct -{ - /// The base buffer data. This must always be the first item in the struct. - draudio_buffer base; - - /// A pointer to the DirectSound buffer object. - LPDIRECTSOUNDBUFFER8 pDSBuffer; - - /// A pointer to the 3D DirectSound buffer object. This will be NULL if 3D positioning is disabled for the buffer. - LPDIRECTSOUND3DBUFFER pDSBuffer3D; - - /// A pointer to the object for handling notification events. - LPDIRECTSOUNDNOTIFY pDSNotify; - - /// The current playback state. - draudio_playback_state playbackState; - - - /// The number of marker events that have been registered. This will never be more than DRAUDIO_MAX_MARKER_COUNT. - unsigned int markerEventCount; - - /// The marker events. - draudio_event_dsound* pMarkerEvents[DRAUDIO_MAX_MARKER_COUNT]; - - /// The event to trigger when the sound is stopped. - draudio_event_dsound* pStopEvent; - - /// The event to trigger when the sound is paused. - draudio_event_dsound* pPauseEvent; - - /// The event to trigger when the sound is played or resumed. - draudio_event_dsound* pPlayEvent; - - - /// The size in bytes of the buffer's extra data. - unsigned int extraDataSize; - - /// The buffer's extra data. - unsigned char pExtraData[1]; - -} draudio_buffer_dsound; - - -void draudio_activate_buffer_events_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - unsigned int dwPositionNotifies = 0; - DSBPOSITIONNOTIFY n[DRAUDIO_MAX_MARKER_COUNT + 1]; // +1 because we use this array for the markers + stop event. - - // Stop - if (pBufferDS->pStopEvent != NULL) - { - LPDSBPOSITIONNOTIFY pN = n + dwPositionNotifies; - pN->dwOffset = DSBPN_OFFSETSTOP; - pN->hEventNotify = pBufferDS->pStopEvent->hEvent; - - dwPositionNotifies += 1; - } - - // Markers - for (unsigned int iMarker = 0; iMarker < pBufferDS->markerEventCount; ++iMarker) - { - LPDSBPOSITIONNOTIFY pN = n + dwPositionNotifies; - pN->dwOffset = pBufferDS->pMarkerEvents[iMarker]->markerOffset; - pN->hEventNotify = pBufferDS->pMarkerEvents[iMarker]->hEvent; - - dwPositionNotifies += 1; - } - - - HRESULT hr = IDirectSoundNotify_SetNotificationPositions(pBufferDS->pDSNotify, dwPositionNotifies, n); -#if 0 - if (FAILED(hr)) { - printf("WARNING: FAILED TO CREATE DIRECTSOUND NOTIFIERS\n"); - } -#else - (void)hr; -#endif -} - -void draudio_deactivate_buffer_events_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - - HRESULT hr = IDirectSoundNotify_SetNotificationPositions(pBufferDS->pDSNotify, 0, NULL); -#if 0 - if (FAILED(hr)) { - printf("WARNING: FAILED TO CLEAR DIRECTSOUND NOTIFIERS\n"); - } -#else - (void)hr; -#endif -} - - -void draudio_delete_context_dsound(draudio_context* pContext) -{ - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext; - assert(pContextDS != NULL); - - draudio_uninit_event_manager_dsound(&pContextDS->eventManager); - - // The message queue needs to uninitialized after the DirectSound marker notification thread. - draudio_uninit_message_queue_dsound(&pContextDS->messageQueue); - - FreeLibrary(pContextDS->hDSoundDLL); - free(pContextDS); -} - - -unsigned int draudio_get_output_device_count_dsound(draudio_context* pContext) -{ - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext; - assert(pContextDS != NULL); - - return pContextDS->outputDeviceCount; -} - -bool draudio_get_output_device_info_dsound(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut) -{ - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext; - assert(pContextDS != NULL); - assert(pInfoOut != NULL); - - if (deviceIndex >= pContextDS->outputDeviceCount) { - return false; - } - - - draudio_strcpy(pInfoOut->description, sizeof(pInfoOut->description), pContextDS->outputDeviceInfo[deviceIndex].description); - - return true; -} - - -draudio_device* draudio_create_output_device_dsound(draudio_context* pContext, unsigned int deviceIndex) -{ - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext; - assert(pContextDS != NULL); - - if (deviceIndex >= pContextDS->outputDeviceCount) { - return NULL; - } - - - LPDIRECTSOUND8 pDS; - - // Create the device. - HRESULT hr; - if (deviceIndex == 0) { - hr = pContextDS->pDirectSoundCreate8(NULL, &pDS, NULL); - } else { - hr = pContextDS->pDirectSoundCreate8(&pContextDS->outputDeviceInfo[deviceIndex].guid, &pDS, NULL); - } - - if (FAILED(hr)) { - return NULL; - } - - - // Set the cooperative level. Must be done before anything else. - hr = IDirectSound_SetCooperativeLevel(pDS, GetForegroundWindow(), DSSCL_EXCLUSIVE); - if (FAILED(hr)) { - IDirectSound_Release(pDS); - return NULL; - } - - - // Primary buffer. - DSBUFFERDESC descDSPrimary; - memset(&descDSPrimary, 0, sizeof(DSBUFFERDESC)); - descDSPrimary.dwSize = sizeof(DSBUFFERDESC); - descDSPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D; - descDSPrimary.guid3DAlgorithm = DRAUDIO_GUID_NULL; - - LPDIRECTSOUNDBUFFER pDSPrimaryBuffer; - hr = IDirectSound_CreateSoundBuffer(pDS, &descDSPrimary, &pDSPrimaryBuffer, NULL); - if (FAILED(hr)) { - IDirectSound_Release(pDS); - return NULL; - } - - - WAVEFORMATIEEEFLOATEX wf = {0}; - wf.Format.cbSize = sizeof(wf); - wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.Format.nChannels = 2; - wf.Format.nSamplesPerSec = 48000; - wf.Format.wBitsPerSample = 32; - wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; - wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; - wf.dwChannelMask = 0; - wf.SubFormat = _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID; - hr = IDirectSoundBuffer_SetFormat(pDSPrimaryBuffer, (WAVEFORMATEX*)&wf); - if (FAILED(hr)) { - IDirectSoundBuffer_Release(pDSPrimaryBuffer); - IDirectSound_Release(pDS); - return NULL; - } - - - // Listener. - LPDIRECTSOUND3DLISTENER pDSListener = NULL; - hr = IDirectSound3DListener_QueryInterface(pDSPrimaryBuffer, g_DSListenerGUID, (LPVOID*)&pDSListener); - if (FAILED(hr)) { - IDirectSoundBuffer_Release(pDSPrimaryBuffer); - IDirectSound_Release(pDS); - return NULL; - } - - - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)malloc(sizeof(draudio_device_dsound)); - if (pDeviceDS != NULL) - { - pDeviceDS->base.pContext = pContext; - pDeviceDS->pDS = pDS; - pDeviceDS->pDSPrimaryBuffer = pDSPrimaryBuffer; - pDeviceDS->pDSListener = pDSListener; - - return (draudio_device*)pDeviceDS; - } - else - { - IDirectSound3DListener_Release(pDSListener); - IDirectSoundBuffer_Release(pDeviceDS->pDSPrimaryBuffer); - IDirectSound_Release(pDS); - return NULL; - } -} - -void draudio_delete_output_device_dsound(draudio_device* pDevice) -{ - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice; - assert(pDeviceDS != NULL); - - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pDevice->pContext; - assert(pContextDS != NULL); - - // The device id not deleted straight away. Instead we post a message to the message for delayed processing. The reason for this is that buffer - // deletion is also delayed which means we want to ensure any delayed processing of buffers is handled before deleting the device. - draudio_message_dsound msg; - msg.id = DRAUDIO_MESSAGE_ID_DELETE_DEVICE; - msg.pBuffer = NULL; - msg.data.delete_device.pDSListener = pDeviceDS->pDSListener; - msg.data.delete_device.pDSPrimaryBuffer = pDeviceDS->pDSPrimaryBuffer; - msg.data.delete_device.pDS = pDeviceDS->pDS; - msg.data.delete_device.pDevice = pDevice; - draudio_post_message_dsound(&pContextDS->messageQueue, msg); - -#if 0 - IDirectSound3DListener_Release(pDeviceDS->pDSListener); - IDirectSoundBuffer_Release(pDeviceDS->pDSPrimaryBuffer); - IDirectSound_Release(pDeviceDS->pDS); - free(pDeviceDS); -#endif -} - - -draudio_buffer* draudio_create_buffer_dsound(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize) -{ - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice; - assert(pDeviceDS != NULL); - assert(pBufferDesc != NULL); - - // 3D is only valid for mono sounds. - if (pBufferDesc->channels > 1 && (pBufferDesc->flags & DRAUDIO_ENABLE_3D) != 0) { - return NULL; - } - - WAVEFORMATIEEEFLOATEX wf = {0}; - wf.Format.cbSize = sizeof(wf); - wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.Format.nChannels = (WORD)pBufferDesc->channels; - wf.Format.nSamplesPerSec = pBufferDesc->sampleRate; - wf.Format.wBitsPerSample = (WORD)pBufferDesc->bitsPerSample; - wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; - wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; - wf.dwChannelMask = 0; - - if (pBufferDesc->format == draudio_format_pcm) { - wf.SubFormat = _g_KSDATAFORMAT_SUBTYPE_PCM_GUID; - } else if (pBufferDesc->format == draudio_format_float) { - wf.SubFormat = _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID; - } else { - return NULL; - } - - - - // We want to try and create a 3D enabled buffer, however this will fail whenever the number of channels is > 1. In this case - // we do not want to attempt to create a 3D enabled buffer because it will just fail anyway. Instead we'll just create a normal - // buffer with panning enabled. - DSBUFFERDESC descDS; - memset(&descDS, 0, sizeof(DSBUFFERDESC)); - descDS.dwSize = sizeof(DSBUFFERDESC); - descDS.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS; - descDS.dwBufferBytes = (DWORD)pBufferDesc->sizeInBytes; - descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; - - LPDIRECTSOUNDBUFFER8 pDSBuffer = NULL; - LPDIRECTSOUND3DBUFFER pDSBuffer3D = NULL; - if ((pBufferDesc->flags & DRAUDIO_ENABLE_3D) == 0) - { - // 3D Disabled. - descDS.dwFlags |= DSBCAPS_CTRLPAN; - - LPDIRECTSOUNDBUFFER pDSBufferTemp; - HRESULT hr = IDirectSound_CreateSoundBuffer(pDeviceDS->pDS, &descDS, &pDSBufferTemp, NULL); - if (FAILED(hr)) { - return NULL; - } - - hr = IDirectSoundBuffer_QueryInterface(pDSBufferTemp, g_DirectSoundBuffer8GUID, (void**)&pDSBuffer); - if (FAILED(hr)) { - IDirectSoundBuffer_Release(pDSBufferTemp); - return NULL; - } - IDirectSoundBuffer_Release(pDSBufferTemp); - } - else - { - // 3D Enabled. - descDS.dwFlags |= DSBCAPS_CTRL3D; - descDS.guid3DAlgorithm = DS3DALG_DEFAULT; - - LPDIRECTSOUNDBUFFER pDSBufferTemp; - HRESULT hr = IDirectSound_CreateSoundBuffer(pDeviceDS->pDS, &descDS, &pDSBufferTemp, NULL); - if (FAILED(hr)) { - return NULL; - } - - hr = IDirectSoundBuffer_QueryInterface(pDSBufferTemp, g_DirectSoundBuffer8GUID, (void**)&pDSBuffer); - if (FAILED(hr)) { - IDirectSoundBuffer_Release(pDSBufferTemp); - return NULL; - } - IDirectSoundBuffer_Release(pDSBufferTemp); - - - hr = IDirectSoundBuffer_QueryInterface(pDSBuffer, g_DirectSound3DBuffer8GUID, (void**)&pDSBuffer3D); - if (FAILED(hr)) { - return NULL; - } - - IDirectSound3DBuffer_SetPosition(pDSBuffer3D, 0, 0, 0, DS3D_IMMEDIATE); - - if ((pBufferDesc->flags & DRAUDIO_RELATIVE_3D) != 0) { - IDirectSound3DBuffer_SetMode(pDSBuffer3D, DS3DMODE_HEADRELATIVE, DS3D_IMMEDIATE); - } - } - - - - // We need to create a notification object so we can notify the host application when the playback buffer hits a certain point. - LPDIRECTSOUNDNOTIFY pDSNotify; - HRESULT hr = IDirectSoundBuffer8_QueryInterface(pDSBuffer, g_DirectSoundNotifyGUID, (void**)&pDSNotify); - if (FAILED(hr)) { - IDirectSound3DBuffer_Release(pDSBuffer3D); - IDirectSoundBuffer8_Release(pDSBuffer); - return NULL; - } - - - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)malloc(sizeof(draudio_buffer_dsound) - sizeof(pBufferDS->pExtraData) + extraDataSize); - if (pBufferDS == NULL) { - IDirectSound3DBuffer_Release(pDSBuffer3D); - IDirectSoundBuffer8_Release(pDSBuffer); - return NULL; - } - - pBufferDS->base.pDevice = pDevice; - pBufferDS->pDSBuffer = pDSBuffer; - pBufferDS->pDSBuffer3D = pDSBuffer3D; - pBufferDS->pDSNotify = pDSNotify; - pBufferDS->playbackState = draudio_stopped; - - pBufferDS->markerEventCount = 0; - memset(pBufferDS->pMarkerEvents, 0, sizeof(pBufferDS->pMarkerEvents)); - pBufferDS->pStopEvent = NULL; - pBufferDS->pPauseEvent = NULL; - pBufferDS->pPlayEvent = NULL; - - - - // Fill with initial data, if applicable. - if (pBufferDesc->pData != NULL) { - draudio_set_buffer_data((draudio_buffer*)pBufferDS, 0, pBufferDesc->pData, pBufferDesc->sizeInBytes); - } - - return (draudio_buffer*)pBufferDS; -} - -void draudio_delete_buffer_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - assert(pBuffer->pDevice != NULL); - - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext; - assert(pContextDS != NULL); - - - // Deactivate the DirectSound notify events for sanity. - draudio_deactivate_buffer_events_dsound(pBuffer); - - - draudio_message_dsound msg; - msg.id = DRAUDIO_MESSAGE_ID_DELETE_BUFFER; - msg.pBuffer = pBuffer; - msg.data.delete_buffer.pDSNotify = pBufferDS->pDSNotify; - msg.data.delete_buffer.pDSBuffer3D = pBufferDS->pDSBuffer3D; - msg.data.delete_buffer.pDSBuffer = pBufferDS->pDSBuffer; - draudio_post_message_dsound(&pContextDS->messageQueue, msg); - -#if 0 - if (pBufferDS->pDSNotify != NULL) { - IDirectSoundNotify_Release(pBufferDS->pDSNotify); - } - - if (pBufferDS->pDSBuffer3D != NULL) { - IDirectSound3DBuffer_Release(pBufferDS->pDSBuffer3D); - } - - if (pBufferDS->pDSBuffer != NULL) { - IDirectSoundBuffer8_Release(pBufferDS->pDSBuffer); - } - - free(pBufferDS); -#endif -} - - -unsigned int draudio_get_buffer_extra_data_size_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - return pBufferDS->extraDataSize; -} - -void* draudio_get_buffer_extra_data_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - return pBufferDS->pExtraData; -} - - -void draudio_set_buffer_data_dsound(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - assert(pData != NULL); - - LPVOID lpvWrite; - DWORD dwLength; - HRESULT hr = IDirectSoundBuffer8_Lock(pBufferDS->pDSBuffer, (DWORD)offset, (DWORD)dataSizeInBytes, &lpvWrite, &dwLength, NULL, NULL, 0); - if (FAILED(hr)) { - return; - } - - assert(dataSizeInBytes <= dwLength); - memcpy(lpvWrite, pData, dataSizeInBytes); - - hr = IDirectSoundBuffer8_Unlock(pBufferDS->pDSBuffer, lpvWrite, dwLength, NULL, 0); - if (FAILED(hr)) { - return; - } -} - - -void draudio_play_dsound(draudio_buffer* pBuffer, bool loop) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - bool postEvent = true; - if (pBufferDS->playbackState == draudio_playing) { - postEvent = false; - } - - - // Events need to be activated. - if (pBufferDS->playbackState == draudio_stopped) { - draudio_activate_buffer_events_dsound(pBuffer); - } - - - DWORD dwFlags = 0; - if (loop) { - dwFlags |= DSBPLAY_LOOPING; - } - - pBufferDS->playbackState = draudio_playing; - IDirectSoundBuffer8_Play(pBufferDS->pDSBuffer, 0, 0, dwFlags); - - // If we have a play event we need to signal the event which will cause the worker thread to call the callback function. - if (pBufferDS->pPlayEvent != NULL && postEvent) { - SetEvent(pBufferDS->pPlayEvent->hEvent); - } -} - -void draudio_pause_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (pBufferDS->playbackState == draudio_playing) - { - pBufferDS->playbackState = draudio_paused; - IDirectSoundBuffer8_Stop(pBufferDS->pDSBuffer); - - // If we have a pause event we need to signal the event which will cause the worker thread to call the callback function. - if (pBufferDS->pPlayEvent != NULL) { - SetEvent(pBufferDS->pPauseEvent->hEvent); - } - } -} - -void draudio_stop_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (pBufferDS->playbackState == draudio_playing) - { - pBufferDS->playbackState = draudio_stopped; - IDirectSoundBuffer8_Stop(pBufferDS->pDSBuffer); - IDirectSoundBuffer8_SetCurrentPosition(pBufferDS->pDSBuffer, 0); - } - else if (pBufferDS->playbackState == draudio_paused) - { - pBufferDS->playbackState = draudio_stopped; - IDirectSoundBuffer8_SetCurrentPosition(pBufferDS->pDSBuffer, 0); - - if (pBufferDS->pStopEvent != NULL) { - SetEvent(pBufferDS->pStopEvent->hEvent); - } - } -} - -draudio_playback_state draudio_get_playback_state_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - return pBufferDS->playbackState; -} - - -void draudio_set_playback_position_dsound(draudio_buffer* pBuffer, unsigned int position) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - IDirectSoundBuffer8_SetCurrentPosition(pBufferDS->pDSBuffer, position); -} - -unsigned int draudio_get_playback_position_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - DWORD position; - HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pBufferDS->pDSBuffer, &position, NULL); - if (FAILED(hr)) { - return 0; - } - - return position; -} - - -void draudio_set_pan_dsound(draudio_buffer* pBuffer, float pan) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - LONG panDB; - if (pan == 0) { - panDB = DSBPAN_CENTER; - } else { - if (pan > 1) { - panDB = DSBPAN_RIGHT; - } else if (pan < -1) { - panDB = DSBPAN_LEFT; - } else { - if (pan < 0) { - panDB = (LONG)((20*log10f(1 + pan)) * 100); - } else { - panDB = -(LONG)((20*log10f(1 - pan)) * 100); - } - } - } - - IDirectSoundBuffer_SetPan(pBufferDS->pDSBuffer, panDB); -} - -float draudio_get_pan_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - LONG panDB; - HRESULT hr = IDirectSoundBuffer_GetPan(pBufferDS->pDSBuffer, &panDB); - if (FAILED(hr)) { - return 0; - } - - - if (panDB < 0) { - return -(1 - (float)(1.0f / powf(10.0f, -panDB / (20.0f*100.0f)))); - } - - if (panDB > 0) { - return (1 - (float)(1.0f / powf(10.0f, panDB / (20.0f*100.0f)))); - } - - return 0; -} - - -void draudio_set_volume_dsound(draudio_buffer* pBuffer, float volume) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - LONG volumeDB; - if (volume > 0) { - if (volume < 1) { - volumeDB = (LONG)((20*log10f(volume)) * 100); - } else { - volumeDB = DSBVOLUME_MAX; - } - } else { - volumeDB = DSBVOLUME_MIN; - } - - IDirectSoundBuffer_SetVolume(pBufferDS->pDSBuffer, volumeDB); -} - -float draudio_get_volume_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - LONG volumeDB; - HRESULT hr = IDirectSoundBuffer_GetVolume(pBufferDS->pDSBuffer, &volumeDB); - if (FAILED(hr)) { - return 1; - } - - return (float)(1.0f / powf(10.0f, -volumeDB / (20.0f*100.0f))); -} - - -void draudio_remove_markers_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - for (unsigned int iMarker = 0; iMarker < pBufferDS->markerEventCount; ++iMarker) - { - if (pBufferDS->pMarkerEvents[iMarker] != NULL) { - draudio_delete_event_dsound(pBufferDS->pMarkerEvents[iMarker]); - pBufferDS->pMarkerEvents[iMarker] = NULL; - } - } - - pBufferDS->markerEventCount = 0; -} - -bool draudio_register_marker_callback_dsound(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - assert(pBufferDS->markerEventCount <= DRAUDIO_MAX_MARKER_COUNT); - - if (pBufferDS->markerEventCount == DRAUDIO_MAX_MARKER_COUNT) { - // Too many markers. - return false; - } - - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext; - assert(pContextDS != NULL); - - draudio_event_dsound* pEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, eventID, pUserData); - if (pEvent == NULL) { - return false; - } - - // draudio_create_event_dsound() will initialize the marker offset to 0, so we'll need to set it manually here. - pEvent->markerOffset = (DWORD)offsetInBytes; - - pBufferDS->pMarkerEvents[pBufferDS->markerEventCount] = pEvent; - pBufferDS->markerEventCount += 1; - - return true; -} - -bool draudio_register_stop_callback_dsound(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (callback == NULL) - { - if (pBufferDS->pStopEvent != NULL) { - draudio_delete_event_dsound(pBufferDS->pStopEvent); - pBufferDS->pStopEvent = NULL; - } - - return true; - } - else - { - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext; - - // If we already have a stop event, just replace the existing one. - if (pBufferDS->pStopEvent != NULL) { - draudio_update_event_dsound(pBufferDS->pStopEvent, callback, pUserData); - } else { - pBufferDS->pStopEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, DRAUDIO_EVENT_ID_STOP, pUserData); - } - - return pBufferDS->pStopEvent != NULL; - } -} - -bool draudio_register_pause_callback_dsound(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (callback == NULL) - { - if (pBufferDS->pPauseEvent != NULL) { - draudio_delete_event_dsound(pBufferDS->pPauseEvent); - pBufferDS->pPauseEvent = NULL; - } - - return true; - } - else - { - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext; - - // If we already have a stop event, just replace the existing one. - if (pBufferDS->pPauseEvent != NULL) { - draudio_update_event_dsound(pBufferDS->pPauseEvent, callback, pUserData); - } else { - pBufferDS->pPauseEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, DRAUDIO_EVENT_ID_PAUSE, pUserData); - } - - return pBufferDS->pPauseEvent != NULL; - } -} - -bool draudio_register_play_callback_dsound(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (callback == NULL) - { - if (pBufferDS->pPlayEvent != NULL) { - draudio_delete_event_dsound(pBufferDS->pPlayEvent); - pBufferDS->pPlayEvent = NULL; - } - - return true; - } - else - { - draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext; - - // If we already have a stop event, just replace the existing one. - if (pBufferDS->pPlayEvent != NULL) { - draudio_update_event_dsound(pBufferDS->pPlayEvent, callback, pUserData); - } else { - pBufferDS->pPlayEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, DRAUDIO_EVENT_ID_PLAY, pUserData); - } - - return pBufferDS->pPlayEvent != NULL; - } -} - - - -void draudio_set_position_dsound(draudio_buffer* pBuffer, float x, float y, float z) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (pBufferDS->pDSBuffer3D != NULL) { - IDirectSound3DBuffer_SetPosition(pBufferDS->pDSBuffer3D, x, y, z, DS3D_IMMEDIATE); - } -} - -void draudio_get_position_dsound(draudio_buffer* pBuffer, float* pPosOut) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - assert(pPosOut != NULL); - - if (pBufferDS->pDSBuffer3D != NULL) - { - D3DVECTOR pos; - IDirectSound3DBuffer_GetPosition(pBufferDS->pDSBuffer3D, &pos); - - pPosOut[0] = pos.x; - pPosOut[1] = pos.y; - pPosOut[2] = pos.z; - } - else - { - pPosOut[0] = 0; - pPosOut[1] = 1; - pPosOut[2] = 2; - } -} - - -void draudio_set_listener_position_dsound(draudio_device* pDevice, float x, float y, float z) -{ - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice; - assert(pDeviceDS != NULL); - - IDirectSound3DListener_SetPosition(pDeviceDS->pDSListener, x, y, z, DS3D_IMMEDIATE); -} - -void draudio_get_listener_position_dsound(draudio_device* pDevice, float* pPosOut) -{ - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice; - assert(pDeviceDS != NULL); - assert(pPosOut != NULL); - - D3DVECTOR pos; - IDirectSound3DListener_GetPosition(pDeviceDS->pDSListener, &pos); - - pPosOut[0] = pos.x; - pPosOut[1] = pos.y; - pPosOut[2] = pos.z; -} - - -void draudio_set_listener_orientation_dsound(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ) -{ - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice; - assert(pDeviceDS != NULL); - - IDirectSound3DListener_SetOrientation(pDeviceDS->pDSListener, forwardX, forwardY, forwardZ, upX, upY, upZ, DS3D_IMMEDIATE); -} - -void draudio_get_listener_orientation_dsound(draudio_device* pDevice, float* pForwardOut, float* pUpOut) -{ - draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice; - assert(pDeviceDS != NULL); - assert(pForwardOut != NULL); - assert(pUpOut != NULL); - - D3DVECTOR forward; - D3DVECTOR up; - IDirectSound3DListener_GetOrientation(pDeviceDS->pDSListener, &forward, &up); - - pForwardOut[0] = forward.x; - pForwardOut[1] = forward.y; - pForwardOut[2] = forward.z; - - pUpOut[0] = up.x; - pUpOut[1] = up.y; - pUpOut[2] = up.z; -} - -void draudio_set_3d_mode_dsound(draudio_buffer* pBuffer, draudio_3d_mode mode) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (pBufferDS->pDSBuffer3D == NULL) { - return; - } - - - DWORD dwMode = DS3DMODE_NORMAL; - if (mode == draudio_3d_mode_relative) { - dwMode = DS3DMODE_HEADRELATIVE; - } else if (mode == draudio_3d_mode_disabled) { - dwMode = DS3DMODE_DISABLE; - } - - IDirectSound3DBuffer_SetMode(pBufferDS->pDSBuffer3D, dwMode, DS3D_IMMEDIATE); -} - -draudio_3d_mode draudio_get_3d_mode_dsound(draudio_buffer* pBuffer) -{ - draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer; - assert(pBufferDS != NULL); - - if (pBufferDS->pDSBuffer3D == NULL) { - return draudio_3d_mode_disabled; - } - - - DWORD dwMode; - if (FAILED(IDirectSound3DBuffer_GetMode(pBufferDS->pDSBuffer3D, &dwMode))) { - return draudio_3d_mode_disabled; - } - - - if (dwMode == DS3DMODE_NORMAL) { - return draudio_3d_mode_absolute; - } - - if (dwMode == DS3DMODE_HEADRELATIVE) { - return draudio_3d_mode_relative; - } - - return draudio_3d_mode_disabled; -} - - -static BOOL CALLBACK DSEnumCallback_OutputDevices(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) -{ - // From MSDN: - // - // The first device enumerated is always called the Primary Sound Driver, and the lpGUID parameter of the callback is - // NULL. This device represents the preferred output device set by the user in Control Panel. - - draudio_context_dsound* pContextDS = (draudio_context_dsound*)lpContext; - assert(pContextDS != NULL); - - if (pContextDS->outputDeviceCount < DRAUDIO_MAX_DEVICE_COUNT) - { - if (lpGuid != NULL) { - memcpy(&pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].guid, lpGuid, sizeof(GUID)); - } else { - memset(&pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].guid, 0, sizeof(GUID)); - } - - draudio_strcpy(pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].description, 256, lpcstrDescription); - draudio_strcpy(pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].moduleName, 256, lpcstrModule); - - pContextDS->outputDeviceCount += 1; - return TRUE; - } - else - { - // Ran out of device slots. - return FALSE; - } -} - -static BOOL CALLBACK DSEnumCallback_InputDevices(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) -{ - // From MSDN: - // - // The first device enumerated is always called the Primary Sound Driver, and the lpGUID parameter of the callback is - // NULL. This device represents the preferred output device set by the user in Control Panel. - - draudio_context_dsound* pContextDS = (draudio_context_dsound*)lpContext; - assert(pContextDS != NULL); - - if (pContextDS->inputDeviceCount < DRAUDIO_MAX_DEVICE_COUNT) - { - if (lpGuid != NULL) { - memcpy(&pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].guid, lpGuid, sizeof(GUID)); - } else { - memset(&pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].guid, 0, sizeof(GUID)); - } - - draudio_strcpy(pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].description, 256, lpcstrDescription); - draudio_strcpy(pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].moduleName, 256, lpcstrModule); - - pContextDS->inputDeviceCount += 1; - return TRUE; - } - else - { - // Ran out of device slots. - return FALSE; - } -} - -draudio_context* draudio_create_context_dsound() -{ - // Load the DLL. - HMODULE hDSoundDLL = LoadLibraryW(L"dsound.dll"); - if (hDSoundDLL == NULL) { - return NULL; - } - - - // Retrieve the APIs. - pDirectSoundCreate8Proc pDirectSoundCreate8 = (pDirectSoundCreate8Proc)GetProcAddress(hDSoundDLL, "DirectSoundCreate8"); - if (pDirectSoundCreate8 == NULL){ - FreeLibrary(hDSoundDLL); - return NULL; - } - - pDirectSoundEnumerateAProc pDirectSoundEnumerateA = (pDirectSoundEnumerateAProc)GetProcAddress(hDSoundDLL, "DirectSoundEnumerateA"); - if (pDirectSoundEnumerateA == NULL){ - FreeLibrary(hDSoundDLL); - return NULL; - } - - pDirectSoundCaptureCreate8Proc pDirectSoundCaptureCreate8 = (pDirectSoundCaptureCreate8Proc)GetProcAddress(hDSoundDLL, "DirectSoundCaptureCreate8"); - if (pDirectSoundCaptureCreate8 == NULL) { - FreeLibrary(hDSoundDLL); - return NULL; - } - - pDirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA = (pDirectSoundCaptureEnumerateAProc)GetProcAddress(hDSoundDLL, "DirectSoundCaptureEnumerateA"); - if (pDirectSoundCaptureEnumerateA == NULL ){ - FreeLibrary(hDSoundDLL); - return NULL; - } - - - - // At this point we can almost certainly assume DirectSound is usable so we'll now go ahead and create the context. - draudio_context_dsound* pContext = (draudio_context_dsound*)malloc(sizeof(draudio_context_dsound)); - if (pContext != NULL) - { - pContext->base.delete_context = draudio_delete_context_dsound; - pContext->base.create_output_device = draudio_create_output_device_dsound; - pContext->base.delete_output_device = draudio_delete_output_device_dsound; - pContext->base.get_output_device_count = draudio_get_output_device_count_dsound; - pContext->base.get_output_device_info = draudio_get_output_device_info_dsound; - pContext->base.create_buffer = draudio_create_buffer_dsound; - pContext->base.delete_buffer = draudio_delete_buffer_dsound; - pContext->base.get_buffer_extra_data_size = draudio_get_buffer_extra_data_size_dsound; - pContext->base.get_buffer_extra_data = draudio_get_buffer_extra_data_dsound; - pContext->base.set_buffer_data = draudio_set_buffer_data_dsound; - pContext->base.play = draudio_play_dsound; - pContext->base.pause = draudio_pause_dsound; - pContext->base.stop = draudio_stop_dsound; - pContext->base.get_playback_state = draudio_get_playback_state_dsound; - pContext->base.set_playback_position = draudio_set_playback_position_dsound; - pContext->base.get_playback_position = draudio_get_playback_position_dsound; - pContext->base.set_pan = draudio_set_pan_dsound; - pContext->base.get_pan = draudio_get_pan_dsound; - pContext->base.set_volume = draudio_set_volume_dsound; - pContext->base.get_volume = draudio_get_volume_dsound; - pContext->base.remove_markers = draudio_remove_markers_dsound; - pContext->base.register_marker_callback = draudio_register_marker_callback_dsound; - pContext->base.register_stop_callback = draudio_register_stop_callback_dsound; - pContext->base.register_pause_callback = draudio_register_pause_callback_dsound; - pContext->base.register_play_callback = draudio_register_play_callback_dsound; - pContext->base.set_position = draudio_set_position_dsound; - pContext->base.get_position = draudio_get_position_dsound; - pContext->base.set_listener_position = draudio_set_listener_position_dsound; - pContext->base.get_listener_position = draudio_get_listener_position_dsound; - pContext->base.set_listener_orientation = draudio_set_listener_orientation_dsound; - pContext->base.get_listener_orientation = draudio_get_listener_orientation_dsound; - pContext->base.set_3d_mode = draudio_set_3d_mode_dsound; - pContext->base.get_3d_mode = draudio_get_3d_mode_dsound; - - pContext->hDSoundDLL = hDSoundDLL; - pContext->pDirectSoundCreate8 = pDirectSoundCreate8; - pContext->pDirectSoundEnumerateA = pDirectSoundEnumerateA; - pContext->pDirectSoundCaptureCreate8 = pDirectSoundCaptureCreate8; - pContext->pDirectSoundCaptureEnumerateA = pDirectSoundCaptureEnumerateA; - - // Enumerate output devices. - pContext->outputDeviceCount = 0; - pContext->pDirectSoundEnumerateA(DSEnumCallback_OutputDevices, pContext); - - // Enumerate input devices. - pContext->inputDeviceCount = 0; - pContext->pDirectSoundCaptureEnumerateA(DSEnumCallback_InputDevices, pContext); - - // The message queue and marker notification thread. - if (!draudio_init_message_queue_dsound(&pContext->messageQueue) || !draudio_init_event_manager_dsound(&pContext->eventManager, &pContext->messageQueue)) - { - // Failed to initialize the event manager. - FreeLibrary(hDSoundDLL); - free(pContext); - - return NULL; - } - } - - return (draudio_context*)pContext; -} -#endif // !DRAUDIO_BUILD_DSOUND - - -/////////////////////////////////////////////////////////////////////////////// -// -// XAudio2 -// -/////////////////////////////////////////////////////////////////////////////// - -#if 0 -#define uuid(x) -#define DX_BUILD -#define INITGUID 1 -#include -#endif -#endif - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_fs.h b/source/engine/thirdparty/dr_libs/old/dr_fs.h deleted file mode 100644 index 6589c14..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_fs.h +++ /dev/null @@ -1,8051 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. -// -// Includes code from miniz.c which can be found here: https://github.com/richgel999/miniz - -// NOTE: dr_fs is very early in development and should be considered unstable. Expect many APIs to change. - -// ABOUT -// -// dr_fs is a simple library which abstracts file IO to allow one to open files from both the native file -// system and archive/package files such as Zip files using a common API. -// -// This file includes code from miniz.c which has been stripped down to include only what's needed to support -// Zip files at basic level. Every public API has been namespaced with "drfs_" to avoid naming conflicts. -// -// Some noteworthy features: -// - Supports verbose absolute paths to avoid ambiguity. For example you can specify a path -// such as "my/package.zip/file.txt" -// - Supports shortened, transparent paths by automatically scanning for supported archives. The -// path "my/package.zip/file.txt" can be shortened to "my/file.txt", for example. This does not -// work for absolute paths, however. See notes below. -// - Fully recursive. A path such as "pack1.zip/pack2.zip/file.txt" should work just fine. -// - Easily supports custom package formats without the need to modify the original source code. -// Look at drfs_register_archive_backend() and the implementation of Zip archives for an -// example. -// - No dependencies except for the C standard library. -// -// Limitations: -// - When a file contained within a Zip file is opened, the entire uncompressed data is loaded -// onto the heap. Keep this in mind when working with large files. -// - Zip, PAK and Wavefront MTL archives are read-only at the moment. -// - dr_fs is not fully thread-safe. See notes below. -// - Asynchronous IO is not supported. -// -// -// -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_FS_IMPLEMENTATION -// #include "dr_fs.h" -// -// You can then #include dr_fs.h in other parts of the program as you would with any other header file. -// -// Example: -// // Create a context. -// drfs_context* pVFS = drfs_create_context(); -// if (pVFS == NULL) { -// // There was an error creating the context. -// } -// -// // Add your base directories for loading from relative paths. If you do not specify at -// // least one base directory you will need to load from absolute paths. -// drfs_add_base_directory(pVFS, "C:/Users/Admin"); -// drfs_add_base_directory(pVFS, "C:/My/Folder"); -// -// ... -// -// // Open a file. A relative path was specified which means it will first check it against -// // "C:/Users/Admin". If it can't be found it will then check against "C:/My/Folder". -// drfs_file* pFile; -// drfs_result result = drfs_open(pVFS, "my/file.txt", DRFS_READ, &pFile); -// if (result != drfs_success) { -// // There was an error loading the file. It probably doesn't exist. -// } -// -// result = drfs_read(pFile, buffer, bufferSize, NULL); -// if (result != drfs_success) { -// // There was an error reading the file. -// } -// -// drfs_close(pFile); -// -// ... -// -// // Shutdown. -// drfs_delete_context(pVFS); -// -// -// -// OPTIONS -// -// To use these options, just place the appropriate #define's in the .c file before including this file. -// -// #define DR_FS_NO_ZIP -// Disable built-in support for Zip files. -// -// #define DR_FS_NO_PAK -// Disable support for Quake 2 PAK files. -// -// #define DR_FS_NO_MTL -// Disable support for Wavefront MTL files. -// -// -// -// THREAD SAFETY -// -// dr_fs is not fully thread safe. Known unsafe functionality includes: -// - Opening a file while adding or removing base directories and backends -// - Closing a file while doing anything on that file object -// - drfs_open() will malloc() the drfs_file object, and drfs_close() will free() it with no garbage collection -// nor reference counting. -// -// The issues mentioned above should not be an issue for the vast majority of cases. Base directories and backends -// will typically be registered once during initialization when the context is created, and it's unlikely an -// application will want to close a file while simultaneously trying to use it on another thread without doing it's -// own synchronization anyway. -// -// Thread-safety has not been completely ignored either. It is possible to read, write and seek on multiple threads. -// In this case it is a simple matter of first-in first-served. Also, APIs are in place to allow an application to -// do it's own synchronization. An application can use drfs_lock() and drfs_unlock() to lock and unlock a file using -// simple mutal exclusion. Inside the lock/unlock pair the application can then use the "_nolock" variation of the -// relevant APIs: -// - drfs_read_nolock() -// - drfs_write_nolock() -// - drfs_seek_nolock() -// - drfs_tell_nolock() -// - drfs_size_nolock() -// -// Opening two files that share the same archive should work fine across multiple threads. For example, if you have -// an archive called MyArchive.zip and then open two files within that archive, you can do work with each of those -// files independently on separate threads. This functionality depends on the implementation of the relevant backend, -// however. -// -// When implementing a backend, it is important to keep synchronization in mind when reading data from the host -// archive file. To help with this, use the drfs_lock() and drfs_unlock() combined with the "_nolock" variations -// of the APIs listed above. -// -// -// -// QUICK NOTES -// -// - The library works by using the notion of an "archive" to create an abstraction around the file system. -// - Conceptually, and archive is just a grouping of files and folders. An archive can be a directory on the native -// file system or an actual archive file such as a .zip file. -// - When iterating over files and folder, the order is undefined. Do not assume alphabetical. -// - When a path includes the name of the package file, such as "my/package.zip/file.txt" (note how the .zip file is -// included in the path), it is referred to as a verbose path. -// - When specifying an absolute path, it is assumed to be verbose. When specifying a relative path, it does not need -// to be verbose, in which case the library will try to search for it. A path such as "my/package.zip/file.txt" is -// equivalent to "my/file.txt". -// - Archive backends are selected based on their extension. -// - Archive backends cannot currently share the same extension. For example, many package file formats use the .pak -// extension, however only one backend can use that .pak extension. -// - For safety, if you want to overwrite a file you must explicitly call drfs_open() with the DRFS_TRUNCATE flag. -// - Platforms other than Windows do not use buffering. That is, they use read() and write() instead of fread() and -// fwrite(). -// - On Linux platforms, if you are having issues with opening files larger than 2GB, make sure this file is the first -// file included in the .c file. This ensures the _LARGEFILE64_SOURCE macro is defined before any other header file -// as required for the use of 64-bit variants of the POSIX APIs. -// - Base paths must be absolute and verbose. -// -// -// -// TODO: -// -// - Test result code consistency. -// - Document performance issues. -// - Consider making it so persistent constant strings (such as base paths) use dynamically allocated strings rather -// than fixed sized arrays of DRFS_MAX_PATH. -// - Replace the miniz reading functionality with a custom one: -// - There is a sort-of-bug where miniz does not correctly enumerate directories in a zip file that was created with -// the "Send to -> Compressed (zipped) folder" functionality in Windows Explorer. This is more of a thing with -// Windows Explorer more than anything, but it'd be nice if it would Just Work. -// - miniz does not support streamed reading yet. Instead, one must decompress the entire file onto the heap which -// is a bit untidy and doesn't work well with very large files. -// - ZIP64 is not supported. - -#ifndef dr_fs_h -#define dr_fs_h - -// These need to be defined before including any headers, but we don't want to expose it to the public header. -#if defined(DR_FS_IMPLEMENTATION) && !defined(_WIN32) -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif -#endif - -#include - -#ifndef DR_SIZED_TYPES_DEFINED -#define DR_SIZED_TYPES_DEFINED -#if defined(_MSC_VER) && _MSC_VER < 1600 -typedef signed char dr_int8; -typedef unsigned char dr_uint8; -typedef signed short dr_int16; -typedef unsigned short dr_uint16; -typedef signed int dr_int32; -typedef unsigned int dr_uint32; -typedef signed __int64 dr_int64; -typedef unsigned __int64 dr_uint64; -#else -#include -typedef int8_t dr_int8; -typedef uint8_t dr_uint8; -typedef int16_t dr_int16; -typedef uint16_t dr_uint16; -typedef int32_t dr_int32; -typedef uint32_t dr_uint32; -typedef int64_t dr_int64; -typedef uint64_t dr_uint64; -#endif -typedef dr_uint8 dr_bool8; -typedef dr_uint32 dr_bool32; -#define DR_TRUE 1 -#define DR_FALSE 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -// The maximum length of a path in bytes, including the null terminator. If a path exceeds this amount, it will be set to an empty -// string. When this is changed the source file will need to be recompiled. Most of the time leaving this at 256 is fine, but it's -// not a problem to increase the size if you are encountering issues. Note that increasing this value will increase memory usage -// on both the heap and the stack. -#ifndef DRFS_MAX_PATH -//#define DRFS_MAX_PATH 256 -#define DRFS_MAX_PATH 1024 -//#define DRFS_MAX_PATH 4096 -#endif - -#define DRFS_READ (1 << 0) -#define DRFS_WRITE (1 << 1) -#define DRFS_EXISTING (1 << 2) -#define DRFS_TRUNCATE (1 << 3) -#define DRFS_CREATE_DIRS (1 << 4) // Creates the directory structure if required. - -#define DRFS_FILE_ATTRIBUTE_DIRECTORY 0x00000001 -#define DRFS_FILE_ATTRIBUTE_READONLY 0x00000002 - -// Result codes. -typedef enum -{ - drfs_success = 0, - drfs_unknown_error = -1, - drfs_invalid_args = -2, // Bad input arguments like a file path string is equal to NULL or whatnot. - drfs_does_not_exist = -3, - drfs_already_exists = -4, - drfs_permission_denied = -5, - drfs_too_many_open_files = -6, - drfs_no_backend = -7, - drfs_out_of_memory = -8, - drfs_not_in_write_directory = -9, // A write operation is required, but the given path is not within the write directory or it's sub-directories. - drfs_path_too_long = -10, - drfs_no_space = -11, - drfs_not_directory = -12, - drfs_too_large = -13, - drfs_at_end_of_file = -14, - drfs_invalid_archive = -15, - drfs_negative_seek = -16 -} drfs_result; - -// The allowable seeking origins. -typedef enum -{ - drfs_origin_current, - drfs_origin_start, - drfs_origin_end -}drfs_seek_origin; - - -typedef void* drfs_handle; - -typedef struct drfs_context drfs_context; -typedef struct drfs_archive drfs_archive; -typedef struct drfs_file drfs_file; -typedef struct drfs_file_info drfs_file_info; -typedef struct drfs_iterator drfs_iterator; - -typedef dr_bool32 (* drfs_is_valid_extension_proc)(const char* extension); -typedef drfs_result (* drfs_open_archive_proc) (drfs_file* pArchiveFile, unsigned int accessMode, drfs_handle* pHandleOut); -typedef void (* drfs_close_archive_proc) (drfs_handle archive); -typedef drfs_result (* drfs_get_file_info_proc) (drfs_handle archive, const char* relativePath, drfs_file_info* fi); -typedef drfs_handle (* drfs_begin_iteration_proc) (drfs_handle archive, const char* relativePath); -typedef void (* drfs_end_iteration_proc) (drfs_handle archive, drfs_handle iterator); -typedef dr_bool32 (* drfs_next_iteration_proc) (drfs_handle archive, drfs_handle iterator, drfs_file_info* fi); -typedef drfs_result (* drfs_delete_file_proc) (drfs_handle archive, const char* relativePath); -typedef drfs_result (* drfs_create_directory_proc) (drfs_handle archive, const char* relativePath); -typedef drfs_result (* drfs_move_file_proc) (drfs_handle archive, const char* relativePathOld, const char* relativePathNew); -typedef drfs_result (* drfs_copy_file_proc) (drfs_handle archive, const char* relativePathSrc, const char* relativePathDst, dr_bool32 failIfExists); -typedef drfs_result (* drfs_open_file_proc) (drfs_handle archive, const char* relativePath, unsigned int accessMode, drfs_handle* pHandleOut); -typedef void (* drfs_close_file_proc) (drfs_handle archive, drfs_handle file); -typedef drfs_result (* drfs_read_file_proc) (drfs_handle archive, drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut); -typedef drfs_result (* drfs_write_file_proc) (drfs_handle archive, drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut); -typedef drfs_result (* drfs_seek_file_proc) (drfs_handle archive, drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin); -typedef dr_uint64 (* drfs_tell_file_proc) (drfs_handle archive, drfs_handle file); -typedef dr_uint64 (* drfs_file_size_proc) (drfs_handle archive, drfs_handle file); -typedef void (* drfs_flush_file_proc) (drfs_handle archive, drfs_handle file); - -typedef struct -{ - drfs_is_valid_extension_proc is_valid_extension; - drfs_open_archive_proc open_archive; - drfs_close_archive_proc close_archive; - drfs_get_file_info_proc get_file_info; - drfs_begin_iteration_proc begin_iteration; - drfs_end_iteration_proc end_iteration; - drfs_next_iteration_proc next_iteration; - drfs_delete_file_proc delete_file; - drfs_create_directory_proc create_directory; - drfs_move_file_proc move_file; - drfs_copy_file_proc copy_file; - drfs_open_file_proc open_file; - drfs_close_file_proc close_file; - drfs_read_file_proc read_file; - drfs_write_file_proc write_file; - drfs_seek_file_proc seek_file; - drfs_tell_file_proc tell_file; - drfs_file_size_proc file_size; - drfs_flush_file_proc flush_file; -} drfs_archive_callbacks; - -struct drfs_file_info -{ - // The absolute path of the file. - char absolutePath[DRFS_MAX_PATH]; - - // The size of the file, in bytes. - dr_uint64 sizeInBytes; - - // The time the file was last modified. - dr_uint64 lastModifiedTime; - - // File attributes. - unsigned int attributes; -}; - -struct drfs_iterator -{ - // A pointer to the archive that contains the folder being iterated. - drfs_archive* pArchive; - - // A pointer to the iterator's internal handle that was returned with begin_iteration(). - drfs_handle internalIteratorHandle; - - // The file info. - drfs_file_info info; -}; - - -typedef struct -{ - drfs_archive_callbacks* pBuffer; - unsigned int count; -} drfs_callbacklist; - -typedef struct -{ - char absolutePath[DRFS_MAX_PATH]; -} drfs_basepath; - -typedef struct -{ - drfs_basepath* pBuffer; - unsigned int capacity; - unsigned int count; -} drfs_basedirs; - -struct drfs_context -{ - // The list of archive callbacks which are used for loading non-native archives. This does not include the native callbacks. - drfs_callbacklist archiveCallbacks; - - // The list of base directories. - drfs_basedirs baseDirectories; - - // The write base directory. - char writeBaseDirectory[DRFS_MAX_PATH]; - - // Keeps track of whether or not write directory guard is enabled. - dr_bool32 isWriteGuardEnabled; -}; - - -// Initializes a pre-allocated context. -drfs_result drfs_init(drfs_context* pContext); - -// Uninitializes a context. -drfs_result drfs_uninit(drfs_context* pContext); - - -// Creates an empty context. -drfs_context* drfs_create_context(); - -// Deletes the given context. -// -// This does not close any files or archives - it is up to the application to ensure those are tidied up. -void drfs_delete_context(drfs_context* pContext); - - -// Registers an archive back-end. -void drfs_register_archive_backend(drfs_context* pContext, drfs_archive_callbacks callbacks); - - -// Inserts a base directory at a specific priority position. -// -// A lower value index means a higher priority. This must be in the range of [0, drfs_get_base_directory_count()]. -void drfs_insert_base_directory(drfs_context* pContext, const char* absolutePath, unsigned int index); - -// Adds a base directory to the end of the list. -// -// The further down the list the base directory, the lower priority is will receive. This adds it to the end which -// means it it given a lower priority to those that are already in the list. Use drfs_insert_base_directory() to -// insert the base directory at a specific position. -// -// Base directories must be an absolute path to a real directory. -void drfs_add_base_directory(drfs_context* pContext, const char* absolutePath); - -// Removes the given base directory. -void drfs_remove_base_directory(drfs_context* pContext, const char* absolutePath); - -// Removes the directory at the given index. -// -// If you need to remove every base directory, use drfs_remove_all_base_directories() since that is more efficient. -void drfs_remove_base_directory_by_index(drfs_context* pContext, unsigned int index); - -// Removes every base directory from the given context. -void drfs_remove_all_base_directories(drfs_context* pContext); - -// Retrieves the number of base directories attached to the given context. -unsigned int drfs_get_base_directory_count(drfs_context* pContext); - -// Retrieves the base directory at the given index. -const char* drfs_get_base_directory_by_index(drfs_context* pContext, unsigned int index); - - -// Sets the base directory for write operations (including delete). -// -// When doing a write operation using a relative path, the full path will be resolved using this directory as the base. -// -// If the base write directory is not set, and absolute path must be used for all write operations. -// -// If the write directory guard is enabled, all write operations that are attempted at a higher level than this directory -// will fail. -void drfs_set_base_write_directory(drfs_context* pContext, const char* absolutePath); - -// Retrieves the base write directory. -dr_bool32 drfs_get_base_write_directory(drfs_context* pContext, char* absolutePathOut, unsigned int absolutePathOutSize); - -// Enables the write directory guard. -void drfs_enable_write_directory_guard(drfs_context* pContext); - -// Disables the write directory guard. -void drfs_disable_write_directory_guard(drfs_context* pContext); - -// Determines whether or not the base directory guard is enabled. -dr_bool32 drfs_is_write_directory_guard_enabled(drfs_context* pContext); - - -// Opens an archive at the given path. -// -// If the given path points to a directory on the native file system an archive will be created at that -// directory. If the path points to an archive file such as a .zip file, dr_fs will hold a handle to -// that file until the archive is closed with drfs_close_archive(). Keep this in mind if you are keeping -// many archives open at a time on platforms that limit the number of files one can have open at any given -// time. -// -// The given path must be either absolute, or relative to one of the base directories. -// -// The path can be nested, such as "C:/my_zip_file.zip/my_inner_zip_file.zip". -drfs_result drfs_open_archive(drfs_context* pContext, const char* absoluteOrRelativePath, unsigned int accessMode, drfs_archive** ppArchiveOut); - -// Opens the archive that owns the given file. -// -// This is different to drfs_open_archive() in that it can accept non-archive files. It will open the -// archive that directly owns the file. In addition, it will output the path of the file, relative to the -// archive. -// -// If the given file is an archive itself, the archive that owns that archive will be opened. If the file -// is a file on the native file system, the returned archive will represent the folder it's directly -// contained in. -drfs_result drfs_open_owner_archive(drfs_context* pContext, const char* absoluteOrRelativePath, unsigned int accessMode, char* relativePathOut, size_t relativePathOutSize, drfs_archive** ppArchiveOut); - -// Closes the given archive. -void drfs_close_archive(drfs_archive* pArchive); - -// Opens a file relative to the given archive. -drfs_result drfs_open_file_from_archive(drfs_archive* pArchive, const char* relativePath, unsigned int accessMode, drfs_file** ppFileOut); - - - -// Opens a file. -// -// When opening the file in write mode, the write pointer will always be sitting at the start of the file. -drfs_result drfs_open(drfs_context* pContext, const char* absoluteOrRelativePath, unsigned int accessMode, drfs_file** ppFileOut); - -// Closes the given file. -void drfs_close(drfs_file* pFile); - -// Reads data from the given file. -// -// Returns DR_TRUE if successful; DR_FALSE otherwise. If the value output to is less than it means the file is at the end. -// -// Do not use the return value to check if the end of the file has been reached. Instead, compare to the value returned to . -drfs_result drfs_read(drfs_file* pFile, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut); - -// Writes data to the given file. -drfs_result drfs_write(drfs_file* pFile, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut); - -// Seeks the file pointer by the given number of bytes, relative to the specified origin. -drfs_result drfs_seek(drfs_file* pFile, dr_int64 bytesToSeek, drfs_seek_origin origin); - -// Retrieves the current position of the file pointer. -dr_uint64 drfs_tell(drfs_file* pFile); - -// Retrieves the size of the given file. -dr_uint64 drfs_size(drfs_file* pFile); - -// Flushes the given file. -void drfs_flush(drfs_file* pFile); - - -// Locks the given file for simple mutal exclusion. -// -// If DR_FALSE is returned it means there was an error and the operation should be aborted. -dr_bool32 drfs_lock(drfs_file* pFile); - -// Unlocks the given file for simple mutal exclusion. -void drfs_unlock(drfs_file* pFile); - -// Unlocked drfs_read() - should only be called inside a drfs_lock()/drfs_unlock() pair. -drfs_result drfs_read_nolock(drfs_file* pFile, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut); - -// Unlocked drfs_write() - should only be called inside a drfs_lock()/drfs_unlock() pair. -drfs_result drfs_write_nolock(drfs_file* pFile, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut); - -// Unlocked drfs_seek() - should only be called inside a drfs_lock()/drfs_unlock() pair. -drfs_result drfs_seek_nolock(drfs_file* pFile, dr_int64 bytesToSeek, drfs_seek_origin origin); - -// Unlocked drfs_tell() - should only be called inside a drfs_lock()/drfs_unlock() pair. -dr_uint64 drfs_tell_nolock(drfs_file* pFile); - -// Unlocked drfs_size() - should only be called inside a drfs_lock()/drfs_unlock() pair. -dr_uint64 drfs_size_nolock(drfs_file* pFile); - - -// Retrieves information about the file at the given path. -// -// is allowed to be null, in which case the call is equivalent to simply checking if the file exists. -drfs_result drfs_get_file_info(drfs_context* pContext, const char* absoluteOrRelativePath, drfs_file_info* fi); - - -// Creates an iterator for iterating over the files and folders in the given directory. -dr_bool32 drfs_begin(drfs_context* pContext, const char* absoluteOrRelativePath, drfs_iterator* pIteratorOut); - -// Goes to the next file or folder based on the given iterator. -dr_bool32 drfs_next(drfs_context* pContext, drfs_iterator* pIterator); - -// Closes the given iterator. -// -// This is not needed if drfs_next_iteration() returns DR_FALSE naturally. If iteration is terminated early, however, this -// needs to be called on the iterator to ensure internal resources are freed. -void drfs_end(drfs_context* pContext, drfs_iterator* pIterator); - - -// Deletes the file at the given path. -// -// The path must be a absolute, or relative to the write directory. -drfs_result drfs_delete_file(drfs_context* pContext, const char* path); - -// Creates a directory. -// -// The path must be a absolute, or relative to the write directory. -drfs_result drfs_create_directory(drfs_context* pContext, const char* path); - -// Moves or renames the given file. -// -// The path must be a absolute, or relative to the write directory. This will fail if: -// - the file already exists -// - the old and new paths are across different archives -// - the archive containing both the old and new paths is read-only -// - the destinations directory structure does not exist -// -// Consider using drfs_copy_file() for more flexibility with moving files to a different location. -drfs_result drfs_move_file(drfs_context* pContext, const char* pathOld, const char* pathNew); - -// Copies a file. -// -// The destination path must be a absolute, or relative to the write directory. -drfs_result drfs_copy_file(drfs_context* pContext, const char* srcPath, const char* dstPath, dr_bool32 failIfExists); - - -// Determines whether or not the given path refers to an archive file. -// -// This does not validate that the archive file exists or is valid. This will also return DR_FALSE if the path refers -// to a folder on the normal file system. -// -// Use drfs_open_archive() to check that the archive file actually exists. -dr_bool32 drfs_is_archive_path(drfs_context* pContext, const char* path); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// High Level API -// -/////////////////////////////////////////////////////////////////////////////// - -// Free's memory that was allocated internally by dr_fs. This is used when dr_fs allocates memory via a high-level helper API -// and the application is done with that memory. -void drfs_free(void* p); - -// Finds the absolute, verbose path of the given path. -drfs_result drfs_find_absolute_path(drfs_context* pContext, const char* relativePath, char* absolutePathOut, size_t absolutePathOutSize); - -// Finds the absolute, verbose path of the given path, using the given path as the higest priority base path. -drfs_result drfs_find_absolute_path_explicit_base(drfs_context* pContext, const char* relativePath, const char* highestPriorityBasePath, char* absolutePathOut, size_t absolutePathOutSize); - -// Helper function for determining whether or not the given path refers to a base directory. -dr_bool32 drfs_is_base_directory(drfs_context* pContext, const char* baseDir); - -// Helper function for writing a string. -drfs_result drfs_write_string(drfs_file* pFile, const char* str); - -// Helper function for writing a string, and then inserting a new line right after it. -// -// The new line character is "\n" and NOT "\r\n". -drfs_result drfs_write_line(drfs_file* pFile, const char* str); - - -// Helper function for opening a binary file and retrieving it's data in one go. -// -// Free the returned pointer with drfs_free() -void* drfs_open_and_read_binary_file(drfs_context* pContext, const char* absoluteOrRelativePath, size_t* pSizeInBytesOut); - -// Helper function for opening a text file and retrieving it's data in one go. -// -// Free the returned pointer with drfs_free(). -// -// The returned string is null terminated. The size returned by pSizeInBytesOut does not include the null terminator. -char* drfs_open_and_read_text_file(drfs_context* pContext, const char* absoluteOrRelativePath, size_t* pSizeInBytesOut); - -// Helper function for opening a file, writing the given data, and then closing it. This deletes the contents of the existing file, if any. -drfs_result drfs_open_and_write_binary_file(drfs_context* pContext, const char* absoluteOrRelativePath, const void* pData, size_t dataSize); - -// Helper function for opening a file, writing the given textual data, and then closing it. This deletes the contents of the existing file, if any. -drfs_result drfs_open_and_write_text_file(drfs_context* pContext, const char* absoluteOrRelativePath, const char* pTextData); - - -// Helper function for determining whether or not the given path refers to an existing file or directory. -dr_bool32 drfs_exists(drfs_context* pContext, const char* absoluteOrRelativePath); - -// Determines if the given path refers to an existing file (not a directory). -// -// This will return DR_FALSE for directories. Use drfs_exists() to check for either a file or directory. -dr_bool32 drfs_is_existing_file(drfs_context* pContext, const char* absoluteOrRelativePath); - -// Determines if the given path refers to an existing directory. -dr_bool32 drfs_is_existing_directory(drfs_context* pContext, const char* absoluteOrRelativePath); - -// Same as drfs_create_directory(), except creates the entire directory structure recursively. -drfs_result drfs_create_directory_recursive(drfs_context* pContext, const char* path); - -// Determines whether or not the given file is at the end. -// -// This is just a high-level helper function equivalent to drfs_tell(pFile) == drfs_size(pFile). -dr_bool32 drfs_eof(drfs_file* pFile); - - - -#ifdef __cplusplus -} -#endif - -#endif //dr_fs_h - - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// - -#ifdef DR_FS_IMPLEMENTATION -#include -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#endif - -// Whether or not the file owns the archive object it's part of. -#define DR_FS_OWNS_PARENT_ARCHIVE 0x00000001 - - -static int drfs__strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ -#ifdef _MSC_VER - return strcpy_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t i; - for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstSizeInBytes) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -#endif -} - -static int drfs__strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ -#ifdef _MSC_VER - return strncpy_s(dst, dstSizeInBytes, src, count); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return EINVAL; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t maxcount = count; - if (count == ((size_t)-1) || count >= dstSizeInBytes) { // -1 = _TRUNCATE - maxcount = dstSizeInBytes - 1; - } - - size_t i; - for (i = 0; i < maxcount && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (src[i] == '\0' || i == count || count == ((size_t)-1)) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -#endif -} - -static int drfs__strcat_s(char* dst, size_t dstSizeInBytes, const char* src) -{ -#ifdef _MSC_VER - return strcat_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - char* dstorig = dst; - - while (dstSizeInBytes > 0 && dst[0] != '\0') { - dst += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - return EINVAL; // Unterminated. - } - - - while (dstSizeInBytes > 0 && src[0] != '\0') { - *dst++ = *src++; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes > 0) { - dst[0] = '\0'; - } else { - dstorig[0] = '\0'; - return ERANGE; - } - - return 0; -#endif -} - -static int drfs__stricmp(const char* string1, const char* string2) -{ -#ifdef _MSC_VER - return _stricmp(string1, string2); -#else - return strcasecmp(string1, string2); -#endif -} - - -static dr_bool32 drfs_basedirs_init(drfs_basedirs* pBasePaths) -{ - if (pBasePaths == NULL) { - return DR_FALSE; - } - - pBasePaths->pBuffer = 0; - pBasePaths->capacity = 0; - pBasePaths->count = 0; - - return DR_TRUE; -} - -static void drfs_basedirs_uninit(drfs_basedirs* pBasePaths) -{ - if (pBasePaths == NULL) { - return; - } - - free(pBasePaths->pBuffer); -} - -static dr_bool32 drfs_basedirs_inflateandinsert(drfs_basedirs* pBasePaths, const char* absolutePath, unsigned int index) -{ - if (pBasePaths == NULL) { - return DR_FALSE; - } - - unsigned int newBufferSize = (pBasePaths->capacity == 0) ? 2 : pBasePaths->capacity*2; - - drfs_basepath* pOldBuffer = pBasePaths->pBuffer; - drfs_basepath* pNewBuffer = (drfs_basepath*)malloc(newBufferSize * sizeof(drfs_basepath)); - if (pNewBuffer == NULL) { - return DR_FALSE; - } - - for (unsigned int iDst = 0; iDst < index; ++iDst) { - memcpy(pNewBuffer + iDst, pOldBuffer + iDst, sizeof(drfs_basepath)); - } - - drfs__strcpy_s((pNewBuffer + index)->absolutePath, DRFS_MAX_PATH, absolutePath); - - for (unsigned int iDst = index; iDst < pBasePaths->count; ++iDst) { - memcpy(pNewBuffer + iDst + 1, pOldBuffer + iDst, sizeof(drfs_basepath)); - } - - - pBasePaths->pBuffer = pNewBuffer; - pBasePaths->capacity = newBufferSize; - pBasePaths->count += 1; - - free(pOldBuffer); - return DR_TRUE; -} - -static dr_bool32 drfs_basedirs_movedown1slot(drfs_basedirs* pBasePaths, unsigned int index) -{ - if (pBasePaths == NULL || pBasePaths->count >= pBasePaths->capacity) { - return DR_FALSE; - } - - for (unsigned int iDst = pBasePaths->count; iDst > index; --iDst) { - memcpy(pBasePaths->pBuffer + iDst, pBasePaths->pBuffer + iDst - 1, sizeof(drfs_basepath)); - } - - return DR_TRUE; -} - -static dr_bool32 drfs_basedirs_insert(drfs_basedirs* pBasePaths, const char* absolutePath, unsigned int index) -{ - if (pBasePaths == NULL || index > pBasePaths->count) { - return DR_FALSE; - } - - if (pBasePaths->count == pBasePaths->capacity) { - return drfs_basedirs_inflateandinsert(pBasePaths, absolutePath, index); - } else { - if (!drfs_basedirs_movedown1slot(pBasePaths, index)) { - return DR_FALSE; - } - - drfs__strcpy_s((pBasePaths->pBuffer + index)->absolutePath, DRFS_MAX_PATH, absolutePath); - pBasePaths->count += 1; - - return DR_TRUE; - } -} - -static dr_bool32 drfs_basedirs_remove(drfs_basedirs* pBasePaths, unsigned int index) -{ - if (pBasePaths == NULL || index >= pBasePaths->count) { - return DR_FALSE; - } - - assert(pBasePaths->count > 0); - - for (unsigned int iDst = index; iDst < pBasePaths->count - 1; ++iDst) { - memcpy(pBasePaths->pBuffer + iDst, pBasePaths->pBuffer + iDst + 1, sizeof(drfs_basepath)); - } - - pBasePaths->count -= 1; - - return DR_TRUE; -} - -static void drfs_basedirs_clear(drfs_basedirs* pBasePaths) -{ - if (pBasePaths == NULL) { - return; - } - - drfs_basedirs_uninit(pBasePaths); - drfs_basedirs_init(pBasePaths); -} - - - -static dr_bool32 drfs_callbacklist_init(drfs_callbacklist* pList) -{ - if (pList == NULL) { - return DR_FALSE; - } - - pList->pBuffer = 0; - pList->count = 0; - - return DR_TRUE; -} - -static void drfs_callbacklist_uninit(drfs_callbacklist* pList) -{ - if (pList == NULL) { - return; - } - - free(pList->pBuffer); -} - -static dr_bool32 drfs_callbacklist_inflate(drfs_callbacklist* pList) -{ - if (pList == NULL) { - return DR_FALSE; - } - - drfs_archive_callbacks* pOldBuffer = pList->pBuffer; - drfs_archive_callbacks* pNewBuffer = (drfs_archive_callbacks*)malloc((pList->count + 1) * sizeof(drfs_archive_callbacks)); - if (pNewBuffer == NULL) { - return DR_FALSE; - } - - for (unsigned int iDst = 0; iDst < pList->count; ++iDst) { - memcpy(pNewBuffer + iDst, pOldBuffer + iDst, sizeof(drfs_archive_callbacks)); - } - - pList->pBuffer = pNewBuffer; - - free(pOldBuffer); - return DR_TRUE; -} - -static dr_bool32 drfs_callbacklist_pushback(drfs_callbacklist* pList, drfs_archive_callbacks callbacks) -{ - if (pList == NULL) { - return DR_FALSE; - } - - if (!drfs_callbacklist_inflate(pList)) { - return DR_FALSE; - } - - pList->pBuffer[pList->count] = callbacks; - pList->count += 1; - - return DR_TRUE; -} - - -struct drfs_archive -{ - // A pointer to the context that owns this archive. - drfs_context* pContext; - - // A pointer to the archive that contains this archive. This can be null in which case it is the top level archive (which is always native). - drfs_archive* pParentArchive; - - // A pointer to the file containing the data of the archive file. - drfs_file* pFile; - - // The internal handle that was returned when the archive was opened by the archive definition. - drfs_handle internalArchiveHandle; - - // Flags. Can be a combination of the following: - // DR_FS_OWNS_PARENT_ARCHIVE - int flags; - - // The callbacks to use when working with on the archive. This contains all of the functions for opening files, reading - // files, etc. - drfs_archive_callbacks callbacks; - - // The absolute, verbose path of the archive. For native archives, this will be the name of the folder on the native file - // system. For non-native archives (zip, etc.) this is the the path of the archive file. - char absolutePath[DRFS_MAX_PATH]; // Change this to char absolutePath[1] and have it sized exactly as needed. -}; - -struct drfs_file -{ - // A pointer to the archive that contains the file. This should never be null. Retrieve a pointer to the contex from this - // by doing pArchive->pContext. The file containing the archive's raw data can be retrieved with pArchive->pFile. - drfs_archive* pArchive; - - // The internal file handle for use by the archive that owns it. - drfs_handle internalFileHandle; - - - // Flags. Can be a combination of the following: - // DR_FS_OWNS_PARENT_ARCHIVE - int flags; - - - // The critical section for locking and unlocking files. -#ifdef _WIN32 -#ifdef DR_FS_WIN32_USE_EVENT_MUTEX - HANDLE lock; -#else - CRITICAL_SECTION lock; -#endif -#else - pthread_mutex_t lock; -#endif -}; - - -//// Path Manipulation //// -// -// Functionality below is taken straight from dr_path, but namespaced as "drfs" to avoid naming conflicts. - -// Structure representing a section of a path. -typedef struct -{ - size_t offset; - size_t length; -} drfs_drpath_segment; - -// Structure used for iterating over a path while at the same time providing useful and easy-to-use information about the iteration. -typedef struct drfs_drpath_iterator -{ - const char* path; - drfs_drpath_segment segment; -} drfs_drpath_iterator; - -static dr_bool32 drfs_drpath_next(drfs_drpath_iterator* i) -{ - if (i == NULL || i->path == NULL) { - return DR_FALSE; - } - - i->segment.offset = i->segment.offset + i->segment.length; - i->segment.length = 0; - - while (i->path[i->segment.offset] != '\0' && (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\')) { - i->segment.offset += 1; - } - - if (i->path[i->segment.offset] == '\0') { - return DR_FALSE; - } - - - while (i->path[i->segment.offset + i->segment.length] != '\0' && (i->path[i->segment.offset + i->segment.length] != '/' && i->path[i->segment.offset + i->segment.length] != '\\')) { - i->segment.length += 1; - } - - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_prev(drfs_drpath_iterator* i) -{ - if (i == NULL || i->path == NULL || i->segment.offset == 0) { - return DR_FALSE; - } - - i->segment.length = 0; - - do - { - i->segment.offset -= 1; - } while (i->segment.offset > 0 && (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\')); - - if (i->segment.offset == 0) { - if (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\') { - i->segment.length = 0; - return DR_TRUE; - } - - return DR_FALSE; - } - - - size_t offsetEnd = i->segment.offset + 1; - while (i->segment.offset > 0 && (i->path[i->segment.offset] != '/' && i->path[i->segment.offset] != '\\')) { - i->segment.offset -= 1; - } - - if (i->path[i->segment.offset] == '/' || i->path[i->segment.offset] == '\\') { - i->segment.offset += 1; - } - - - i->segment.length = offsetEnd - i->segment.offset; - - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_first(const char* path, drfs_drpath_iterator* i) -{ - if (i == 0) return DR_FALSE; - i->path = path; - i->segment.offset = 0; - i->segment.length = 0; - - if (path == 0 || path[0] == '\0') { - return DR_FALSE; - } - - while (i->path[i->segment.length] != '\0' && (i->path[i->segment.length] != '/' && i->path[i->segment.length] != '\\')) { - i->segment.length += 1; - } - - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_last(const char* path, drfs_drpath_iterator* i) -{ - if (i == 0) return DR_FALSE; - i->path = path; - i->segment.offset = 0; - i->segment.length = 0; - - if (path == 0 || path[0] == '\0') { - return DR_FALSE; - } - - i->path = path; - i->segment.offset = strlen(path); - i->segment.length = 0; - - return drfs_drpath_prev(i); -} - -static dr_bool32 drfs_drpath_segments_equal(const char* s0Path, const drfs_drpath_segment s0, const char* s1Path, const drfs_drpath_segment s1) -{ - if (s0Path == NULL || s1Path == NULL) { - return DR_FALSE; - } - - if (s0.length != s1.length) { - return DR_FALSE; - } - - return strncmp(s0Path + s0.offset, s1Path + s1.offset, s0.length) == 0; -} - -static dr_bool32 drfs_drpath_iterators_equal(const drfs_drpath_iterator i0, const drfs_drpath_iterator i1) -{ - return drfs_drpath_segments_equal(i0.path, i0.segment, i1.path, i1.segment); -} - -static dr_bool32 drfs_drpath_is_linux_style_root_segment(const drfs_drpath_iterator i) -{ - if (i.path == NULL) { - return DR_FALSE; - } - - if (i.segment.offset == 0 && i.segment.length == 0) { - return DR_TRUE; // "/" style root. - } - - return DR_FALSE; -} - -static dr_bool32 drfs_drpath_is_win32_style_root_segment(const drfs_drpath_iterator i) -{ - if (i.path == NULL) { - return DR_FALSE; - } - - if (i.segment.offset == 0 && i.segment.length == 2) { - if (((i.path[0] >= 'a' && i.path[0] <= 'z') || (i.path[0] >= 'A' && i.path[0] <= 'Z')) && i.path[1] == ':') { - return DR_TRUE; - } - } - - return DR_FALSE; -} - -static dr_bool32 drfs_drpath_is_root_segment(const drfs_drpath_iterator i) -{ - return drfs_drpath_is_linux_style_root_segment(i) || drfs_drpath_is_win32_style_root_segment(i); -} - -static dr_bool32 drfs_drpath_append_iterator(char* base, size_t baseBufferSizeInBytes, drfs_drpath_iterator i) -{ - if (base == NULL) { - return DR_FALSE; - } - - size_t path1Length = strlen(base); - size_t path2Length = i.segment.length; - - if (path1Length >= baseBufferSizeInBytes) { - return DR_FALSE; - } - - if (drfs_drpath_is_linux_style_root_segment(i)) { - if (baseBufferSizeInBytes > 1) { - base[0] = '/'; - base[1] = '\0'; - return DR_TRUE; - } - } - - - // Slash. - if (path1Length > 0 && base[path1Length - 1] != '/' && base[path1Length - 1] != '\\') { - base[path1Length] = '/'; - path1Length += 1; - } - - // Other part. - if (path1Length + path2Length >= baseBufferSizeInBytes) { - path2Length = baseBufferSizeInBytes - path1Length - 1; // -1 for the null terminator. - } - - drfs__strncpy_s(base + path1Length, baseBufferSizeInBytes - path1Length, i.path + i.segment.offset, path2Length); - - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_is_descendant(const char* descendantAbsolutePath, const char* parentAbsolutePath) -{ - drfs_drpath_iterator iChild; - if (!drfs_drpath_first(descendantAbsolutePath, &iChild)) { - return DR_FALSE; // The descendant is an empty string which makes it impossible for it to be a descendant. - } - - drfs_drpath_iterator iParent; - if (drfs_drpath_first(parentAbsolutePath, &iParent)) - { - do - { - // If the segment is different, the paths are different and thus it is not a descendant. - if (!drfs_drpath_iterators_equal(iParent, iChild)) { - return DR_FALSE; - } - - if (!drfs_drpath_next(&iChild)) { - return DR_FALSE; // The descendant is shorter which means it's impossible for it to be a descendant. - } - - } while (drfs_drpath_next(&iParent)); - } - - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_is_child(const char* childAbsolutePath, const char* parentAbsolutePath) -{ - drfs_drpath_iterator iChild; - if (!drfs_drpath_first(childAbsolutePath, &iChild)) { - return DR_FALSE; // The descendant is an empty string which makes it impossible for it to be a descendant. - } - - drfs_drpath_iterator iParent; - if (drfs_drpath_first(parentAbsolutePath, &iParent)) - { - do - { - // If the segment is different, the paths are different and thus it is not a descendant. - if (!drfs_drpath_iterators_equal(iParent, iChild)) { - return DR_FALSE; - } - - if (!drfs_drpath_next(&iChild)) { - return DR_FALSE; // The descendant is shorter which means it's impossible for it to be a descendant. - } - - } while (drfs_drpath_next(&iParent)); - } - - // At this point we have finished iteration of the parent, which should be shorter one. We now do one more iterations of - // the child to ensure it is indeed a direct child and not a deeper descendant. - return !drfs_drpath_next(&iChild); -} - -static void drfs_drpath_base_path(char* path) -{ - if (path == NULL) { - return; - } - - char* baseend = path; - - // We just loop through the path until we find the last slash. - while (path[0] != '\0') { - if (path[0] == '/' || path[0] == '\\') { - baseend = path; - } - - path += 1; - } - - - // Now we just loop backwards until we hit the first non-slash. - while (baseend > path) { - if (baseend[0] != '/' && baseend[0] != '\\') { - break; - } - - baseend -= 1; - } - - - // We just put a null terminator on the end. - baseend[0] = '\0'; -} - -static void drfs_drpath_copy_base_path(const char* path, char* baseOut, size_t baseSizeInBytes) -{ - if (path == NULL || baseOut == NULL || baseSizeInBytes == 0) { - return; - } - - drfs__strcpy_s(baseOut, baseSizeInBytes, path); - drfs_drpath_base_path(baseOut); -} - -static const char* drfs_drpath_file_name(const char* path) -{ - if (path == NULL) { - return NULL; - } - - const char* fileName = path; - - // We just loop through the path until we find the last slash. - while (path[0] != '\0') { - if (path[0] == '/' || path[0] == '\\') { - fileName = path; - } - - path += 1; - } - - // At this point the file name is sitting on a slash, so just move forward. - while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { - fileName += 1; - } - - return fileName; -} - -static const char* drfs_drpath_extension(const char* path) -{ - if (path == NULL) { - return NULL; - } - - const char* extension = drfs_drpath_file_name(path); - const char* lastoccurance = 0; - - // Just find the last '.' and return. - while (extension[0] != '\0') - { - extension += 1; - - if (extension[0] == '.') { - extension += 1; - lastoccurance = extension; - } - } - - return (lastoccurance != 0) ? lastoccurance : extension; -} - -static dr_bool32 drfs_drpath_equal(const char* path1, const char* path2) -{ - if (path1 == NULL || path2 == NULL) { - return DR_FALSE; - } - - if (path1 == path2 || (path1[0] == '\0' && path2[0] == '\0')) { - return DR_TRUE; // Two empty paths are treated as the same. - } - - drfs_drpath_iterator iPath1; - drfs_drpath_iterator iPath2; - if (drfs_drpath_first(path1, &iPath1) && drfs_drpath_first(path2, &iPath2)) - { - dr_bool32 isPath1Valid; - dr_bool32 isPath2Valid; - - do - { - if (!drfs_drpath_iterators_equal(iPath1, iPath2)) { - return DR_FALSE; - } - - isPath1Valid = drfs_drpath_next(&iPath1); - isPath2Valid = drfs_drpath_next(&iPath2); - - } while (isPath1Valid && isPath2Valid); - - // At this point either iPath1 and/or iPath2 have finished iterating. If both of them are at the end, the two paths are equal. - return isPath1Valid == isPath2Valid && iPath1.path[iPath1.segment.offset] == '\0' && iPath2.path[iPath2.segment.offset] == '\0'; - } - - return DR_FALSE; -} - -static dr_bool32 drfs_drpath_is_relative(const char* path) -{ - if (path == NULL) { - return DR_FALSE; - } - - drfs_drpath_iterator seg; - if (drfs_drpath_first(path, &seg)) { - return !drfs_drpath_is_root_segment(seg); - } - - // We'll get here if the path is empty. We consider this to be a relative path. - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_is_absolute(const char* path) -{ - return !drfs_drpath_is_relative(path); -} - -static dr_bool32 drfs_drpath_append(char* base, size_t baseBufferSizeInBytes, const char* other) -{ - if (base == NULL || other == NULL) { - return DR_FALSE; - } - - size_t path1Length = strlen(base); - size_t path2Length = strlen(other); - - if (path1Length >= baseBufferSizeInBytes) { - return DR_FALSE; - } - - - // Slash. - if (path1Length > 0 && base[path1Length - 1] != '/' && base[path1Length - 1] != '\\') { - base[path1Length] = '/'; - path1Length += 1; - } - - // Other part. - if (path1Length + path2Length >= baseBufferSizeInBytes) { - path2Length = baseBufferSizeInBytes - path1Length - 1; // -1 for the null terminator. - } - - drfs__strncpy_s(base + path1Length, baseBufferSizeInBytes - path1Length, other, path2Length); - - return DR_TRUE; -} - -static dr_bool32 drfs_drpath_copy_and_append(char* dst, size_t dstSizeInBytes, const char* base, const char* other) -{ - if (dst == NULL || dstSizeInBytes == 0) { - return DR_FALSE; - } - - drfs__strcpy_s(dst, dstSizeInBytes, base); - return drfs_drpath_append(dst, dstSizeInBytes, other); -} - -// This function recursively cleans a path which is defined as a chain of iterators. This function works backwards, which means at the time of calling this -// function, each iterator in the chain should be placed at the end of the path. -// -// This does not write the null terminator, nor a leading slash for absolute paths. -static size_t _drfs_drpath_clean_trywrite(drfs_drpath_iterator* iterators, unsigned int iteratorCount, char* pathOut, size_t pathOutSizeInBytes, unsigned int ignoreCounter) -{ - if (iteratorCount == 0) { - return 0; - } - - drfs_drpath_iterator isegment = iterators[iteratorCount - 1]; - - - // If this segment is a ".", we ignore it. If it is a ".." we ignore it and increment "ignoreCount". - int ignoreThisSegment = ignoreCounter > 0 && isegment.segment.length > 0; - - if (isegment.segment.length == 1 && isegment.path[isegment.segment.offset] == '.') - { - // "." - ignoreThisSegment = 1; - } - else - { - if (isegment.segment.length == 2 && isegment.path[isegment.segment.offset] == '.' && isegment.path[isegment.segment.offset + 1] == '.') - { - // ".." - ignoreThisSegment = 1; - ignoreCounter += 1; - } - else - { - // It's a regular segment, so decrement the ignore counter. - if (ignoreCounter > 0) { - ignoreCounter -= 1; - } - } - } - - - // The previous segment needs to be written before we can write this one. - size_t bytesWritten = 0; - - drfs_drpath_iterator prev = isegment; - if (!drfs_drpath_prev(&prev)) - { - if (iteratorCount > 1) - { - iteratorCount -= 1; - prev = iterators[iteratorCount - 1]; - } - else - { - prev.path = NULL; - prev.segment.offset = 0; - prev.segment.length = 0; - } - } - - if (prev.segment.length > 0) - { - iterators[iteratorCount - 1] = prev; - bytesWritten = _drfs_drpath_clean_trywrite(iterators, iteratorCount, pathOut, pathOutSizeInBytes, ignoreCounter); - } - - - if (!ignoreThisSegment) - { - if (pathOutSizeInBytes > 0) - { - pathOut += bytesWritten; - pathOutSizeInBytes -= bytesWritten; - - if (bytesWritten > 0) - { - pathOut[0] = '/'; - bytesWritten += 1; - - pathOut += 1; - pathOutSizeInBytes -= 1; - } - - if (pathOutSizeInBytes >= isegment.segment.length) - { - drfs__strncpy_s(pathOut, pathOutSizeInBytes, isegment.path + isegment.segment.offset, isegment.segment.length); - bytesWritten += isegment.segment.length; - } - else - { - drfs__strncpy_s(pathOut, pathOutSizeInBytes, isegment.path + isegment.segment.offset, pathOutSizeInBytes); - bytesWritten += pathOutSizeInBytes; - } - } - } - - return bytesWritten; -} - -static size_t drfs_drpath_append_and_clean(char* dst, size_t dstSizeInBytes, const char* base, const char* other) -{ - if (base == NULL || other == NULL) { - return 0; - } - - drfs_drpath_iterator last[2]; - dr_bool32 isPathEmpty0 = !drfs_drpath_last(base, last + 0); - dr_bool32 isPathEmpty1 = !drfs_drpath_last(other, last + 1); - - if (isPathEmpty0 && isPathEmpty1) { - return 0; // Both input strings are empty. - } - - size_t bytesWritten = 0; - if (base[0] == '/') { - if (dst != NULL && dstSizeInBytes > 1) { - dst[0] = '/'; - bytesWritten = 1; - } - } - - bytesWritten += _drfs_drpath_clean_trywrite(last, 2, dst + bytesWritten, dstSizeInBytes - bytesWritten - 1, 0); // -1 to ensure there is enough room for a null terminator later on. - if (dstSizeInBytes > bytesWritten) { - dst[bytesWritten] = '\0'; - } - - return bytesWritten + 1; -} - - -//// Private Utiltities //// - -// Recursively creates the given directory structure on the native file system. -static dr_bool32 drfs_mkdir_recursive_native(const char* absolutePath); - -// Determines whether or not the given path is valid for writing based on the base write path and whether or not -// the write guard is enabled. -static dr_bool32 drfs_validate_write_path(drfs_context* pContext, const char* absoluteOrRelativePath, char* absolutePathOut, unsigned int absolutePathOutSize) -{ - // If the path is relative, we need to convert to absolute. Then, if the write directory guard is enabled, we need to check that it's a descendant of the base path. - if (drfs_drpath_is_relative(absoluteOrRelativePath)) { - if (drfs_drpath_append_and_clean(absolutePathOut, absolutePathOutSize, pContext->writeBaseDirectory, absoluteOrRelativePath)) { - absoluteOrRelativePath = absolutePathOut; - } else { - return DR_FALSE; - } - } else { - if (drfs__strcpy_s(absolutePathOut, absolutePathOutSize, absoluteOrRelativePath) != 0) { - return DR_FALSE; - } - } - - // If you trigger this assert it means you're trying to open a file for writing with a relative path but haven't yet - // set the write directory. Either set the write directory with drfs_set_base_write_directory(), or use an absolute - // path to open the file. - assert(drfs_drpath_is_absolute(absoluteOrRelativePath)); - if (!drfs_drpath_is_absolute(absoluteOrRelativePath)) { - return DR_FALSE; - } - - - if (drfs_is_write_directory_guard_enabled(pContext)) { - if (drfs_drpath_is_descendant(absoluteOrRelativePath, pContext->writeBaseDirectory)) { - return DR_TRUE; - } else { - return DR_FALSE; - } - } else { - return DR_TRUE; - } -} - -// A simple helper function for determining the access mode to use for an archive file based on the access mode -// of a file within that archive. -static unsigned int drfs_archive_access_mode(unsigned int fileAccessMode) -{ - return (fileAccessMode == DRFS_READ) ? DRFS_READ : DRFS_READ | DRFS_WRITE | DRFS_EXISTING; -} - - - -//// Platform-Specific Section //// - -// The functions in this section implement a common abstraction for working with files on the native file system. When adding -// support for a new platform you'll probably want to either implement a platform-specific back-end or force stdio. - -#if defined(_WIN32) -#define DR_FS_USE_WIN32 -#else -#define DR_FS_USE_STDIO -#endif - -// Low-level function for opening a file on the native file system. -// -// This will fail if attempting to open a file that's inside an archive such as a zip file. It can only open -// files that are sitting on the native file system. -// -// The given file path must be absolute. -static drfs_result drfs_open_native_file(const char* absolutePath, unsigned int accessMode, drfs_handle* pHandleOut); - -// Closes the given native file. -static void drfs_close_native_file(drfs_handle file); - -// Determines whether or not the given path refers to a directory on the native file system. -static dr_bool32 drfs_is_native_directory(const char* absolutePath); - -// Determines whether or not the given path refers to a file on the native file system. This will return DR_FALSE for directories. -static dr_bool32 drfs_is_native_file(const char* absolutePath); - -// Deletes a native file. -static drfs_result drfs_delete_native_file(const char* absolutePath); - -// Creates a directory on the native file system. -static drfs_result drfs_mkdir_native(const char* absolutePath); - -// Moves or renames a native file. Fails if the target already exists. -static drfs_result drfs_move_native_file(const char* absolutePathOld, const char* absolutePathNew); - -// Creates a copy of a native file. -static drfs_result drfs_copy_native_file(const char* absolutePathSrc, const char* absolutePathDst, dr_bool32 failIfExists); - -// Reads data from the given native file. -static drfs_result drfs_read_native_file(drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut); - -// Writes data to the given native file. -static drfs_result drfs_write_native_file(drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut); - -// Seeks the given native file. -static drfs_result drfs_seek_native_file(drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin); - -// Retrieves the read/write pointer of the given native file. -static dr_uint64 drfs_tell_native_file(drfs_handle file); - -// Retrieves the size of the given native file. -static dr_uint64 drfs_get_native_file_size(drfs_handle file); - -// Flushes the given native file. -static void drfs_flush_native_file(drfs_handle file); - -// Retrieves information about the file OR DIRECTORY at the given path on the native file system. -// -// is allowed to be null, in which case the call is equivalent to simply checking if the file or directory exists. -static drfs_result drfs_get_native_file_info(const char* absolutePath, drfs_file_info* fi); - -// Creates an iterator for iterating over the native files in the given directory. -// -// The iterator will be deleted with drfs_end_native_iteration(). -static drfs_handle drfs_begin_native_iteration(const char* absolutePath); - -// Deletes the iterator that was returned with drfs_end_native_iteration(). -static void drfs_end_native_iteration(drfs_handle iterator); - -// Retrieves information about the next native file based on the given iterator. -static dr_bool32 drfs_next_native_iteration(drfs_handle iterator, drfs_file_info* fi); - - - -#ifdef DR_FS_USE_WIN32 -static drfs_result drfs__GetLastError_to_result() -{ - switch (GetLastError()) - { - case ERROR_SUCCESS: return drfs_success; - case ERROR_FILE_NOT_FOUND: return drfs_does_not_exist; - case ERROR_PATH_NOT_FOUND: return drfs_does_not_exist; - case ERROR_TOO_MANY_OPEN_FILES: return drfs_too_many_open_files; - case ERROR_ACCESS_DENIED: return drfs_permission_denied; - case ERROR_NOT_ENOUGH_MEMORY: return drfs_out_of_memory; - case ERROR_DISK_FULL: return drfs_no_space; - case ERROR_HANDLE_EOF: return drfs_at_end_of_file; - case ERROR_NEGATIVE_SEEK: return drfs_negative_seek; - default: return drfs_unknown_error; - } -} - -static drfs_result drfs_open_native_file(const char* absolutePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(absolutePath != NULL); - assert(pHandleOut != NULL); - - DWORD dwDesiredAccess = 0; - DWORD dwShareMode = 0; - DWORD dwCreationDisposition = OPEN_EXISTING; - - if ((accessMode & DRFS_READ) != 0) { - dwDesiredAccess |= FILE_GENERIC_READ; - dwShareMode |= FILE_SHARE_READ; - } - - if ((accessMode & DRFS_WRITE) != 0) { - dwDesiredAccess |= FILE_GENERIC_WRITE; - - if ((accessMode & DRFS_EXISTING) != 0) { - if ((accessMode & DRFS_TRUNCATE) != 0) { - dwCreationDisposition = TRUNCATE_EXISTING; - } else { - dwCreationDisposition = OPEN_EXISTING; - } - } else { - if ((accessMode & DRFS_TRUNCATE) != 0) { - dwCreationDisposition = CREATE_ALWAYS; - } else { - dwCreationDisposition = OPEN_ALWAYS; - } - } - } - - - HANDLE hFile = CreateFileA(absolutePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - // We failed to create the file, however it may be because we are trying to create the file and the directory structure does not exist yet. In this - // case we want to try creating the directory structure and try again. - if ((accessMode & DRFS_WRITE) != 0 && (accessMode & DRFS_CREATE_DIRS) != 0) - { - char dirAbsolutePath[DRFS_MAX_PATH]; - drfs_drpath_copy_base_path(absolutePath, dirAbsolutePath, sizeof(dirAbsolutePath)); - - if (!drfs_is_native_directory(dirAbsolutePath) && drfs_mkdir_recursive_native(dirAbsolutePath)) { - hFile = CreateFileA(absolutePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - } - } - } - - if (hFile != INVALID_HANDLE_VALUE) { - *pHandleOut = (drfs_handle)hFile; - return drfs_success; - } - - return drfs__GetLastError_to_result(); -} - -static void drfs_close_native_file(drfs_handle file) -{ - CloseHandle((HANDLE)file); -} - -static dr_bool32 drfs_is_native_directory(const char* absolutePath) -{ - DWORD attributes = GetFileAttributesA(absolutePath); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; -} - -static dr_bool32 drfs_is_native_file(const char* absolutePath) -{ - DWORD attributes = GetFileAttributesA(absolutePath); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; -} - -static drfs_result drfs_delete_native_file(const char* absolutePath) -{ - BOOL wasSuccessful; - - DWORD attributes = GetFileAttributesA(absolutePath); - if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - wasSuccessful = DeleteFileA(absolutePath); - } else { - wasSuccessful = RemoveDirectoryA(absolutePath); - } - - if (wasSuccessful) { - return drfs_success; - } - - return drfs__GetLastError_to_result(); -} - -static drfs_result drfs_mkdir_native(const char* absolutePath) -{ - BOOL wasSuccessful = CreateDirectoryA(absolutePath, NULL); - if (wasSuccessful) { - return drfs_success; - } - - return drfs__GetLastError_to_result(); -} - -static drfs_result drfs_move_native_file(const char* absolutePathOld, const char* absolutePathNew) -{ - BOOL wasSuccessful = MoveFileExA(absolutePathOld, absolutePathNew, 0); - if (wasSuccessful) { - return drfs_success; - } - - return drfs__GetLastError_to_result(); -} - -static drfs_result drfs_copy_native_file(const char* absolutePathSrc, const char* absolutePathDst, dr_bool32 failIfExists) -{ - BOOL wasSuccessful = CopyFileA(absolutePathSrc, absolutePathDst, failIfExists); - if (wasSuccessful) { - return drfs_success; - } - - return drfs__GetLastError_to_result(); -} - -static drfs_result drfs_read_native_file(drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - // Unfortunately Win32 expects a DWORD for the number of bytes to read, however we accept size_t. We need to loop to ensure - // we handle data > 4GB correctly. - - size_t totalBytesRead = 0; - - char* pDst = (char*)pDataOut; - dr_uint64 bytesRemaining = bytesToRead; - while (bytesRemaining > 0) - { - DWORD bytesToProcess; - if (bytesRemaining > UINT_MAX) { - bytesToProcess = UINT_MAX; - } else { - bytesToProcess = (DWORD)bytesRemaining; - } - - - DWORD bytesRead; - BOOL wasSuccessful = ReadFile((HANDLE)file, pDst, bytesToProcess, &bytesRead, NULL); - if (!wasSuccessful || bytesRead != bytesToProcess) - { - // We failed to read the chunk. - totalBytesRead += bytesRead; - - if (pBytesReadOut) { - *pBytesReadOut = totalBytesRead; - } - - return drfs__GetLastError_to_result(); - } - - pDst += bytesRead; - bytesRemaining -= bytesRead; - totalBytesRead += bytesRead; - } - - - if (pBytesReadOut != NULL) { - *pBytesReadOut = totalBytesRead; - } - - return drfs_success; -} - -static drfs_result drfs_write_native_file(drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - // Unfortunately Win32 expects a DWORD for the number of bytes to write, however we accept size_t. We need to loop to ensure - // we handle data > 4GB correctly. - - size_t totalBytesWritten = 0; - const char* pSrc = (const char*)pData; - - size_t bytesRemaining = bytesToWrite; - while (bytesRemaining > 0) - { - DWORD bytesToProcess; - if (bytesRemaining > UINT_MAX) { - bytesToProcess = UINT_MAX; - } else { - bytesToProcess = (DWORD)bytesRemaining; - } - - DWORD bytesWritten; - BOOL wasSuccessful = WriteFile((HANDLE)file, pSrc, bytesToProcess, &bytesWritten, NULL); - if (!wasSuccessful || bytesWritten != bytesToProcess) - { - // We failed to write the chunk. - totalBytesWritten += bytesWritten; - - if (pBytesWrittenOut) { - *pBytesWrittenOut = totalBytesWritten; - } - - return drfs__GetLastError_to_result(); - } - - pSrc += bytesWritten; - bytesRemaining -= bytesWritten; - totalBytesWritten += bytesWritten; - } - - if (pBytesWrittenOut) { - *pBytesWrittenOut = totalBytesWritten; - } - - return drfs_success;; -} - -static drfs_result drfs_seek_native_file(drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - LARGE_INTEGER lNewFilePointer; - LARGE_INTEGER lDistanceToMove; - lDistanceToMove.QuadPart = bytesToSeek; - - DWORD dwMoveMethod = FILE_CURRENT; - if (origin == drfs_origin_start) { - dwMoveMethod = FILE_BEGIN; - } else if (origin == drfs_origin_end) { - dwMoveMethod = FILE_END; - } - - BOOL wasSuccessful = SetFilePointerEx((HANDLE)file, lDistanceToMove, &lNewFilePointer, dwMoveMethod); - if (!wasSuccessful) { - return drfs__GetLastError_to_result(); - } - - return drfs_success; -} - -static dr_uint64 drfs_tell_native_file(drfs_handle file) -{ - LARGE_INTEGER lNewFilePointer; - LARGE_INTEGER lDistanceToMove; - lDistanceToMove.QuadPart = 0; - - if (SetFilePointerEx((HANDLE)file, lDistanceToMove, &lNewFilePointer, FILE_CURRENT)) { - return (dr_uint64)lNewFilePointer.QuadPart; - } - - return 0; -} - -static dr_uint64 drfs_get_native_file_size(drfs_handle file) -{ - LARGE_INTEGER fileSize; - if (GetFileSizeEx((HANDLE)file, &fileSize)) { - return (dr_uint64)fileSize.QuadPart; - } - - return 0; -} - -static void drfs_flush_native_file(drfs_handle file) -{ - FlushFileBuffers((HANDLE)file); -} - -static drfs_result drfs_get_native_file_info(const char* absolutePath, drfs_file_info* fi) -{ - assert(absolutePath != NULL); - - // is allowed to be null, in which case the call is equivalent to simply checking if the file exists. - if (fi == NULL) { - if (GetFileAttributesA(absolutePath) != INVALID_FILE_ATTRIBUTES) { - return drfs_success; - } - - return drfs_does_not_exist; - } - - WIN32_FILE_ATTRIBUTE_DATA fad; - if (GetFileAttributesExA(absolutePath, GetFileExInfoStandard, &fad)) - { - ULARGE_INTEGER liSize; - liSize.LowPart = fad.nFileSizeLow; - liSize.HighPart = fad.nFileSizeHigh; - - ULARGE_INTEGER liTime; - liTime.LowPart = fad.ftLastWriteTime.dwLowDateTime; - liTime.HighPart = fad.ftLastWriteTime.dwHighDateTime; - - strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), absolutePath); - fi->sizeInBytes = liSize.QuadPart; - fi->lastModifiedTime = liTime.QuadPart; - - fi->attributes = 0; - if ((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_DIRECTORY; - } - if ((fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_READONLY; - } - - return drfs_success; - } - - return drfs__GetLastError_to_result(); -} - -typedef struct -{ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - char directoryPath[1]; -} drfs_iterator_win32; - -static drfs_handle drfs_begin_native_iteration(const char* absolutePath) -{ - assert(drfs_drpath_is_absolute(absolutePath)); - - char searchQuery[DRFS_MAX_PATH]; - if (strcpy_s(searchQuery, sizeof(searchQuery), absolutePath) != 0) { - return NULL; - } - - unsigned int searchQueryLength = (unsigned int)strlen(searchQuery); - if (searchQueryLength >= DRFS_MAX_PATH - 3) { - return NULL; // Path is too long. - } - - searchQuery[searchQueryLength + 0] = '\\'; - searchQuery[searchQueryLength + 1] = '*'; - searchQuery[searchQueryLength + 2] = '\0'; - - drfs_iterator_win32* pIterator = (drfs_iterator_win32*)malloc(sizeof(*pIterator) + searchQueryLength); - if (pIterator == NULL) { - return NULL; - } - - ZeroMemory(pIterator, sizeof(*pIterator)); - - pIterator->hFind = FindFirstFileA(searchQuery, &pIterator->ffd); - if (pIterator->hFind == INVALID_HANDLE_VALUE) { - free(pIterator); - return NULL; // Failed to begin search. - } - - strcpy_s(pIterator->directoryPath, searchQueryLength + 1, absolutePath); // This won't fail in practice. - return (drfs_handle)pIterator; -} - -static void drfs_end_native_iteration(drfs_handle iterator) -{ - drfs_iterator_win32* pIterator = (drfs_iterator_win32*)iterator; - assert(pIterator != NULL); - - if (pIterator->hFind) { - FindClose(pIterator->hFind); - } - - free(pIterator); -} - -static dr_bool32 drfs_next_native_iteration(drfs_handle iterator, drfs_file_info* fi) -{ - drfs_iterator_win32* pIterator = (drfs_iterator_win32*)iterator; - assert(pIterator != NULL); - - if (pIterator->hFind != INVALID_HANDLE_VALUE && pIterator->hFind != NULL) - { - // Skip past "." and ".." directories. - while (strcmp(pIterator->ffd.cFileName, ".") == 0 || strcmp(pIterator->ffd.cFileName, "..") == 0) { - if (FindNextFileA(pIterator->hFind, &pIterator->ffd) == 0) { - return DR_FALSE; - } - } - - if (fi != NULL) - { - // The absolute path actually needs to be set to the relative path. The higher level APIs are the once responsible for translating - // it back to an absolute path. - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), pIterator->ffd.cFileName); - - ULARGE_INTEGER liSize; - liSize.LowPart = pIterator->ffd.nFileSizeLow; - liSize.HighPart = pIterator->ffd.nFileSizeHigh; - fi->sizeInBytes = liSize.QuadPart; - - ULARGE_INTEGER liTime; - liTime.LowPart = pIterator->ffd.ftLastWriteTime.dwLowDateTime; - liTime.HighPart = pIterator->ffd.ftLastWriteTime.dwHighDateTime; - fi->lastModifiedTime = liTime.QuadPart; - - fi->attributes = 0; - if ((pIterator->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_DIRECTORY; - } - if ((pIterator->ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_READONLY; - } - } - - if (!FindNextFileA(pIterator->hFind, &pIterator->ffd)) { - FindClose(pIterator->hFind); - pIterator->hFind = NULL; - } - - return DR_TRUE; - } - - return DR_FALSE; -} -#endif //DR_FS_USE_WIN32 - - -#ifdef DR_FS_USE_STDIO -#include -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#endif - -#define DRFS_HANDLE_TO_FD(file) ((int)((size_t)file) - 1) -#define DRFS_FD_TO_HANDLE(fd) ((drfs_handle)(size_t)(fd + 1)) - -static drfs_result drfs__errno_to_result() -{ - switch (errno) - { - case EACCES: return drfs_permission_denied; - case EEXIST: return drfs_already_exists; - case EISDIR: return drfs_permission_denied; - case EMFILE: return drfs_too_many_open_files; - case ENFILE: return drfs_too_many_open_files; - case ENAMETOOLONG: return drfs_path_too_long; - case ENOENT: return drfs_does_not_exist; - case ENOMEM: return drfs_out_of_memory; - case ENOSPC: return drfs_no_space; - case ENOTDIR: return drfs_not_directory; - case EOVERFLOW: return drfs_too_large; - case EROFS: return drfs_permission_denied; - case ETXTBSY: return drfs_permission_denied; - case EBADF: return drfs_invalid_args; - case EINVAL: return drfs_invalid_args; - default: return drfs_unknown_error; - } -} - -static int drfs__open_fd(const char* absolutePath, int flags) -{ - return open64(absolutePath, flags, 0666); -} - -static int drfs__stat64(const char* filename, struct stat64* st) -{ - return stat64(filename, st); -} - -static int drfs__fstat64(int fd, struct stat64* st) -{ - return fstat64(fd, st); -} - -static int drfs__mode_is_dir(int mode) -{ - return S_ISDIR(mode); -} - -static int drfs__mode_has_write_permission(int mode) -{ - return (mode & S_IWUSR) != 0; -} - - -static drfs_result drfs_open_native_file(const char* absolutePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(absolutePath != NULL); - assert(pHandleOut != NULL); - - *pHandleOut = NULL; - - int flags = 0; - if ((accessMode & DRFS_READ) != 0) { - if ((accessMode & DRFS_WRITE) != 0) { - flags = O_RDWR; - } else { - flags = O_RDONLY; - } - } else { - if ((accessMode & DRFS_WRITE) != 0) { - flags = O_WRONLY; - } else { - return drfs_permission_denied; // Neither read nor write mode was specified. - } - } - - if ((accessMode & DRFS_TRUNCATE) != 0) { - flags |= O_TRUNC; - } - - if ((accessMode & DRFS_EXISTING) == 0) { - flags |= O_CREAT; - } - - int fd = drfs__open_fd(absolutePath, flags); - if (fd == -1) - { - // We failed to open the file, however it could be because the directory structure is not in place. We need to check - // the access mode flags for DRFS_CREATE_DIRS and try creating the directory structure. - if ((accessMode & DRFS_WRITE) != 0 && (accessMode & DRFS_CREATE_DIRS) != 0) - { - char dirAbsolutePath[DRFS_MAX_PATH]; - drfs_drpath_copy_base_path(absolutePath, dirAbsolutePath, sizeof(dirAbsolutePath)); - - if (!drfs_is_native_directory(dirAbsolutePath) && drfs_mkdir_recursive_native(dirAbsolutePath)) { - fd = drfs__open_fd(absolutePath, flags); - } - } - } - - if (fd == -1) { - return drfs__errno_to_result(); - } - - *pHandleOut = DRFS_FD_TO_HANDLE(fd); - return drfs_success; -} - -static void drfs_close_native_file(drfs_handle file) -{ - close(DRFS_HANDLE_TO_FD(file)); -} - -static dr_bool32 drfs_is_native_directory(const char* absolutePath) -{ - struct stat64 info; - if (drfs__stat64(absolutePath, &info) != 0) { - return DR_FALSE; // Likely the folder doesn't exist. - } - - return drfs__mode_is_dir(info.st_mode); // Only return DR_TRUE if it's a directory. Return DR_FALSE if it's a file. -} - -static dr_bool32 drfs_is_native_file(const char* absolutePath) -{ - struct stat64 info; - if (drfs__stat64(absolutePath, &info) != 0) { - return DR_FALSE; // Likely the folder doesn't exist. - } - - return !drfs__mode_is_dir(info.st_mode); // Only return DR_TRUE if it's a file. Return DR_FALSE if it's a directory. -} - -static drfs_result drfs_delete_native_file(const char* absolutePath) -{ - if (remove(absolutePath) == 0) { - return drfs_success; - } - - return drfs__errno_to_result(); -} - -static drfs_result drfs_move_native_file(const char* absolutePathOld, const char* absolutePathNew) -{ - if (rename(absolutePathOld, absolutePathNew) == 0) { - return drfs_success; - } - - return drfs__errno_to_result(); -} - -static drfs_result drfs_mkdir_native(const char* absolutePath) -{ - if (mkdir(absolutePath, 0777) == 0) { - return drfs_success; - } - - return drfs__errno_to_result(); -} - -static drfs_result drfs_copy_native_file(const char* absolutePathSrc, const char* absolutePathDst, dr_bool32 failIfExists) -{ - if (drfs_drpath_equal(absolutePathSrc, absolutePathDst)) { - if (!failIfExists) { - return drfs_success; - } else { - return drfs_already_exists; - } - } - - int fdSrc = drfs__open_fd(absolutePathSrc, O_RDONLY); - if (fdSrc == -1) { - return drfs__errno_to_result(); - } - - int fdDst = drfs__open_fd(absolutePathDst, O_WRONLY | O_TRUNC | O_CREAT | ((failIfExists) ? O_EXCL : 0)); - if (fdDst == -1) { - close(fdSrc); - return drfs__errno_to_result(); - } - - drfs_result result = drfs_success; - - struct stat64 info; - if (drfs__fstat64(fdSrc, &info) == 0) - { -#ifdef __linux__ - ssize_t bytesRemaining = info.st_size; - while (bytesRemaining > 0) { - ssize_t bytesCopied = sendfile(fdDst, fdSrc, NULL, bytesRemaining); - if (bytesCopied == -1) { - result = drfs__errno_to_result(); - break; - } - - bytesRemaining -= bytesCopied; - } -#else - char buffer[BUFSIZ]; - int bytesRead; - while ((bytesRead = read(fdSrc, buffer, sizeof(buffer))) > 0) { - if (write(fdDst, buffer, bytesRead) != bytesRead) { - result = drfs__errno_to_result(); - break; - } - } -#endif - } - else - { - result = drfs__errno_to_result(); - } - - close(fdDst); - close(fdSrc); - - // Permissions. - chmod(absolutePathDst, info.st_mode & 07777); - - return result; -} - -static drfs_result drfs_read_native_file(drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - // The documentation for read() states that if the number of bytes being read (bytesToRead) is larger than SSIZE_MAX, - // the result is unspecified. We'll make things a bit more robust by explicitly checking for this and handling it. - char* pDataOut8 = (char*)pDataOut; - drfs_result result = drfs_success; - - size_t totalBytesRead = 0; - while (bytesToRead > 0) - { - ssize_t bytesRead = read(DRFS_HANDLE_TO_FD(file), pDataOut8 + totalBytesRead, (bytesToRead > SSIZE_MAX) ? SSIZE_MAX : bytesToRead); - if (bytesRead == -1) { - result = drfs__errno_to_result(); - break; - } - - if (bytesRead == 0) { - break; // Reached the end. - } - - totalBytesRead += bytesRead; - bytesToRead -= bytesRead; - } - - if (pBytesReadOut) { - *pBytesReadOut = totalBytesRead; - } - - return result; -} - -static drfs_result drfs_write_native_file(drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - // We want to handle writes in the same way as we do reads due to the return valid being signed. - const char* pDataIn8 = (const char*)pData; - drfs_result result = drfs_success; - - size_t totalBytesWritten = 0; - while (bytesToWrite > 0) - { - ssize_t bytesWritten = write(DRFS_HANDLE_TO_FD(file), pDataIn8 + totalBytesWritten, (bytesToWrite > SSIZE_MAX) ? SSIZE_MAX : bytesToWrite); - if (bytesWritten == -1) { - result = drfs__errno_to_result(); - break; - } - - if (bytesWritten == 0) { - result = drfs__errno_to_result(); - break; - } - - totalBytesWritten += bytesWritten; - bytesToWrite -= bytesWritten; - } - - if (pBytesWrittenOut != NULL) { - *pBytesWrittenOut = totalBytesWritten; - } - - return result; -} - -static drfs_result drfs_seek_native_file(drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - int stdioOrigin = SEEK_CUR; - if (origin == drfs_origin_start) { - stdioOrigin = SEEK_SET; - } else if (origin == drfs_origin_end) { - stdioOrigin = SEEK_END; - } - - if (lseek64(DRFS_HANDLE_TO_FD(file), bytesToSeek, stdioOrigin) == -1) { - return drfs__errno_to_result(); - } - - return drfs_success; -} - -static dr_uint64 drfs_tell_native_file(drfs_handle file) -{ - return lseek64(DRFS_HANDLE_TO_FD(file), 0, SEEK_CUR); -} - -static dr_uint64 drfs_get_native_file_size(drfs_handle file) -{ - struct stat64 info; - if (drfs__fstat64(DRFS_HANDLE_TO_FD(file), &info) != 0) { - return 0; - } - - return info.st_size; -} - -static void drfs_flush_native_file(drfs_handle file) -{ - // The posix implementation does not require flushing. - (void)file; -} - -static drfs_result drfs_get_native_file_info(const char* absolutePath, drfs_file_info* fi) -{ - assert(absolutePath != NULL); - - struct stat64 info; - if (stat64(absolutePath, &info) != 0) { - return drfs__errno_to_result(); - } - - // is allowed to be null, in which case the call is equivalent to simply checking if the file exists. - if (fi != NULL) - { - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), absolutePath); - fi->sizeInBytes = info.st_size; - fi->lastModifiedTime = info.st_mtime; - - fi->attributes = 0; - if (drfs__mode_is_dir(info.st_mode)) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_DIRECTORY; - } - if (drfs__mode_has_write_permission(info.st_mode) == DR_FALSE) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_READONLY; - } - } - - return drfs_success; -} - -typedef struct -{ - DIR* dir; - char directoryPath[1]; -} drfs_iterator_posix; - -static drfs_handle drfs_begin_native_iteration(const char* absolutePath) -{ - DIR* dir = opendir(absolutePath); - if (dir == NULL) { - return NULL; - } - - drfs_iterator_posix* pIterator = (drfs_iterator_posix*)malloc(sizeof(drfs_iterator_posix) + strlen(absolutePath)); - if (pIterator == NULL) { - return NULL; - } - - pIterator->dir = dir; - drfs__strcpy_s(pIterator->directoryPath, strlen(absolutePath) + 1, absolutePath); - - return pIterator; -} - -static void drfs_end_native_iteration(drfs_handle iterator) -{ - drfs_iterator_posix* pIterator = (drfs_iterator_posix*)iterator; - if (pIterator == NULL) { - return; - } - - closedir(pIterator->dir); - free(pIterator); -} - -static dr_bool32 drfs_next_native_iteration(drfs_handle iterator, drfs_file_info* fi) -{ - drfs_iterator_posix* pIterator = (drfs_iterator_posix*)iterator; - if (pIterator == NULL || pIterator->dir == NULL) { - return DR_FALSE; - } - - struct dirent* info = readdir(pIterator->dir); - if (info == NULL) { - return DR_FALSE; - } - - // Skip over "." and ".." folders. - while (strcmp(info->d_name, ".") == 0 || strcmp(info->d_name, "..") == 0) { - info = readdir(pIterator->dir); - if (info == NULL) { - return DR_FALSE; - } - } - - char fileAbsolutePath[DRFS_MAX_PATH]; - drfs_drpath_copy_and_append(fileAbsolutePath, sizeof(fileAbsolutePath), pIterator->directoryPath, info->d_name); - - if (drfs_get_native_file_info(fileAbsolutePath, fi)) { - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), info->d_name); - } - - return DR_TRUE; -} -#endif //DR_FS_USE_STDIO - - -static dr_bool32 drfs_mkdir_recursive_native(const char* absolutePath) -{ - char runningPath[DRFS_MAX_PATH]; - runningPath[0] = '\0'; - - drfs_drpath_iterator iPathSeg; - if (!drfs_drpath_first(absolutePath, &iPathSeg)) { - return DR_FALSE; - } - - // Never check the first segment because we can assume it always exists - it will always be the drive root. - if (drfs_drpath_append_iterator(runningPath, sizeof(runningPath), iPathSeg)) - { - // Loop over every directory until we find one that does not exist. - while (drfs_drpath_next(&iPathSeg)) - { - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), iPathSeg)) { - return DR_FALSE; - } - - if (!drfs_is_native_directory(runningPath)) { - if (drfs_mkdir_native(runningPath) != drfs_success) { - return DR_FALSE; - } - - break; - } - } - - - // At this point all we need to do is create the remaining directories - we can assert that the directory does not exist - // rather than actually checking it which should be a bit more efficient. - while (drfs_drpath_next(&iPathSeg)) - { - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), iPathSeg)) { - return DR_FALSE; - } - - assert(!drfs_is_native_directory(runningPath)); - - if (drfs_mkdir_native(runningPath) != drfs_success) { - return DR_FALSE; - } - } - - return DR_TRUE; - } - - return DR_FALSE; -} - - - -//// Native Archive Implementation //// - -typedef struct -{ - // The access mode. - unsigned int accessMode; - - // The absolute path of the directory. - char absolutePath[1]; - -} drfs_archive_native; - -static drfs_result drfs_open_archive__native(drfs_file* pArchiveFile, unsigned int accessMode, drfs_handle* pHandleOut) -{ - (void)pArchiveFile; - (void)accessMode; - - // This function should never be called for native archives. Native archives are a special case because they are just directories - // on the file system rather than actual files, and as such they are handled just slightly differently. This function is only - // included here for this assert so we can ensure we don't incorrectly call this function. - assert(DR_FALSE); - - *pHandleOut = NULL; - return drfs_unknown_error; -} - -static drfs_result drfs_open_archive__native__special(const char* absolutePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(absolutePath != NULL); // There is no notion of a file for native archives (which are just directories on the file system). - assert(pHandleOut != NULL); - - *pHandleOut = NULL; - - size_t absolutePathLen = strlen(absolutePath); - - drfs_archive_native* pNativeArchive = (drfs_archive_native*)malloc(sizeof(*pNativeArchive) + absolutePathLen + 1); - if (pNativeArchive == NULL) { - return drfs_out_of_memory; - } - - drfs__strcpy_s(pNativeArchive->absolutePath, absolutePathLen + 1, absolutePath); - pNativeArchive->accessMode = accessMode; - - *pHandleOut = (drfs_handle)pNativeArchive; - return drfs_success; -} - -static void drfs_close_archive__native(drfs_handle archive) -{ - // Nothing to do except free the object. - free(archive); -} - -static drfs_result drfs_get_file_info__native(drfs_handle archive, const char* relativePath, drfs_file_info* fi) -{ - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePath[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePath, sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) { - return drfs_path_too_long; - } - - if (fi != NULL) { - memset(fi, 0, sizeof(*fi)); - } - - return drfs_get_native_file_info(absolutePath, fi); -} - -static drfs_handle drfs_begin_iteration__native(drfs_handle archive, const char* relativePath) -{ - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePath[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePath, sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) { - return NULL; - } - - return drfs_begin_native_iteration(absolutePath); -} - -static void drfs_end_iteration__native(drfs_handle archive, drfs_handle iterator) -{ - (void)archive; - assert(archive != NULL); - assert(iterator != NULL); - - drfs_end_native_iteration(iterator); -} - -static dr_bool32 drfs_next_iteration__native(drfs_handle archive, drfs_handle iterator, drfs_file_info* fi) -{ - (void)archive; - assert(archive != NULL); - assert(iterator != NULL); - - return drfs_next_native_iteration(iterator, fi); -} - -static drfs_result drfs_delete_file__native(drfs_handle archive, const char* relativePath) -{ - assert(relativePath != NULL); - - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePath[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePath, sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) { - return drfs_path_too_long; - } - - return drfs_delete_native_file(absolutePath); -} - -static drfs_result drfs_move_file__native(drfs_handle archive, const char* relativePathOld, const char* relativePathNew) -{ - assert(relativePathOld != NULL); - assert(relativePathNew != NULL); - - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePathOld[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePathOld, sizeof(absolutePathOld), pNativeArchive->absolutePath, relativePathOld)) { - return drfs_path_too_long; - } - - char absolutePathNew[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePathNew, sizeof(absolutePathNew), pNativeArchive->absolutePath, relativePathNew)) { - return drfs_path_too_long; - } - - return drfs_move_native_file(absolutePathOld, absolutePathNew); -} - -static drfs_result drfs_create_directory__native(drfs_handle archive, const char* relativePath) -{ - assert(relativePath != NULL); - - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePath[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePath, sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) { - return drfs_path_too_long; - } - - return drfs_mkdir_native(absolutePath); -} - -static drfs_result drfs_copy_file__native(drfs_handle archive, const char* relativePathSrc, const char* relativePathDst, dr_bool32 failIfExists) -{ - assert(relativePathSrc != NULL); - assert(relativePathDst != NULL); - - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePathSrc[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePathSrc, sizeof(absolutePathSrc), pNativeArchive->absolutePath, relativePathSrc)) { - return drfs_path_too_long; - } - - char absolutePathDst[DRFS_MAX_PATH]; - if (!drfs_drpath_copy_and_append(absolutePathDst, sizeof(absolutePathDst), pNativeArchive->absolutePath, relativePathDst)) { - return drfs_path_too_long; - } - - return drfs_copy_native_file(absolutePathSrc, absolutePathDst, failIfExists); -} - -static drfs_result drfs_open_file__native(drfs_handle archive, const char* relativePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(archive != NULL); - assert(relativePath != NULL); - - drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive; - assert(pNativeArchive != NULL); - - char absolutePath[DRFS_MAX_PATH]; - if (drfs_drpath_copy_and_append(absolutePath, sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) { - return drfs_open_native_file(absolutePath, accessMode, pHandleOut); - } - - return drfs_path_too_long; -} - -static void drfs_close_file__native(drfs_handle archive, drfs_handle file) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - drfs_close_native_file(file); -} - -static drfs_result drfs_read_file__native(drfs_handle archive, drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - return drfs_read_native_file(file, pDataOut, bytesToRead, pBytesReadOut); -} - -static drfs_result drfs_write_file__native(drfs_handle archive, drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - return drfs_write_native_file(file, pData, bytesToWrite, pBytesWrittenOut); -} - -static drfs_result drfs_seek_file__native(drfs_handle archive, drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - return drfs_seek_native_file(file, bytesToSeek, origin); -} - -static dr_uint64 drfs_tell_file__native(drfs_handle archive, drfs_handle file) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - return drfs_tell_native_file(file); -} - -static dr_uint64 drfs_file_size__native(drfs_handle archive, drfs_handle file) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - return drfs_get_native_file_size(file); -} - -static void drfs_flush__native(drfs_handle archive, drfs_handle file) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - - drfs_flush_native_file(file); -} - - -// Finds the back-end callbacks by the given extension. -static dr_bool32 drfs_find_backend_by_extension(drfs_context* pContext, const char* extension, drfs_archive_callbacks* pCallbacksOut) -{ - if (pContext == NULL || extension == NULL || extension[0] == '\0') { - return DR_FALSE; - } - - for (unsigned int i = 0; i < pContext->archiveCallbacks.count; ++i) - { - if (pContext->archiveCallbacks.pBuffer[i].is_valid_extension) { - if (pContext->archiveCallbacks.pBuffer[i].is_valid_extension(extension)) { - if (pCallbacksOut) { - *pCallbacksOut = pContext->archiveCallbacks.pBuffer[i]; - } - return DR_TRUE; - } - } - } - - return DR_FALSE; -} - -// Recursively claims ownership of parent archives so that when the child archive is deleted, so are it's parents. -static void drfs_recursively_claim_ownership_or_parent_archive(drfs_archive* pArchive) -{ - if (pArchive == NULL) { - return; - } - - pArchive->flags |= DR_FS_OWNS_PARENT_ARCHIVE; - drfs_recursively_claim_ownership_or_parent_archive(pArchive->pParentArchive); -} - -// Opens a native archive. -static drfs_result drfs_open_native_archive(drfs_context* pContext, const char* absolutePath, unsigned int accessMode, drfs_archive** ppArchive) -{ - assert(pContext != NULL); - assert(ppArchive != NULL); - assert(absolutePath != NULL); - - *ppArchive = NULL; - - drfs_handle internalArchiveHandle; - drfs_result result = drfs_open_archive__native__special(absolutePath, accessMode, &internalArchiveHandle); - if (result != drfs_success) { - return result; - } - - drfs_archive* pArchive = (drfs_archive*)malloc(sizeof(*pArchive)); - if (pArchive == NULL) { - drfs_close_archive__native(internalArchiveHandle); - return drfs_out_of_memory; - } - - pArchive->pContext = pContext; - pArchive->pParentArchive = NULL; - pArchive->pFile = NULL; - pArchive->internalArchiveHandle = internalArchiveHandle; - pArchive->flags = 0; - pArchive->callbacks.is_valid_extension = NULL; - pArchive->callbacks.open_archive = drfs_open_archive__native; - pArchive->callbacks.close_archive = drfs_close_archive__native; - pArchive->callbacks.get_file_info = drfs_get_file_info__native; - pArchive->callbacks.begin_iteration = drfs_begin_iteration__native; - pArchive->callbacks.end_iteration = drfs_end_iteration__native; - pArchive->callbacks.next_iteration = drfs_next_iteration__native; - pArchive->callbacks.delete_file = drfs_delete_file__native; - pArchive->callbacks.create_directory = drfs_create_directory__native; - pArchive->callbacks.move_file = drfs_move_file__native; - pArchive->callbacks.copy_file = drfs_copy_file__native; - pArchive->callbacks.open_file = drfs_open_file__native; - pArchive->callbacks.close_file = drfs_close_file__native; - pArchive->callbacks.read_file = drfs_read_file__native; - pArchive->callbacks.write_file = drfs_write_file__native; - pArchive->callbacks.seek_file = drfs_seek_file__native; - pArchive->callbacks.tell_file = drfs_tell_file__native; - pArchive->callbacks.file_size = drfs_file_size__native; - pArchive->callbacks.flush_file = drfs_flush__native; - drfs__strcpy_s(pArchive->absolutePath, sizeof(pArchive->absolutePath), absolutePath); - - *ppArchive = pArchive; - return drfs_success; -} - -// Opens an archive from a file and callbacks. -static drfs_result drfs_open_non_native_archive(drfs_archive* pParentArchive, drfs_file* pArchiveFile, drfs_archive_callbacks* pBackEndCallbacks, const char* relativePath, unsigned int accessMode, drfs_archive** ppArchiveOut) -{ - assert(pParentArchive != NULL); - assert(pArchiveFile != NULL); - assert(pBackEndCallbacks != NULL); - assert(ppArchiveOut != NULL); - - *ppArchiveOut = NULL; - - if (pBackEndCallbacks->open_archive == NULL) { - return drfs_no_backend; - } - - drfs_handle internalArchiveHandle; - drfs_result result = pBackEndCallbacks->open_archive(pArchiveFile, accessMode, &internalArchiveHandle); - if (result != drfs_success) { - return result; - } - - drfs_archive* pArchive = (drfs_archive*)malloc(sizeof(*pArchive)); - if (pArchive == NULL) { - pBackEndCallbacks->close_archive(internalArchiveHandle); - return drfs_out_of_memory; - } - - pArchive->pContext = pParentArchive->pContext; - pArchive->pParentArchive = pParentArchive; - pArchive->pFile = pArchiveFile; - pArchive->internalArchiveHandle = internalArchiveHandle; - pArchive->flags = 0; - pArchive->callbacks = *pBackEndCallbacks; - drfs_drpath_copy_and_append(pArchive->absolutePath, sizeof(pArchive->absolutePath), pParentArchive->absolutePath, relativePath); - - *ppArchiveOut = pArchive; - return drfs_success; -} - -// Attempts to open an archive from another archive. -static drfs_result drfs_open_non_native_archive_from_path(drfs_archive* pParentArchive, const char* relativePath, unsigned int accessMode, drfs_archive** ppArchiveOut) -{ - assert(pParentArchive != NULL); - assert(ppArchiveOut != NULL); - assert(relativePath != NULL); - - *ppArchiveOut = NULL; - - drfs_archive_callbacks backendCallbacks; - if (!drfs_find_backend_by_extension(pParentArchive->pContext, drfs_drpath_extension(relativePath), &backendCallbacks)) { - return drfs_no_backend; - } - - drfs_file* pArchiveFile; - drfs_result result = drfs_open_file_from_archive(pParentArchive, relativePath, accessMode, &pArchiveFile); - if (result != drfs_success) { - return result; - } - - drfs_archive* pArchive; - result = drfs_open_non_native_archive(pParentArchive, pArchiveFile, &backendCallbacks, relativePath, accessMode, &pArchive); - if (pArchive == NULL) { - return result; - } - - *ppArchiveOut = pArchive; - return drfs_success; -} - - -// Recursively opens the archive that owns the file at the given verbose path. -static drfs_result drfs_open_owner_archive_recursively_from_verbose_path(drfs_archive* pParentArchive, const char* relativePath, unsigned int accessMode, char* relativePathOut, size_t relativePathOutSize, drfs_archive** ppArchiveOut) -{ - assert(pParentArchive != NULL); - assert(relativePath != NULL); - assert(ppArchiveOut != NULL); - - *ppArchiveOut = NULL; - - if (pParentArchive->callbacks.get_file_info == NULL) { - return drfs_no_backend; - } - - drfs_file_info fi; - if (pParentArchive->callbacks.get_file_info(pParentArchive->internalArchiveHandle, relativePath, &fi) == drfs_success) - { - // The file is in this archive. - drfs__strcpy_s(relativePathOut, relativePathOutSize, relativePath); - *ppArchiveOut = pParentArchive; - return drfs_success; - } - else - { - char runningPath[DRFS_MAX_PATH]; - runningPath[0] = '\0'; - - drfs_drpath_iterator segment; - if (drfs_drpath_first(relativePath, &segment)) - { - do - { - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), segment)) { - return drfs_path_too_long; - } - - if (pParentArchive->callbacks.get_file_info(pParentArchive->internalArchiveHandle, runningPath, &fi) == drfs_success) - { - if ((fi.attributes & DRFS_FILE_ATTRIBUTE_DIRECTORY) == 0) - { - // The running path points to an actual file. It could be a sub-archive. - drfs_archive_callbacks backendCallbacks; - if (drfs_find_backend_by_extension(pParentArchive->pContext, drfs_drpath_extension(runningPath), &backendCallbacks)) - { - drfs_file* pNextArchiveFile; - drfs_open_file_from_archive(pParentArchive, runningPath, accessMode, &pNextArchiveFile); - if (pNextArchiveFile == NULL) { - break; // Failed to open the archive file. - } - - drfs_archive* pNextArchive; - drfs_open_non_native_archive(pParentArchive, pNextArchiveFile, &backendCallbacks, runningPath, accessMode, &pNextArchive); - if (pNextArchive == NULL) { - drfs_close(pNextArchiveFile); - break; - } - - // At this point we should have an archive. We now need to call this function recursively if there are any segments left. - drfs_drpath_iterator nextsegment = segment; - if (drfs_drpath_next(&nextsegment)) - { - drfs_archive* pOwnerArchive; - drfs_open_owner_archive_recursively_from_verbose_path(pNextArchive, nextsegment.path + nextsegment.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive); - if (pOwnerArchive == NULL) { - drfs_close_archive(pNextArchive); - break; - } - - *ppArchiveOut = pOwnerArchive; - return drfs_success; - } - else - { - // We reached the end of the path. If we get here it means the file doesn't exist, because otherwise we would have caught it in the check right at the top. - drfs_close_archive(pNextArchive); - break; - } - } - } - } - } while (drfs_drpath_next(&segment)); - } - - // The running path is not part of this archive. - // NOTE: Is this the correct return value we should be using? Should we be returning an error and setting the output archive to NULL? - drfs__strcpy_s(relativePathOut, relativePathOutSize, relativePath); - *ppArchiveOut = pParentArchive; - return drfs_does_not_exist; - } -} - -// Opens the archive that owns the file at the given verbose path. -static drfs_result drfs_open_owner_archive_from_absolute_path(drfs_context* pContext, const char* absolutePath, unsigned int accessMode, char* relativePathOut, size_t relativePathOutSize, drfs_archive** ppArchiveOut) -{ - assert(pContext != NULL); - assert(absolutePath != NULL); - assert(ppArchiveOut != NULL); - - *ppArchiveOut = NULL; - - // We are currently assuming absolute path's are verbose. This means we don't need to do any searching on the file system. We just - // move through the path and look for a segment with an extension matching one of the registered back-ends. - - char runningPath[DRFS_MAX_PATH]; - runningPath[0] = '\0'; - - if (absolutePath[0] == '/') { - runningPath[0] = '/'; - runningPath[1] = '\0'; - } - - drfs_drpath_iterator segment; - if (drfs_drpath_first(absolutePath, &segment)) - { - do - { - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), segment)) { - return drfs_path_too_long; - } - - if (!drfs_is_native_directory(runningPath)) - { - char dirAbsolutePath[DRFS_MAX_PATH]; - drfs_drpath_copy_base_path(runningPath, dirAbsolutePath, sizeof(dirAbsolutePath)); - - drfs_archive* pNativeArchive; - drfs_result result = drfs_open_native_archive(pContext, dirAbsolutePath, accessMode, &pNativeArchive); - if (result != drfs_success) { - return result; // Failed to open the native archive. - } - - - // The running path is not a native directory. It could be an archive file. - drfs_archive_callbacks backendCallbacks; - if (drfs_find_backend_by_extension(pContext, drfs_drpath_extension(runningPath), &backendCallbacks)) - { - // The running path refers to an archive file. We need to try opening the archive here. If this fails, we - // need to return NULL. - drfs_archive* pArchive; - result = drfs_open_owner_archive_recursively_from_verbose_path(pNativeArchive, segment.path + segment.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pArchive); - if (pArchive == NULL) { - drfs_close_archive(pNativeArchive); - return result; - } - - *ppArchiveOut = pArchive; - return drfs_success; - } - else - { - drfs__strcpy_s(relativePathOut, relativePathOutSize, segment.path + segment.segment.offset); - *ppArchiveOut = pNativeArchive; - return drfs_success; - } - } - - } while (drfs_drpath_next(&segment)); - } - - return drfs_does_not_exist; -} - -// Recursively opens the archive that owns the file specified by the given relative path. -static drfs_result drfs_open_owner_archive_recursively_from_relative_path(drfs_archive* pParentArchive, const char* rootSearchPath, const char* relativePath, unsigned int accessMode, char* relativePathOut, size_t relativePathOutSize, drfs_archive** ppArchiveOut) -{ - assert(pParentArchive != NULL); - assert(relativePath != NULL); - assert(ppArchiveOut != NULL); - - *ppArchiveOut = NULL; - - if (pParentArchive->callbacks.get_file_info == NULL) { - return drfs_no_backend; - } - - // Always try the direct route by checking if the file exists within the archive first. - drfs_file_info fi; - if (pParentArchive->callbacks.get_file_info(pParentArchive->internalArchiveHandle, relativePath, &fi) == drfs_success) - { - // The file is in this archive. - drfs__strcpy_s(relativePathOut, relativePathOutSize, relativePath); - *ppArchiveOut = pParentArchive; - return drfs_success; - } - else - { - // The file does not exist within this archive. We need to search the parent archive recursively. We never search above - // the path specified by rootSearchPath. - char runningPath[DRFS_MAX_PATH]; - drfs__strcpy_s(runningPath, sizeof(runningPath), rootSearchPath); - - // Part of rootSearchPath and relativePath will be overlapping. We want to begin searching at the non-overlapping section. - drfs_drpath_iterator pathSeg0; - drfs_drpath_iterator pathSeg1; - dr_bool32 isSeg0Valid = drfs_drpath_first(rootSearchPath, &pathSeg0); - dr_bool32 isSeg1Valid = drfs_drpath_first(relativePath, &pathSeg1); - while (isSeg0Valid && isSeg1Valid) { - isSeg0Valid = drfs_drpath_next(&pathSeg0); - isSeg1Valid = drfs_drpath_next(&pathSeg1); - } - - relativePath = pathSeg1.path + pathSeg1.segment.offset; - - // Searching works as such: - // For each segment in "relativePath" - // If segment is archive then - // Open and search archive - // Else - // Search each archive file in this directory - // Endif - drfs_drpath_iterator pathseg; - if (drfs_drpath_first(relativePath, &pathseg)) - { - do - { - char runningPathBase[DRFS_MAX_PATH]; - drfs__strcpy_s(runningPathBase, sizeof(runningPathBase), runningPath); - - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), pathseg)) { - return drfs_path_too_long; - } - - drfs_archive* pNextArchive; - drfs_open_non_native_archive_from_path(pParentArchive, runningPath, accessMode, &pNextArchive); - if (pNextArchive != NULL) - { - // It's an archive segment. We need to check this archive recursively, starting from the next segment. - drfs_drpath_iterator nextseg = pathseg; - if (!drfs_drpath_next(&nextseg)) { - // Should never actually get here, but if we do it means we've reached the end of the path. Assume the file could not be found. - drfs_close_archive(pNextArchive); - return drfs_unknown_error; - } - - drfs_archive* pOwnerArchive; - drfs_open_owner_archive_recursively_from_relative_path(pNextArchive, "", nextseg.path + nextseg.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive); - if (pOwnerArchive == NULL) { - drfs_close_archive(pNextArchive); - return drfs_does_not_exist; - } - - *ppArchiveOut = pOwnerArchive; - return drfs_success; - } - else - { - // It's not an archive segment. We need to search. - if (pParentArchive->callbacks.begin_iteration == NULL || pParentArchive->callbacks.next_iteration == NULL || pParentArchive->callbacks.end_iteration == NULL) { - return drfs_no_backend; - } - - drfs_handle iterator = pParentArchive->callbacks.begin_iteration(pParentArchive->internalArchiveHandle, runningPathBase); - if (iterator == NULL) { - return drfs_no_backend; - } - - while (pParentArchive->callbacks.next_iteration(pParentArchive->internalArchiveHandle, iterator, &fi)) - { - if ((fi.attributes & DRFS_FILE_ATTRIBUTE_DIRECTORY) == 0) - { - // It's a file which means it could be an archive. Note that fi.absolutePath is actually relative to the parent archive. - drfs_open_non_native_archive_from_path(pParentArchive, fi.absolutePath, accessMode, &pNextArchive); - if (pNextArchive != NULL) - { - // It's an archive, so check it. - drfs_archive* pOwnerArchive; - drfs_open_owner_archive_recursively_from_relative_path(pNextArchive, "", pathseg.path + pathseg.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive); - if (pOwnerArchive != NULL) { - pParentArchive->callbacks.end_iteration(pParentArchive->internalArchiveHandle, iterator); - *ppArchiveOut = pOwnerArchive; - return drfs_success; - } else { - drfs_close_archive(pNextArchive); - } - } - } - } - - pParentArchive->callbacks.end_iteration(pParentArchive->internalArchiveHandle, iterator); - } - - } while (drfs_drpath_next(&pathseg)); - } - } - - return drfs_does_not_exist; -} - -// Opens the archive that owns the file at the given path that's relative to the given base path. This supports non-verbose paths and will search -// the file system for the archive. -static drfs_result drfs_open_owner_archive_from_relative_path(drfs_context* pContext, const char* absoluteBasePath, const char* relativePath, unsigned int accessMode, char* relativePathOut, size_t relativePathOutSize, drfs_archive** ppArchiveOut) -{ - assert(pContext != NULL); - assert(absoluteBasePath != NULL); - assert(relativePath != NULL); - assert(drfs_drpath_is_absolute(absoluteBasePath)); - assert(ppArchiveOut != NULL); - - *ppArchiveOut = NULL; - - char adjustedRelativePath[DRFS_MAX_PATH]; - char relativeBasePath[DRFS_MAX_PATH]; - relativeBasePath[0] = '\0'; - - // The base path should be absolute and verbose. It does not need to be an actual directory. - drfs_archive* pBaseArchive = NULL; - if (drfs_is_native_directory(absoluteBasePath)) - { - drfs_result result = drfs_open_native_archive(pContext, absoluteBasePath, accessMode, &pBaseArchive); - if (result != drfs_success) { - return result; - } - - if (drfs__strcpy_s(adjustedRelativePath, sizeof(adjustedRelativePath), relativePath) != 0) { - drfs_close_archive(pBaseArchive); - return drfs_path_too_long; - } - } - else - { - drfs_result result = drfs_open_owner_archive(pContext, absoluteBasePath, accessMode, relativeBasePath, sizeof(relativeBasePath), &pBaseArchive); - if (result != drfs_success) { - return result; - } - - if (!drfs_drpath_copy_and_append(adjustedRelativePath, sizeof(adjustedRelativePath), relativeBasePath, relativePath)) { - drfs_close_archive(pBaseArchive); - return drfs_path_too_long; - } - } - - - // We couldn't open the archive file from here, so we'll need to search for the owner archive recursively. - drfs_archive* pOwnerArchive; - drfs_result result = drfs_open_owner_archive_recursively_from_relative_path(pBaseArchive, relativeBasePath, adjustedRelativePath, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive); - if (pOwnerArchive == NULL) { - return result; - } - - drfs_recursively_claim_ownership_or_parent_archive(pOwnerArchive); - - *ppArchiveOut = pOwnerArchive; - return drfs_success; -} - -// Opens an archive from a path that's relative to the given base path. This supports non-verbose paths and will search -// the file system for the archive. -static drfs_result drfs_open_archive_from_relative_path(drfs_context* pContext, const char* absoluteBasePath, const char* relativePath, unsigned int accessMode, drfs_archive** ppArchiveOut) -{ - assert(pContext != NULL); - assert(absoluteBasePath != NULL); - assert(relativePath != NULL); - assert(drfs_drpath_is_absolute(absoluteBasePath)); - assert(ppArchiveOut != NULL); - - *ppArchiveOut = NULL; - - char adjustedRelativePath[DRFS_MAX_PATH]; - char relativeBasePath[DRFS_MAX_PATH]; - relativeBasePath[0] = '\0'; - - // The base path should be absolute and verbose. It does not need to be an actual directory. - drfs_archive* pBaseArchive = NULL; - if (drfs_is_native_directory(absoluteBasePath)) - { - drfs_result result = drfs_open_native_archive(pContext, absoluteBasePath, accessMode, &pBaseArchive); - if (result != drfs_success) { - return result; - } - - if (drfs__strcpy_s(adjustedRelativePath, sizeof(adjustedRelativePath), relativePath) != 0) { - drfs_close_archive(pBaseArchive); - return drfs_path_too_long; - } - } - else - { - drfs_result result = drfs_open_owner_archive(pContext, absoluteBasePath, accessMode, relativeBasePath, sizeof(relativeBasePath), &pBaseArchive); - if (result != drfs_success) { - return result; - } - - if (!drfs_drpath_copy_and_append(adjustedRelativePath, sizeof(adjustedRelativePath), relativeBasePath, relativePath)) { - drfs_close_archive(pBaseArchive); - return drfs_path_too_long; - } - } - - - // We can try opening the file directly from the base path. If this doesn't work, we can try recursively opening the owner archive - // an open from there. - drfs_archive* pArchive; - drfs_result result = drfs_open_non_native_archive_from_path(pBaseArchive, adjustedRelativePath, accessMode, &pArchive); - if (pArchive == NULL) - { - // We couldn't open the archive file from here, so we'll need to search for the owner archive recursively. - char archiveRelativePath[DRFS_MAX_PATH]; - drfs_archive* pOwnerArchive; - result = drfs_open_owner_archive_recursively_from_relative_path(pBaseArchive, relativeBasePath, adjustedRelativePath, accessMode, archiveRelativePath, sizeof(archiveRelativePath), &pOwnerArchive); - if (pOwnerArchive != NULL) - { - drfs_recursively_claim_ownership_or_parent_archive(pOwnerArchive); - - result = drfs_open_non_native_archive_from_path(pOwnerArchive, archiveRelativePath, accessMode, &pArchive); - if (pArchive == NULL) { - drfs_close_archive(pOwnerArchive); - return result; - } - } - } - - if (pArchive == NULL) { - drfs_close_archive(pBaseArchive); - return drfs_does_not_exist; - } - - *ppArchiveOut = pArchive; - return drfs_success; -} - -//// Back-End Registration //// - -#ifndef DR_FS_NO_ZIP -// Registers the archive callbacks which enables support for Zip files. -static void drfs_register_zip_backend(drfs_context* pContext); -#endif - -#ifndef DR_FS_NO_PAK -// Registers the archive callbacks which enables support for Quake 2 pak files. -static void drfs_register_pak_backend(drfs_context* pContext); -#endif - -#ifndef DR_FS_NO_MTL -// Registers the archive callbacks which enables support for Quake 2 pak files. -static void drfs_register_mtl_backend(drfs_context* pContext); -#endif - - - -//// Public API Implementation //// - -drfs_result drfs_init(drfs_context* pContext) -{ - if (pContext == NULL) return drfs_invalid_args; - memset(pContext, 0, sizeof(*pContext)); - - if (!drfs_callbacklist_init(&pContext->archiveCallbacks) || !drfs_basedirs_init(&pContext->baseDirectories)) { - return drfs_unknown_error; - } - - pContext->isWriteGuardEnabled = 0; - -#ifndef DR_FS_NO_ZIP - drfs_register_zip_backend(pContext); -#endif - -#ifndef DR_FS_NO_PAK - drfs_register_pak_backend(pContext); -#endif - -#ifndef DR_FS_NO_MTL - drfs_register_mtl_backend(pContext); -#endif - - return drfs_success; -} - -drfs_result drfs_uninit(drfs_context* pContext) -{ - if (pContext == NULL) return drfs_invalid_args; - - drfs_basedirs_uninit(&pContext->baseDirectories); - drfs_callbacklist_uninit(&pContext->archiveCallbacks); - return drfs_success; -} - - -drfs_context* drfs_create_context() -{ - drfs_context* pContext = (drfs_context*)malloc(sizeof(*pContext)); - if (pContext == NULL) { - return NULL; - } - - if (drfs_init(pContext) != drfs_success) { - free(pContext); - return NULL; - } - - return pContext; -} - -void drfs_delete_context(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drfs_uninit(pContext); - free(pContext); -} - - -void drfs_register_archive_backend(drfs_context* pContext, drfs_archive_callbacks callbacks) -{ - if (pContext == NULL) { - return; - } - - drfs_callbacklist_pushback(&pContext->archiveCallbacks, callbacks); -} - - -void drfs_insert_base_directory(drfs_context* pContext, const char* absolutePath, unsigned int index) -{ - if (pContext == NULL) { - return; - } - - drfs_basedirs_insert(&pContext->baseDirectories, absolutePath, index); -} - -void drfs_add_base_directory(drfs_context* pContext, const char* absolutePath) -{ - if (pContext == NULL) { - return; - } - - drfs_insert_base_directory(pContext, absolutePath, drfs_get_base_directory_count(pContext)); -} - -void drfs_remove_base_directory(drfs_context* pContext, const char* absolutePath) -{ - if (pContext == NULL) { - return; - } - - for (unsigned int iPath = 0; iPath < pContext->baseDirectories.count; /*DO NOTHING*/) { - if (drfs_drpath_equal(pContext->baseDirectories.pBuffer[iPath].absolutePath, absolutePath)) { - drfs_basedirs_remove(&pContext->baseDirectories, iPath); - } else { - ++iPath; - } - } -} - -void drfs_remove_base_directory_by_index(drfs_context* pContext, unsigned int index) -{ - if (pContext == NULL) { - return; - } - - drfs_basedirs_remove(&pContext->baseDirectories, index); -} - -void drfs_remove_all_base_directories(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drfs_basedirs_clear(&pContext->baseDirectories); -} - -unsigned int drfs_get_base_directory_count(drfs_context* pContext) -{ - if (pContext == NULL) { - return 0; - } - - return pContext->baseDirectories.count; -} - -const char* drfs_get_base_directory_by_index(drfs_context* pContext, unsigned int index) -{ - if (pContext == NULL || index >= pContext->baseDirectories.count) { - return NULL; - } - - return pContext->baseDirectories.pBuffer[index].absolutePath; -} - - -void drfs_set_base_write_directory(drfs_context* pContext, const char* absolutePath) -{ - if (pContext == NULL) { - return; - } - - if (absolutePath == NULL) { - memset(pContext->writeBaseDirectory, 0, sizeof(pContext->writeBaseDirectory)); - } else { - drfs__strcpy_s(pContext->writeBaseDirectory, sizeof(pContext->writeBaseDirectory), absolutePath); - } -} - -dr_bool32 drfs_get_base_write_directory(drfs_context* pContext, char* absolutePathOut, unsigned int absolutePathOutSize) -{ - if (pContext == NULL || absolutePathOut == NULL || absolutePathOutSize == 0) { - return DR_FALSE; - } - - return drfs__strcpy_s(absolutePathOut, absolutePathOutSize, pContext->writeBaseDirectory) == 0; -} - -void drfs_enable_write_directory_guard(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - pContext->isWriteGuardEnabled = DR_TRUE; -} - -void drfs_disable_write_directory_guard(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - pContext->isWriteGuardEnabled = DR_FALSE; -} - -dr_bool32 drfs_is_write_directory_guard_enabled(drfs_context* pContext) -{ - if (pContext == NULL) { - return DR_FALSE; - } - - return pContext->isWriteGuardEnabled; -} - - - - -drfs_result drfs_open_archive(drfs_context* pContext, const char* absoluteOrRelativePath, unsigned int accessMode, drfs_archive** ppArchiveOut) -{ - if (ppArchiveOut == NULL) { - return drfs_invalid_args; - } - - *ppArchiveOut = NULL; - - if (pContext == NULL || absoluteOrRelativePath == NULL) { - return drfs_invalid_args; - } - - if (drfs_drpath_is_absolute(absoluteOrRelativePath)) - { - if (drfs_is_native_directory(absoluteOrRelativePath)) - { - // It's a native directory. - return drfs_open_native_archive(pContext, absoluteOrRelativePath, accessMode, ppArchiveOut); - } - else - { - // It's not a native directory. We can just use drfs_open_owner_archive() in this case. - char relativePath[DRFS_MAX_PATH]; - drfs_archive* pOwnerArchive; - drfs_result result = drfs_open_owner_archive(pContext, absoluteOrRelativePath, accessMode, relativePath, sizeof(relativePath), &pOwnerArchive); - if (result != drfs_success) { - return result; - } - - drfs_archive* pArchive; - result = drfs_open_non_native_archive_from_path(pOwnerArchive, relativePath, accessMode, &pArchive); - if (result != drfs_success) { - drfs_close_archive(pOwnerArchive); - return result; - } - - drfs_recursively_claim_ownership_or_parent_archive(pArchive); - - *ppArchiveOut = pArchive; - return drfs_success; - } - } - else - { - // The input path is not absolute. We need to check each base directory. - - for (unsigned int iBaseDir = 0; iBaseDir < drfs_get_base_directory_count(pContext); ++iBaseDir) - { - drfs_archive* pArchive; - drfs_result result = drfs_open_archive_from_relative_path(pContext, drfs_get_base_directory_by_index(pContext, iBaseDir), absoluteOrRelativePath, accessMode, &pArchive); - if (result == drfs_success && pArchive != NULL) { - drfs_recursively_claim_ownership_or_parent_archive(pArchive); - - *ppArchiveOut = pArchive; - return drfs_success; - } - } - } - - return drfs_does_not_exist; -} - -drfs_result drfs_open_owner_archive(drfs_context* pContext, const char* absoluteOrRelativePath, unsigned int accessMode, char* relativePathOut, size_t relativePathOutSize, drfs_archive** ppArchiveOut) -{ - if (ppArchiveOut == NULL) { - return drfs_invalid_args; - } - - *ppArchiveOut = NULL; - - if (pContext == NULL || absoluteOrRelativePath == NULL) { - return drfs_invalid_args; - } - - if (drfs_drpath_is_absolute(absoluteOrRelativePath)) - { - if (drfs_is_native_file(absoluteOrRelativePath) || drfs_is_native_directory(absoluteOrRelativePath)) - { - // It's a native file. The owner archive is the directory it's directly sitting in. - char dirAbsolutePath[DRFS_MAX_PATH]; - drfs_drpath_copy_base_path(absoluteOrRelativePath, dirAbsolutePath, sizeof(dirAbsolutePath)); - - drfs_archive* pArchive; - drfs_result result = drfs_open_archive(pContext, dirAbsolutePath, accessMode, &pArchive); - if (result != drfs_success) { - return result; - } - - if (relativePathOut) { - if (drfs__strcpy_s(relativePathOut, relativePathOutSize, drfs_drpath_file_name(absoluteOrRelativePath)) != 0) { - drfs_close_archive(pArchive); - return drfs_path_too_long; - } - } - - *ppArchiveOut = pArchive; - return drfs_success; - } - else - { - // It's not a native file or directory. - drfs_archive* pArchive; - drfs_result result = drfs_open_owner_archive_from_absolute_path(pContext, absoluteOrRelativePath, accessMode, relativePathOut, relativePathOutSize, &pArchive); - if (pArchive == NULL) { - return result; - } - - drfs_recursively_claim_ownership_or_parent_archive(pArchive); - - *ppArchiveOut = pArchive; - return drfs_success; - } - } - else - { - // The input path is not absolute. We need to loop through each base directory. - - for (unsigned int iBaseDir = 0; iBaseDir < drfs_get_base_directory_count(pContext); ++iBaseDir) - { - drfs_archive* pArchive; - drfs_result result = drfs_open_owner_archive_from_relative_path(pContext, drfs_get_base_directory_by_index(pContext, iBaseDir), absoluteOrRelativePath, accessMode, relativePathOut, relativePathOutSize, &pArchive); - if (result == drfs_success && pArchive != NULL) { - drfs_recursively_claim_ownership_or_parent_archive(pArchive); - - *ppArchiveOut = pArchive; - return drfs_success; - } - } - } - - return drfs_does_not_exist; -} - -void drfs_close_archive(drfs_archive* pArchive) -{ - if (pArchive == NULL) { - return; - } - - // The internal handle needs to be closed. - if (pArchive->callbacks.close_archive) { - pArchive->callbacks.close_archive(pArchive->internalArchiveHandle); - } - - drfs_close(pArchive->pFile); - - - if ((pArchive->flags & DR_FS_OWNS_PARENT_ARCHIVE) != 0) { - drfs_close_archive(pArchive->pParentArchive); - } - - free(pArchive); -} - -drfs_result drfs_open_file_from_archive(drfs_archive* pArchive, const char* relativePath, unsigned int accessMode, drfs_file** ppFileOut) -{ - if (ppFileOut == NULL) { - return drfs_invalid_args; - } - - *ppFileOut = NULL; - - if (pArchive == NULL || relativePath == NULL || pArchive->callbacks.open_file == NULL) { - return drfs_invalid_args; - } - - drfs_handle internalFileHandle; - drfs_result result = pArchive->callbacks.open_file(pArchive->internalArchiveHandle, relativePath, accessMode, &internalFileHandle); - if (result != drfs_success) { - return result; - } - - // At this point the file is opened and we can create the file object. - drfs_file* pFile = (drfs_file*)malloc(sizeof(*pFile)); - if (pFile == NULL) { - pArchive->callbacks.close_file(pArchive->internalArchiveHandle, internalFileHandle); - return drfs_out_of_memory; - } - - pFile->pArchive = pArchive; - pFile->internalFileHandle = internalFileHandle; - pFile->flags = 0; - - // The lock. -#ifdef _WIN32 -#ifdef DR_FS_WIN32_USE_EVENT_MUTEX - pFile->lock = CreateEvent(NULL, FALSE, TRUE, NULL); -#else - InitializeCriticalSection(&pFile->lock); -#endif -#else - if (pthread_mutex_init(&pFile->lock, NULL) != 0) { - drfs_close(pFile); - return drfs_unknown_error; - } -#endif - - *ppFileOut = pFile; - return drfs_success; -} - - -drfs_result drfs_open(drfs_context* pContext, const char* absoluteOrRelativePath, unsigned int accessMode, drfs_file** ppFile) -{ - if (ppFile == NULL) { - return drfs_invalid_args; - } - - // Always set the output file to null at the start for safety. - *ppFile = NULL; - - if (pContext == NULL || absoluteOrRelativePath == NULL) { - return drfs_invalid_args; - } - - char absolutePathForWriteMode[DRFS_MAX_PATH]; - if ((accessMode & DRFS_WRITE) != 0) { - if (drfs_validate_write_path(pContext, absoluteOrRelativePath, absolutePathForWriteMode, sizeof(absolutePathForWriteMode))) { - absoluteOrRelativePath = absolutePathForWriteMode; - } else { - return drfs_not_in_write_directory; - } - } - - char relativePath[DRFS_MAX_PATH]; - drfs_archive* pArchive; - drfs_result result = drfs_open_owner_archive(pContext, absoluteOrRelativePath, drfs_archive_access_mode(accessMode), relativePath, sizeof(relativePath), &pArchive); - if (result != drfs_success) { - return result; - } - - drfs_file* pFile; - result = drfs_open_file_from_archive(pArchive, relativePath, accessMode, &pFile); - if (result != drfs_success) { - drfs_close_archive(pArchive); - return result; - } - - // When using this API, we want to claim ownership of the archive so that it's closed when we close this file. - pFile->flags |= DR_FS_OWNS_PARENT_ARCHIVE; - - *ppFile = pFile; - return drfs_success; -} - -void drfs_close(drfs_file* pFile) -{ - if (!drfs_lock(pFile)) { - return; - } - - if (pFile->pArchive != NULL && pFile->pArchive->callbacks.close_file) { - pFile->pArchive->callbacks.close_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle); - pFile->internalFileHandle = NULL; - } - - if ((pFile->flags & DR_FS_OWNS_PARENT_ARCHIVE) != 0) { - drfs_close_archive(pFile->pArchive); - pFile->pArchive = NULL; - } - - drfs_unlock(pFile); - - - // The lock. -#ifdef _WIN32 -#ifdef DR_FS_WIN32_USE_EVENT_MUTEX - CloseHandle(pFile->lock); -#else - DeleteCriticalSection(&pFile->lock); -#endif -#else - pthread_mutex_destroy(&pFile->lock); -#endif - - free(pFile); -} - -drfs_result drfs_read_nolock(drfs_file* pFile, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - if (pFile == NULL || pDataOut == NULL || pFile->pArchive == NULL || pFile->pArchive->callbacks.read_file == NULL) { - return drfs_invalid_args; - } - - return pFile->pArchive->callbacks.read_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle, pDataOut, bytesToRead, pBytesReadOut); -} - -drfs_result drfs_read(drfs_file* pFile, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - if (!drfs_lock(pFile)) { - return drfs_unknown_error; - } - - drfs_result result = drfs_read_nolock(pFile, pDataOut, bytesToRead, pBytesReadOut); - - drfs_unlock(pFile); - return result; -} - -drfs_result drfs_write_nolock(drfs_file* pFile, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - if (pFile == NULL || pData == NULL || pFile->pArchive == NULL || pFile->pArchive->callbacks.write_file == NULL) { - return drfs_invalid_args; - } - - return pFile->pArchive->callbacks.write_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle, pData, bytesToWrite, pBytesWrittenOut); -} - -drfs_result drfs_write(drfs_file* pFile, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - if (!drfs_lock(pFile)) { - return drfs_unknown_error; - } - - drfs_result result = drfs_write_nolock(pFile, pData, bytesToWrite, pBytesWrittenOut); - - drfs_unlock(pFile); - return result; -} - -drfs_result drfs_seek_nolock(drfs_file* pFile, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - if (pFile == NULL || pFile->pArchive == NULL || pFile->pArchive->callbacks.seek_file == NULL) { - return drfs_invalid_args; - } - - return pFile->pArchive->callbacks.seek_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle, bytesToSeek, origin); -} - -drfs_result drfs_seek(drfs_file* pFile, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - if (!drfs_lock(pFile)) { - return drfs_unknown_error; - } - - drfs_result result = drfs_seek_nolock(pFile, bytesToSeek, origin); - - drfs_unlock(pFile); - return result; -} - -dr_uint64 drfs_tell_nolock(drfs_file* pFile) -{ - if (pFile == NULL || pFile->pArchive == NULL || pFile->pArchive->callbacks.tell_file == NULL) { - return DR_FALSE; - } - - return pFile->pArchive->callbacks.tell_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle); -} - -dr_uint64 drfs_tell(drfs_file* pFile) -{ - if (!drfs_lock(pFile)) { - return 0; - } - - dr_uint64 result = drfs_tell_nolock(pFile); - - drfs_unlock(pFile); - return result; -} - -dr_uint64 drfs_size_nolock(drfs_file* pFile) -{ - if (pFile == NULL || pFile->pArchive == NULL || pFile->pArchive->callbacks.file_size == NULL) { - return 0; - } - - return pFile->pArchive->callbacks.file_size(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle); -} - -dr_uint64 drfs_size(drfs_file* pFile) -{ - if (!drfs_lock(pFile)) { - return DR_FALSE; - } - - dr_uint64 result = drfs_size_nolock(pFile); - - drfs_unlock(pFile); - return result; -} - -void drfs_flush(drfs_file* pFile) -{ - if (pFile == NULL || pFile->pArchive == NULL || pFile->pArchive->callbacks.flush_file == NULL) { - return; - } - - pFile->pArchive->callbacks.flush_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle); -} - - -dr_bool32 drfs_lock(drfs_file* pFile) -{ - if (pFile == NULL || pFile->internalFileHandle == NULL) { - return DR_FALSE; - } - -#ifdef _WIN32 -#ifdef DR_FS_WIN32_USE_EVENT_MUTEX - WaitForSingleObject(pFile->lock, INFINITE); -#else - EnterCriticalSection(&pFile->lock); -#endif -#else - pthread_mutex_lock(&pFile->lock); -#endif - - return DR_TRUE; -} - -void drfs_unlock(drfs_file* pFile) -{ - if (pFile == NULL || pFile->internalFileHandle == NULL) { - return; - } - -#ifdef _WIN32 -#ifdef DR_FS_WIN32_USE_EVENT_MUTEX - SetEvent(pFile->lock); -#else - LeaveCriticalSection(&pFile->lock); -#endif -#else - pthread_mutex_unlock(&pFile->lock); -#endif -} - - -drfs_result drfs_get_file_info(drfs_context* pContext, const char* absoluteOrRelativePath, drfs_file_info* fi) -{ - if (pContext == NULL || absoluteOrRelativePath == NULL) { - return drfs_invalid_args; - } - - char relativePath[DRFS_MAX_PATH]; - drfs_archive* pOwnerArchive; - drfs_result result = drfs_open_owner_archive(pContext, absoluteOrRelativePath, DRFS_READ, relativePath, sizeof(relativePath), &pOwnerArchive); - if (result != drfs_success) { - return result; - } - - result = drfs_no_backend; - if (pOwnerArchive->callbacks.get_file_info) { - result = pOwnerArchive->callbacks.get_file_info(pOwnerArchive->internalArchiveHandle, relativePath, fi); - } - - if (result == drfs_success && fi != NULL) { - drfs_drpath_copy_and_append(fi->absolutePath, sizeof(fi->absolutePath), pOwnerArchive->absolutePath, relativePath); - } - - drfs_close_archive(pOwnerArchive); - return result; -} - - -dr_bool32 drfs_begin(drfs_context* pContext, const char* absoluteOrRelativePath, drfs_iterator* pIteratorOut) -{ - if (pIteratorOut == NULL) return DR_FALSE; - memset(pIteratorOut, 0, sizeof(*pIteratorOut)); - - if (pContext == NULL || absoluteOrRelativePath == NULL) { - return DR_FALSE; - } - - // We need to open the archive that the given folder is in. The path could, however, point to an actual archive which is allowed - // in which case we just iterate over the root directory within that archive. What we do is first try using the path as an actual - // archive. If it fails we assume the path is to a folder within an archive (such as a zip file) in which case we just try opening - // the owner archive. If both fail, we return DR_FALSE. - - char relativePath[DRFS_MAX_PATH]; - drfs_result result = drfs_open_archive(pContext, absoluteOrRelativePath, DRFS_READ, &pIteratorOut->pArchive); - if (result == drfs_success) { - relativePath[0] = '\0'; - } else { - result = drfs_open_owner_archive(pContext, absoluteOrRelativePath, DRFS_READ, relativePath, sizeof(relativePath), &pIteratorOut->pArchive); - if (result != drfs_success) { - return DR_FALSE; - } - } - - assert(pIteratorOut->pArchive != NULL); - - - if (pIteratorOut->pArchive->callbacks.begin_iteration) { - pIteratorOut->internalIteratorHandle = pIteratorOut->pArchive->callbacks.begin_iteration(pIteratorOut->pArchive->internalArchiveHandle, relativePath); - } - - if (pIteratorOut->internalIteratorHandle == NULL) { - drfs_close_archive(pIteratorOut->pArchive); - pIteratorOut->pArchive = NULL; - return DR_FALSE; - } - - - dr_bool32 foundFirst = drfs_next(pContext, pIteratorOut); - if (!foundFirst) { - drfs_end(pContext, pIteratorOut); - } - - return foundFirst; -} - -dr_bool32 drfs_next(drfs_context* pContext, drfs_iterator* pIterator) -{ - if (pIterator == NULL) { - return DR_FALSE; - } - - memset(&pIterator->info, 0, sizeof(pIterator->info)); - - if (pContext == NULL || pIterator->pArchive == NULL) { - return DR_FALSE; - } - - dr_bool32 result = DR_FALSE; - if (pIterator->pArchive->callbacks.next_iteration) { - result = pIterator->pArchive->callbacks.next_iteration(pIterator->pArchive->internalArchiveHandle, pIterator->internalIteratorHandle, &pIterator->info); - } - - // At this point the pIterator->info.absolutePath is actually referring to a relative path. We need to convert it to an absolute path. - if (result) { - char relativePath[DRFS_MAX_PATH]; - drfs__strcpy_s(relativePath, sizeof(relativePath), pIterator->info.absolutePath); - drfs_drpath_copy_and_append(pIterator->info.absolutePath, sizeof(pIterator->info.absolutePath), pIterator->pArchive->absolutePath, relativePath); - } - - return result; -} - -void drfs_end(drfs_context* pContext, drfs_iterator* pIterator) -{ - if (pContext == NULL || pIterator == NULL) { - return; - } - - if (pIterator->pArchive != NULL && pIterator->pArchive->callbacks.end_iteration) { - pIterator->pArchive->callbacks.end_iteration(pIterator->pArchive->internalArchiveHandle, pIterator->internalIteratorHandle); - } - - drfs_close_archive(pIterator->pArchive); - memset(pIterator, 0, sizeof(*pIterator)); -} - -drfs_result drfs_delete_file(drfs_context* pContext, const char* path) -{ - if (pContext == NULL || path == NULL) { - return drfs_invalid_args; - } - - char absolutePath[DRFS_MAX_PATH]; - if (!drfs_validate_write_path(pContext, path, absolutePath, sizeof(absolutePath))) { - return drfs_not_in_write_directory; - } - - - char relativePath[DRFS_MAX_PATH]; - drfs_archive* pArchive; - drfs_result result = drfs_open_owner_archive(pContext, absolutePath, drfs_archive_access_mode(DRFS_READ | DRFS_WRITE), relativePath, sizeof(relativePath), &pArchive); - if (result != drfs_success) { - return result; - } - - result = drfs_no_backend; - if (pArchive->callbacks.delete_file) { - result = pArchive->callbacks.delete_file(pArchive->internalArchiveHandle, relativePath); - } - - drfs_close_archive(pArchive); - return result; -} - -drfs_result drfs_create_directory(drfs_context* pContext, const char* path) -{ - if (pContext == NULL || path == NULL) { - return drfs_invalid_args; - } - - char absolutePath[DRFS_MAX_PATH]; - if (!drfs_validate_write_path(pContext, path, absolutePath, sizeof(absolutePath))) { - return drfs_not_in_write_directory; - } - - char relativePath[DRFS_MAX_PATH]; - drfs_archive* pArchive; - drfs_result result = drfs_open_owner_archive(pContext, absolutePath, drfs_archive_access_mode(DRFS_READ | DRFS_WRITE), relativePath, sizeof(relativePath), &pArchive); - if (result != drfs_success) { - return result; - } - - result = drfs_no_backend; - if (pArchive->callbacks.create_directory) { - result = pArchive->callbacks.create_directory(pArchive->internalArchiveHandle, relativePath); - } - - drfs_close_archive(pArchive); - return result; -} - -drfs_result drfs_move_file(drfs_context* pContext, const char* pathOld, const char* pathNew) -{ - // Renaming/moving is not supported across different archives. - - if (pContext == NULL || pathOld == NULL || pathNew == NULL) { - return drfs_invalid_args; - } - - - char absolutePathOld[DRFS_MAX_PATH]; - if (drfs_validate_write_path(pContext, pathOld, absolutePathOld, sizeof(absolutePathOld))) { - pathOld = absolutePathOld; - } else { - return drfs_not_in_write_directory; - } - - char absolutePathNew[DRFS_MAX_PATH]; - if (drfs_validate_write_path(pContext, pathNew, absolutePathNew, sizeof(absolutePathNew))) { - pathNew = absolutePathNew; - } else { - return drfs_not_in_write_directory; - } - - - - - - char relativePathOld[DRFS_MAX_PATH]; - drfs_archive* pArchiveOld; - drfs_result result = drfs_open_owner_archive(pContext, pathOld, drfs_archive_access_mode(DRFS_READ | DRFS_WRITE), relativePathOld, sizeof(relativePathOld), &pArchiveOld); - if (pArchiveOld != NULL) - { - char relativePathNew[DRFS_MAX_PATH]; - drfs_archive* pArchiveNew; - result = drfs_open_owner_archive(pContext, pathNew, drfs_archive_access_mode(DRFS_READ | DRFS_WRITE), relativePathNew, sizeof(relativePathNew), &pArchiveNew); - if (pArchiveNew != NULL) - { - dr_bool32 areBothArchivesNative = (pArchiveOld->callbacks.move_file == pArchiveNew->callbacks.move_file && pArchiveNew->callbacks.move_file == drfs_move_file__native); - if (areBothArchivesNative) - { - result = drfs_move_native_file(absolutePathOld, absolutePathNew); - } - else - { - if (drfs_drpath_equal(pArchiveOld->absolutePath, pArchiveNew->absolutePath) && pArchiveOld->callbacks.move_file) { - result = pArchiveOld->callbacks.move_file(pArchiveOld, relativePathOld, relativePathNew); - } else { - result = drfs_permission_denied; // Attempting to rename across different archives which is not supported. - } - } - - drfs_close_archive(pArchiveNew); - - } - - drfs_close_archive(pArchiveOld); - } - - return result; -} - -drfs_result drfs_copy_file(drfs_context* pContext, const char* srcPath, const char* dstPath, dr_bool32 failIfExists) -{ - if (pContext == NULL || srcPath == NULL || dstPath == NULL) { - return drfs_invalid_args; - } - - char dstPathAbsolute[DRFS_MAX_PATH]; - if (!drfs_validate_write_path(pContext, dstPath, dstPathAbsolute, sizeof(dstPathAbsolute))) { - return drfs_not_in_write_directory; - } - - - // We want to open the archive of both the source and destination. If they are the same archive we'll do an intra-archive copy. - char srcRelativePath[DRFS_MAX_PATH]; - drfs_archive* pSrcArchive; - drfs_result result = drfs_open_owner_archive(pContext, srcPath, drfs_archive_access_mode(DRFS_READ), srcRelativePath, sizeof(srcRelativePath), &pSrcArchive); - if (result != drfs_success) { - return result; - } - - char dstRelativePath[DRFS_MAX_PATH]; - drfs_archive* pDstArchive; - result = drfs_open_owner_archive(pContext, dstPathAbsolute, drfs_archive_access_mode(DRFS_READ | DRFS_WRITE), dstRelativePath, sizeof(dstRelativePath), &pDstArchive); - if (result != drfs_success) { - drfs_close_archive(pSrcArchive); - return result; - } - - - - result = drfs_success; - if (strcmp(pSrcArchive->absolutePath, pDstArchive->absolutePath) == 0 && pDstArchive->callbacks.copy_file) - { - // Intra-archive copy. - result = pDstArchive->callbacks.copy_file(pDstArchive->internalArchiveHandle, srcRelativePath, dstRelativePath, failIfExists); - } - else - { - dr_bool32 areBothArchivesNative = (pSrcArchive->callbacks.copy_file == pDstArchive->callbacks.copy_file && pDstArchive->callbacks.copy_file == drfs_copy_file__native); - if (areBothArchivesNative) - { - char srcPathAbsolute[DRFS_MAX_PATH]; - drfs_drpath_copy_and_append(srcPathAbsolute, sizeof(srcPathAbsolute), pSrcArchive->absolutePath, srcPath); - - result = drfs_copy_native_file(srcPathAbsolute, dstPathAbsolute, failIfExists); - } - else - { - // Inter-archive copy. This is a theoretically slower path because we do everything manually. Probably not much slower in practice, though. - if (failIfExists && pDstArchive->callbacks.get_file_info(pDstArchive, dstRelativePath, NULL) == drfs_success) - { - result = drfs_already_exists; - } - else - { - drfs_file* pSrcFile; - result = drfs_open_file_from_archive(pSrcArchive, srcRelativePath, DRFS_READ, &pSrcFile); - if (result != drfs_success) { - return result; - } - - drfs_file* pDstFile; - result = drfs_open_file_from_archive(pDstArchive, dstRelativePath, DRFS_WRITE | DRFS_TRUNCATE, &pDstFile); - if (result != drfs_success) { - drfs_close(pSrcFile); - return result; - } - - assert(pSrcFile != NULL); - assert(pDstFile != NULL); - - char chunk[4096]; - size_t bytesRead; - while (drfs_read(pSrcFile, chunk, sizeof(chunk), &bytesRead) == drfs_success && bytesRead > 0) - { - result = drfs_write(pDstFile, chunk, bytesRead, NULL); - if (result != drfs_success) { - break; - } - } - - drfs_close(pSrcFile); - drfs_close(pDstFile); - } - } - } - - - drfs_close_archive(pSrcArchive); - drfs_close_archive(pDstArchive); - - return result; -} - - -dr_bool32 drfs_is_archive_path(drfs_context* pContext, const char* path) -{ - return drfs_find_backend_by_extension(pContext, drfs_drpath_extension(path), NULL); -} - - - -/////////////////////////////////////////////////////////////////////////////// -// -// High Level API -// -/////////////////////////////////////////////////////////////////////////////// -void drfs_free(void* p) -{ - free(p); -} - -drfs_result drfs_find_absolute_path(drfs_context* pContext, const char* relativePath, char* absolutePathOut, size_t absolutePathOutSize) -{ - if (absolutePathOut == NULL) return drfs_invalid_args; - if (absolutePathOutSize > 0) absolutePathOut[0] = '\0'; - - if (pContext == NULL || relativePath == NULL || absolutePathOutSize == 0) { - return drfs_invalid_args; - } - - drfs_file_info fi; - if (drfs_get_file_info(pContext, relativePath, &fi) == drfs_success) { - if (drfs__strcpy_s(absolutePathOut, absolutePathOutSize, fi.absolutePath) == 0) { - return drfs_success; - } - } - - return drfs_does_not_exist; -} - -drfs_result drfs_find_absolute_path_explicit_base(drfs_context* pContext, const char* relativePath, const char* highestPriorityBasePath, char* absolutePathOut, size_t absolutePathOutSize) -{ - if (absolutePathOut == NULL) return drfs_invalid_args; - if (absolutePathOutSize > 0) absolutePathOut[0] = '\0'; - - if (pContext == NULL || relativePath == NULL || highestPriorityBasePath == NULL || absolutePathOutSize == 0) { - return drfs_invalid_args; - } - - drfs_result result = drfs_unknown_error; - drfs_insert_base_directory(pContext, highestPriorityBasePath, 0); - { - result = drfs_find_absolute_path(pContext, relativePath, absolutePathOut, absolutePathOutSize); - } - drfs_remove_base_directory_by_index(pContext, 0); - - return result; -} - -dr_bool32 drfs_is_base_directory(drfs_context* pContext, const char* baseDir) -{ - if (pContext == NULL) { - return DR_FALSE; - } - - for (unsigned int i = 0; i < drfs_get_base_directory_count(pContext); ++i) { - if (drfs_drpath_equal(drfs_get_base_directory_by_index(pContext, i), baseDir)) { - return DR_TRUE; - } - } - - return DR_FALSE; -} - -drfs_result drfs_write_string(drfs_file* pFile, const char* str) -{ - return drfs_write(pFile, str, (unsigned int)strlen(str), NULL); -} - -drfs_result drfs_write_line(drfs_file* pFile, const char* str) -{ - drfs_result result = drfs_write_string(pFile, str); - if (result != drfs_success) { - return result; - } - - return drfs_write_string(pFile, "\n"); -} - - -void* drfs_open_and_read_binary_file(drfs_context* pContext, const char* absoluteOrRelativePath, size_t* pSizeInBytesOut) -{ - drfs_file* pFile; - if (drfs_open(pContext, absoluteOrRelativePath, DRFS_READ, &pFile) != drfs_success) { - return NULL; - } - - dr_uint64 fileSize = drfs_size(pFile); - if (fileSize > SIZE_MAX) - { - // File's too big. - drfs_close(pFile); - return NULL; - } - - - void* pData = malloc((size_t)fileSize); - if (pData == NULL) - { - // Failed to allocate memory. - drfs_close(pFile); - return NULL; - } - - - if (drfs_read(pFile, pData, (size_t)fileSize, NULL) != drfs_success) - { - free(pData); - if (pSizeInBytesOut != NULL) { - *pSizeInBytesOut = 0; - } - - drfs_close(pFile); - return NULL; - } - - - if (pSizeInBytesOut != NULL) { - *pSizeInBytesOut = (size_t)fileSize; - } - - drfs_close(pFile); - return pData; -} - -char* drfs_open_and_read_text_file(drfs_context* pContext, const char* absoluteOrRelativePath, size_t* pSizeInBytesOut) -{ - drfs_file* pFile; - if (drfs_open(pContext, absoluteOrRelativePath, DRFS_READ, &pFile) != drfs_success) { - return NULL; - } - - dr_uint64 fileSize = drfs_size(pFile); - if (fileSize > SIZE_MAX) - { - // File's too big. - drfs_close(pFile); - return NULL; - } - - - void* pData = malloc((size_t)fileSize + 1); // +1 for null terminator. - if (pData == NULL) - { - // Failed to allocate memory. - drfs_close(pFile); - return NULL; - } - - - if (drfs_read(pFile, pData, (size_t)fileSize, NULL) != drfs_success) - { - free(pData); - if (pSizeInBytesOut != NULL) { - *pSizeInBytesOut = 0; - } - - drfs_close(pFile); - return NULL; - } - - // Null terminator. - ((char*)pData)[fileSize] = '\0'; - - - if (pSizeInBytesOut != NULL) { - *pSizeInBytesOut = (size_t)fileSize; - } - - drfs_close(pFile); - return (char*)pData; -} - -drfs_result drfs_open_and_write_binary_file(drfs_context* pContext, const char* absoluteOrRelativePath, const void* pData, size_t dataSize) -{ - drfs_result result = drfs_unknown_error; - - drfs_file* pFile; - result = drfs_open(pContext, absoluteOrRelativePath, DRFS_WRITE | DRFS_TRUNCATE, &pFile); - if (result != drfs_success) { - return result; - } - - result = drfs_write(pFile, pData, dataSize, NULL); - - drfs_close(pFile); - return result; -} - -drfs_result drfs_open_and_write_text_file(drfs_context* pContext, const char* absoluteOrRelativePath, const char* pTextData) -{ - return drfs_open_and_write_binary_file(pContext, absoluteOrRelativePath, pTextData, strlen(pTextData)); -} - - -dr_bool32 drfs_exists(drfs_context* pContext, const char* absoluteOrRelativePath) -{ - drfs_file_info fi; - return drfs_get_file_info(pContext, absoluteOrRelativePath, &fi) == drfs_success; -} - -dr_bool32 drfs_is_existing_file(drfs_context* pContext, const char* absoluteOrRelativePath) -{ - drfs_file_info fi; - if (drfs_get_file_info(pContext, absoluteOrRelativePath, &fi) == drfs_success) - { - return (fi.attributes & DRFS_FILE_ATTRIBUTE_DIRECTORY) == 0; - } - - return DR_FALSE; -} - -dr_bool32 drfs_is_existing_directory(drfs_context* pContext, const char* absoluteOrRelativePath) -{ - drfs_file_info fi; - if (drfs_get_file_info(pContext, absoluteOrRelativePath, &fi) == drfs_success) - { - return (fi.attributes & DRFS_FILE_ATTRIBUTE_DIRECTORY) != 0; - } - - return DR_FALSE; -} - -drfs_result drfs_create_directory_recursive(drfs_context* pContext, const char* path) -{ - if (pContext == NULL || path == NULL) { - return drfs_invalid_args; - } - - // We just iterate over each segment and try creating each directory if it doesn't exist. - char absolutePath[DRFS_MAX_PATH]; - if (drfs_validate_write_path(pContext, path, absolutePath, DRFS_MAX_PATH)) { - path = absolutePath; - } else { - return drfs_not_in_write_directory; - } - - - char runningPath[DRFS_MAX_PATH]; - runningPath[0] = '\0'; - - drfs_drpath_iterator iPathSeg; - if (!drfs_drpath_first(absolutePath, &iPathSeg)) { - return drfs_invalid_args; - } - - // Never check the first segment because we can assume it always exists - it will always be the drive root. - if (drfs_drpath_append_iterator(runningPath, sizeof(runningPath), iPathSeg)) - { - // Loop over every directory until we find one that does not exist. - while (drfs_drpath_next(&iPathSeg)) - { - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), iPathSeg)) { - return drfs_path_too_long; - } - - if (!drfs_is_existing_directory(pContext, runningPath)) { - drfs_result result = drfs_create_directory(pContext, runningPath); - if (result != drfs_success) { - return result; - } - - break; - } - } - - - // At this point all we need to do is create the remaining directories - we can assert that the directory does not exist - // rather than actually checking it which should be a bit more efficient. - while (drfs_drpath_next(&iPathSeg)) - { - if (!drfs_drpath_append_iterator(runningPath, sizeof(runningPath), iPathSeg)) { - return drfs_path_too_long; - } - - assert(!drfs_is_existing_directory(pContext, runningPath)); - - drfs_result result = drfs_create_directory(pContext, runningPath); - if (result != drfs_success) { - return result; - } - } - - - return drfs_success; - } - else - { - return drfs_invalid_args; - } -} - -dr_bool32 drfs_eof(drfs_file* pFile) -{ - return drfs_tell(pFile) == drfs_size(pFile); -} - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// ZIP -// -/////////////////////////////////////////////////////////////////////////////// -#ifndef DR_FS_NO_ZIP - -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4334) -#endif -#if defined(__GNUC__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-macros" - #pragma GCC diagnostic ignored "-Wcast-align" - #pragma GCC diagnostic ignored "-Wextra" - -#if __GNUC__ >= 6 && !defined __clang__ - #pragma GCC diagnostic ignored "-Wmisleading-indentation" -#endif -#endif - -#ifndef DRFS_MINIZ_HEADER_INCLUDED -#define DRFS_MINIZ_HEADER_INCLUDED - -// If DRFS_MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or -// get/set file times, and the C run-time funcs that get/set times won't be called. -// The current downside is the times written to your archives will be from 1979. -//#define DRFS_MINIZ_NO_TIME - -// Define DRFS_MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. -//#define DRFS_MINIZ_NO_ARCHIVE_APIS - -#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) - // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux - #define DRFS_MINIZ_NO_TIME -#endif - -#if !defined(DRFS_MINIZ_NO_TIME) && !defined(DRFS_MINIZ_NO_ARCHIVE_APIS) - #include -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -// DRFS_MINIZ_X86_OR_X64_CPU is only used to help set the below macros. -#define DRFS_MINIZ_X86_OR_X64_CPU 1 -#endif - -#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || DRFS_MINIZ_X86_OR_X64_CPU -// Set DRFS_MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. -#define DRFS_MINIZ_LITTLE_ENDIAN 1 -#endif - -#if DRFS_MINIZ_X86_OR_X64_CPU -// Set DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. -#define DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -#endif - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -// Set DRFS_MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). -#define DRFS_MINIZ_HAS_64BIT_REGISTERS 1 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// ------------------- zlib-style API Definitions. - -// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: drfs_mz_ulong can be either 32 or 64-bits! -typedef unsigned long drfs_mz_ulong; - -// drfs_mz_free() internally uses the DRFS_MZ_FREE() macro (which by default calls free() unless you've modified the DRFS_MZ_MALLOC macro) to release a block allocated from the heap. -void drfs_mz_free(void *p); - -#define DRFS_MZ_ADLER32_INIT (1) -// drfs_mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. -drfs_mz_ulong drfs_mz_adler32(drfs_mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define DRFS_MZ_CRC32_INIT (0) -// drfs_mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. -drfs_mz_ulong drfs_mz_crc32(drfs_mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -// Compression strategies. -enum { DRFS_MZ_DEFAULT_STRATEGY = 0, DRFS_MZ_FILTERED = 1, DRFS_MZ_HUFFMAN_ONLY = 2, DRFS_MZ_RLE = 3, DRFS_MZ_FIXED = 4 }; - -// Method -#define DRFS_MZ_DEFLATED 8 - -// Heap allocation callbacks. -// Note that drfs_mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. -typedef void *(*drfs_mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*drfs_mz_free_func)(void *opaque, void *address); -typedef void *(*drfs_mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -// ------------------- Types and macros - -typedef unsigned char drfs_mz_uint8; -typedef signed short drfs_mz_int16; -typedef unsigned short drfs_drfs_mz_uint16; -typedef unsigned int drfs_drfs_mz_uint32; -typedef unsigned int drfs_mz_uint; -typedef long long drfs_mz_int64; -typedef unsigned long long drfs_mz_uint64; -typedef int drfs_mz_bool; - -#define DRFS_MZ_FALSE (0) -#define DRFS_MZ_TRUE (1) - -// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. -#ifdef _MSC_VER - #define DRFS_MZ_MACRO_END while (0, 0) -#else - #define DRFS_MZ_MACRO_END while (0) -#endif - -// ------------------- ZIP archive reading/writing - -#ifndef DRFS_MINIZ_NO_ARCHIVE_APIS - -enum -{ - DRFS_MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, - DRFS_MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, - DRFS_MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 -}; - -typedef struct -{ - drfs_drfs_mz_uint32 m_file_index; - drfs_drfs_mz_uint32 m_central_dir_ofs; - drfs_drfs_mz_uint16 m_version_made_by; - drfs_drfs_mz_uint16 m_version_needed; - drfs_drfs_mz_uint16 m_bit_flag; - drfs_drfs_mz_uint16 m_method; -#ifndef DRFS_MINIZ_NO_TIME - time_t m_time; -#endif - drfs_drfs_mz_uint32 m_crc32; - drfs_mz_uint64 m_comp_size; - drfs_mz_uint64 m_uncomp_size; - drfs_drfs_mz_uint16 m_internal_attr; - drfs_drfs_mz_uint32 m_external_attr; - drfs_mz_uint64 m_local_header_ofs; - drfs_drfs_mz_uint32 m_comment_size; - char m_filename[DRFS_MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - char m_comment[DRFS_MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; -} drfs_drfs_mz_zip_archive_file_stat; - -typedef size_t (*drfs_mz_file_read_func)(void *pOpaque, drfs_mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t (*drfs_mz_file_write_func)(void *pOpaque, drfs_mz_uint64 file_ofs, const void *pBuf, size_t n); - -struct drfs_mz_zip_internal_state_tag; -typedef struct drfs_mz_zip_internal_state_tag drfs_mz_zip_internal_state; - -typedef enum -{ - DRFS_MZ_ZIP_MODE_INVALID = 0, - DRFS_MZ_ZIP_MODE_READING = 1, - DRFS_MZ_ZIP_MODE_WRITING = 2, - DRFS_MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -} drfs_mz_zip_mode; - -typedef struct drfs_mz_zip_archive_tag -{ - drfs_mz_uint64 m_archive_size; - drfs_mz_uint64 m_central_directory_file_ofs; - drfs_mz_uint m_total_files; - drfs_mz_zip_mode m_zip_mode; - - drfs_mz_uint m_file_offset_alignment; - - drfs_mz_alloc_func m_pAlloc; - drfs_mz_free_func m_pFree; - drfs_mz_realloc_func m_pRealloc; - void *m_pAlloc_opaque; - - drfs_mz_file_read_func m_pRead; - drfs_mz_file_write_func m_pWrite; - void *m_pIO_opaque; - - drfs_mz_zip_internal_state *m_pState; - -} drfs_mz_zip_archive; - -typedef enum -{ - DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - DRFS_MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, - DRFS_MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 -} drfs_mz_zip_flags; - -// ZIP archive reading - -// Inits a ZIP archive reader. -// These functions read and validate the archive's central directory. -drfs_mz_bool drfs_mz_zip_reader_init(drfs_mz_zip_archive *pZip, drfs_mz_uint64 size, drfs_drfs_mz_uint32 flags); - -// Returns the total number of files in the archive. -drfs_mz_uint drfs_mz_zip_reader_get_num_files(drfs_mz_zip_archive *pZip); - -// Returns detailed information about an archive file entry. -drfs_mz_bool drfs_mz_zip_reader_file_stat(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, drfs_drfs_mz_zip_archive_file_stat *pStat); - -// Determines if an archive file entry is a directory entry. -drfs_mz_bool drfs_mz_zip_reader_is_file_a_directory(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index); - -// Retrieves the filename of an archive file entry. -// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. -drfs_mz_uint drfs_mz_zip_reader_get_filename(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, char *pFilename, drfs_mz_uint filename_buf_size); - -// Attempts to locates a file in the archive's central directory. -// Valid flags: DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE, DRFS_MZ_ZIP_FLAG_IGNORE_PATH -// Returns -1 if the file cannot be found. -int drfs_mz_zip_reader_locate_file(drfs_mz_zip_archive *pZip, const char *pName, const char *pComment, drfs_mz_uint flags); - -// Extracts a archive file to a memory buffer using no memory allocation. -drfs_mz_bool drfs_mz_zip_reader_extract_to_mem_no_alloc(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, void *pBuf, size_t buf_size, drfs_mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem_no_alloc(drfs_mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, drfs_mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - -// Extracts a archive file to a memory buffer. -drfs_mz_bool drfs_mz_zip_reader_extract_to_mem(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, void *pBuf, size_t buf_size, drfs_mz_uint flags); -drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem(drfs_mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, drfs_mz_uint flags); - -// Extracts a archive file to a dynamically allocated heap buffer. -void *drfs_mz_zip_reader_extract_to_heap(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, size_t *pSize, drfs_mz_uint flags); - -// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. -drfs_mz_bool drfs_mz_zip_reader_end(drfs_mz_zip_archive *pZip); - -#endif // #ifndef DRFS_MINIZ_NO_ARCHIVE_APIS - -// ------------------- Low-level Decompression API Definitions - -// Decompression flags used by drfs_tinfl_decompress(). -// DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. -// DRFS_TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. -// DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). -// DRFS_TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. -enum -{ - DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - DRFS_TINFL_FLAG_HAS_MORE_INPUT = 2, - DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - DRFS_TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -// High level decompression functions: -// drfs_tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. -// On return: -// Function returns a pointer to the decompressed data, or NULL on failure. -// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must call drfs_mz_free() on the returned block when it's no longer needed. -void *drfs_tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// drfs_tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. -// Returns DRFS_TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. -#define DRFS_TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t drfs_tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// drfs_tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. -// Returns 1 on success or 0 on failure. -typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int drfs_tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct drfs_tinfl_decompressor_tag; typedef struct drfs_tinfl_decompressor_tag drfs_tinfl_decompressor; - -// Max size of LZ dictionary. -#define DRFS_TINFL_LZ_DICT_SIZE 32768 - -// Return status. -typedef enum -{ - DRFS_TINFL_STATUS_BAD_PARAM = -3, - DRFS_TINFL_STATUS_ADLER32_MISMATCH = -2, - DRFS_TINFL_STATUS_FAILED = -1, - DRFS_TINFL_STATUS_DONE = 0, - DRFS_TINFL_STATUS_NEEDS_MORE_INPUT = 1, - DRFS_TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} drfs_tinfl_status; - -// Initializes the decompressor to its initial state. -#define drfs_tinfl_init(r) do { (r)->m_state = 0; } DRFS_MZ_MACRO_END -#define drfs_tinfl_get_adler32(r) (r)->m_check_adler32 - -// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. -// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -drfs_tinfl_status drfs_tinfl_decompress(drfs_tinfl_decompressor *r, const drfs_mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, drfs_mz_uint8 *pOut_buf_start, drfs_mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const drfs_drfs_mz_uint32 decomp_flags); - -// Internal/private bits follow. -enum -{ - DRFS_TINFL_MAX_HUFF_TABLES = 3, DRFS_TINFL_MAX_HUFF_SYMBOLS_0 = 288, DRFS_TINFL_MAX_HUFF_SYMBOLS_1 = 32, DRFS_TINFL_MAX_HUFF_SYMBOLS_2 = 19, - DRFS_TINFL_FAST_LOOKUP_BITS = 10, DRFS_TINFL_FAST_LOOKUP_SIZE = 1 << DRFS_TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - drfs_mz_uint8 m_code_size[DRFS_TINFL_MAX_HUFF_SYMBOLS_0]; - drfs_mz_int16 m_look_up[DRFS_TINFL_FAST_LOOKUP_SIZE], m_tree[DRFS_TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} drfs_tinfl_huff_table; - -#if DRFS_MINIZ_HAS_64BIT_REGISTERS - #define DRFS_TINFL_USE_64BIT_BITBUF 1 -#endif - -#if DRFS_TINFL_USE_64BIT_BITBUF - typedef drfs_mz_uint64 drfs_tinfl_bit_buf_t; - #define DRFS_TINFL_BITBUF_SIZE (64) -#else - typedef drfs_drfs_mz_uint32 drfs_tinfl_bit_buf_t; - #define DRFS_TINFL_BITBUF_SIZE (32) -#endif - -struct drfs_tinfl_decompressor_tag -{ - drfs_drfs_mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[DRFS_TINFL_MAX_HUFF_TABLES]; - drfs_tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - drfs_tinfl_huff_table m_tables[DRFS_TINFL_MAX_HUFF_TABLES]; - drfs_mz_uint8 m_raw_header[4], m_len_codes[DRFS_TINFL_MAX_HUFF_SYMBOLS_0 + DRFS_TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#ifdef __cplusplus -} -#endif - -#endif // MINIZ_HEADER_INCLUDED - -// ------------------- End of Header: Implementation follows. (If you only want the header, define DRFS_MINIZ_HEADER_FILE_ONLY.) - -#ifndef DRFS_MINIZ_HEADER_FILE_ONLY - -typedef unsigned char mz_validate_uint16[sizeof(drfs_drfs_mz_uint16)==2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(drfs_drfs_mz_uint32)==4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(drfs_mz_uint64)==8 ? 1 : -1]; - -#include -#include - -#define DRFS_MZ_ASSERT(x) assert(x) - -#define DRFS_MZ_MALLOC(x) malloc(x) -#define DRFS_MZ_FREE(x) free(x) -#define DRFS_MZ_REALLOC(p, x) realloc(p, x) - -#define DRFS_MZ_MAX(a,b) (((a)>(b))?(a):(b)) -#define DRFS_MZ_MIN(a,b) (((a)<(b))?(a):(b)) -#define DRFS_MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES && DRFS_MINIZ_LITTLE_ENDIAN - #define DRFS_MZ_READ_LE16(p) *((const drfs_drfs_mz_uint16 *)(p)) - #define DRFS_MZ_READ_LE32(p) *((const drfs_drfs_mz_uint32 *)(p)) -#else - #define DRFS_MZ_READ_LE16(p) ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[0]) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[1]) << 8U)) - #define DRFS_MZ_READ_LE32(p) ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[0]) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[1]) << 8U) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[2]) << 16U) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[3]) << 24U)) -#endif - -#ifdef _MSC_VER - #define DRFS_MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) - #define DRFS_MZ_FORCEINLINE inline __attribute__((__always_inline__)) -#else - #define DRFS_MZ_FORCEINLINE inline -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -static void *drfs__def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return DRFS_MZ_MALLOC(items * size); } -static void drfs__def_free_func(void *opaque, void *address) { (void)opaque, (void)address; DRFS_MZ_FREE(address); } -static void *drfs__def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return DRFS_MZ_REALLOC(address, items * size); } - -// ------------------- zlib-style API's - -drfs_mz_ulong drfs_mz_adler32(drfs_mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - drfs_drfs_mz_uint32 i, s1 = (drfs_drfs_mz_uint32)(adler & 0xffff), s2 = (drfs_drfs_mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; - if (!ptr) return DRFS_MZ_ADLER32_INIT; - while (buf_len) { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - return (s2 << 16) + s1; -} - -// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ -drfs_mz_ulong drfs_mz_crc32(drfs_mz_ulong crc, const drfs_mz_uint8 *ptr, size_t buf_len) -{ - static const drfs_drfs_mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; - drfs_drfs_mz_uint32 crcu32 = (drfs_drfs_mz_uint32)crc; - if (!ptr) return DRFS_MZ_CRC32_INIT; - crcu32 = ~crcu32; while (buf_len--) { drfs_mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } - return ~crcu32; -} - -void drfs_mz_free(void *p) -{ - DRFS_MZ_FREE(p); -} - - -// ------------------- Low-level Decompression (completely independent from all compression API's) - -#define DRFS_TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define DRFS_TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define DRFS_TINFL_CR_BEGIN switch(r->m_state) { case 0: -#define DRFS_TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } DRFS_MZ_MACRO_END -#define DRFS_TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { DRFS_TINFL_CR_RETURN(state_index, result); } } DRFS_MZ_MACRO_END -#define DRFS_TINFL_CR_FINISH } - -// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never -// reads ahead more than it needs to. Currently DRFS_TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. -#define DRFS_TINFL_GET_BYTE(state_index, c) do { \ - if (pIn_buf_cur >= pIn_buf_end) { \ - for ( ; ; ) { \ - if (decomp_flags & DRFS_TINFL_FLAG_HAS_MORE_INPUT) { \ - DRFS_TINFL_CR_RETURN(state_index, DRFS_TINFL_STATUS_NEEDS_MORE_INPUT); \ - if (pIn_buf_cur < pIn_buf_end) { \ - c = *pIn_buf_cur++; \ - break; \ - } \ - } else { \ - c = 0; \ - break; \ - } \ - } \ - } else c = *pIn_buf_cur++; } DRFS_MZ_MACRO_END - -#define DRFS_TINFL_NEED_BITS(state_index, n) do { drfs_mz_uint c; DRFS_TINFL_GET_BYTE(state_index, c); bit_buf |= (((drfs_tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (drfs_mz_uint)(n)) -#define DRFS_TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (drfs_mz_uint)(n)) { DRFS_TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } DRFS_MZ_MACRO_END -#define DRFS_TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (drfs_mz_uint)(n)) { DRFS_TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } DRFS_MZ_MACRO_END - -// DRFS_TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. -// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a -// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the -// bit buffer contains >=15 bits (deflate's max. Huffman code size). -#define DRFS_TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do { \ - temp = (pHuff)->m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } else if (num_bits > DRFS_TINFL_FAST_LOOKUP_BITS) { \ - code_len = DRFS_TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } DRFS_TINFL_GET_BYTE(state_index, c); bit_buf |= (((drfs_tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ - } while (num_bits < 15); - -// DRFS_TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read -// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully -// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. -// The slow path is only executed at the very end of the input buffer. -#define DRFS_TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ - int temp; drfs_mz_uint code_len, c; \ - if (num_bits < 15) { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - DRFS_TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } else { \ - bit_buf |= (((drfs_tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((drfs_tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else { \ - code_len = DRFS_TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ - } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } DRFS_MZ_MACRO_END - -drfs_tinfl_status drfs_tinfl_decompress(drfs_tinfl_decompressor *r, const drfs_mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, drfs_mz_uint8 *pOut_buf_start, drfs_mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const drfs_drfs_mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - static const drfs_mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; - - drfs_tinfl_status status = DRFS_TINFL_STATUS_FAILED; drfs_drfs_mz_uint32 num_bits, dist, counter, num_extra; drfs_tinfl_bit_buf_t bit_buf; - const drfs_mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - drfs_mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return DRFS_TINFL_STATUS_BAD_PARAM; } - - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - DRFS_TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER) - { - DRFS_TINFL_GET_BYTE(1, r->m_zhdr0); DRFS_TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { DRFS_TINFL_CR_RETURN_FOREVER(36, DRFS_TINFL_STATUS_FAILED); } - } - - do - { - DRFS_TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - DRFS_TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) DRFS_TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else DRFS_TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (drfs_mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { DRFS_TINFL_CR_RETURN_FOREVER(39, DRFS_TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { - DRFS_TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(52, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (drfs_mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(9, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & DRFS_TINFL_FLAG_HAS_MORE_INPUT) - { - DRFS_TINFL_CR_RETURN(38, DRFS_TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { - DRFS_TINFL_CR_RETURN_FOREVER(40, DRFS_TINFL_STATUS_FAILED); - } - } - n = DRFS_MZ_MIN(DRFS_MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - DRFS_TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (drfs_mz_uint)n; - } - } - else if (r->m_type == 3) - { - DRFS_TINFL_CR_RETURN_FOREVER(10, DRFS_TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - drfs_mz_uint8 *p = r->m_tables[0].m_code_size; drfs_mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; DRFS_TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { DRFS_TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - DRFS_MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { drfs_mz_uint s; DRFS_TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (drfs_mz_uint8)s; } - r->m_table_sizes[2] = 19; - } - for ( ; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; drfs_tinfl_huff_table *pTable; - drfs_mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; DRFS_MZ_CLEAR_OBJ(total_syms); DRFS_MZ_CLEAR_OBJ(pTable->m_look_up); DRFS_MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { - DRFS_TINFL_CR_RETURN_FOREVER(35, DRFS_TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - drfs_mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= DRFS_TINFL_FAST_LOOKUP_BITS) { drfs_mz_int16 k = (drfs_mz_int16)((code_size << 9) | sym_index); while (rev_code < DRFS_TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)] = (drfs_mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (DRFS_TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (DRFS_TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (drfs_mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (drfs_mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - drfs_mz_uint s; DRFS_TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (drfs_mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { - DRFS_TINFL_CR_RETURN_FOREVER(17, DRFS_TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; DRFS_TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - DRFS_TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - DRFS_TINFL_CR_RETURN_FOREVER(21, DRFS_TINFL_STATUS_FAILED); - } - DRFS_TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); DRFS_TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for ( ; ; ) - { - drfs_mz_uint8 *pSrc; - for ( ; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - DRFS_TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(24, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (drfs_mz_uint8)counter; - } - else - { - int sym2; drfs_mz_uint code_len; -#if DRFS_TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((drfs_tinfl_bit_buf_t)DRFS_MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } -#else - if (num_bits < 15) { bit_buf |= (((drfs_tinfl_bit_buf_t)DRFS_MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = DRFS_TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; - if (counter & 256) - break; - -#if !DRFS_TINFL_USE_64BIT_BITBUF - if (num_bits < 15) { bit_buf |= (((drfs_tinfl_bit_buf_t)DRFS_MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = DRFS_TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - bit_buf >>= code_len; num_bits -= code_len; - - pOut_buf_cur[0] = (drfs_mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (drfs_mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) break; - - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { drfs_mz_uint extra_bits; DRFS_TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } - - DRFS_TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { drfs_mz_uint extra_bits; DRFS_TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - DRFS_TINFL_CR_RETURN_FOREVER(37, DRFS_TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((DRFS_MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(53, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const drfs_mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((drfs_drfs_mz_uint32 *)pOut_buf_cur)[0] = ((const drfs_drfs_mz_uint32 *)pSrc)[0]; - ((drfs_drfs_mz_uint32 *)pOut_buf_cur)[1] = ((const drfs_drfs_mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - if (decomp_flags & DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER) - { - DRFS_TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { drfs_mz_uint s; if (num_bits) DRFS_TINFL_GET_BITS(41, s, 8); else DRFS_TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } - } - DRFS_TINFL_CR_RETURN_FOREVER(34, DRFS_TINFL_STATUS_DONE); - DRFS_TINFL_CR_FINISH - -common_exit: - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER | DRFS_TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const drfs_mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - drfs_drfs_mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == DRFS_TINFL_STATUS_DONE) && (decomp_flags & DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = DRFS_TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -// Higher level helper functions. -void *drfs_tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - drfs_tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - drfs_tinfl_init(&decomp); - for ( ; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - drfs_tinfl_status status = drfs_tinfl_decompress(&decomp, (const drfs_mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (drfs_mz_uint8*)pBuf, pBuf ? (drfs_mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~DRFS_TINFL_FLAG_HAS_MORE_INPUT) | DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == DRFS_TINFL_STATUS_NEEDS_MORE_INPUT)) - { - DRFS_MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == DRFS_TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; - pNew_buf = DRFS_MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - DRFS_MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; - } - return pBuf; -} - -size_t drfs_tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - drfs_tinfl_decompressor decomp; drfs_tinfl_status status; drfs_tinfl_init(&decomp); - status = drfs_tinfl_decompress(&decomp, (const drfs_mz_uint8*)pSrc_buf, &src_buf_len, (drfs_mz_uint8*)pOut_buf, (drfs_mz_uint8*)pOut_buf, &out_buf_len, (flags & ~DRFS_TINFL_FLAG_HAS_MORE_INPUT) | DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != DRFS_TINFL_STATUS_DONE) ? DRFS_TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -} - -int drfs_tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - int result = 0; - drfs_tinfl_decompressor decomp; - drfs_mz_uint8 *pDict = (drfs_mz_uint8*)DRFS_MZ_MALLOC(DRFS_TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return DRFS_TINFL_STATUS_FAILED; - drfs_tinfl_init(&decomp); - for ( ; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = DRFS_TINFL_LZ_DICT_SIZE - dict_ofs; - drfs_tinfl_status status = drfs_tinfl_decompress(&decomp, (const drfs_mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(DRFS_TINFL_FLAG_HAS_MORE_INPUT | DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != DRFS_TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == DRFS_TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (DRFS_TINFL_LZ_DICT_SIZE - 1); - } - DRFS_MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; -} - - -// ------------------- .ZIP archive reading - -#ifndef DRFS_MINIZ_NO_ARCHIVE_APIS - -#define DRFS_MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - -// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. -enum -{ - // ZIP archive identifiers and record sizes - DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, - DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - // Central directory header record offsets - DRFS_MZ_ZIP_CDH_SIG_OFS = 0, DRFS_MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, DRFS_MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, DRFS_MZ_ZIP_CDH_BIT_FLAG_OFS = 8, - DRFS_MZ_ZIP_CDH_METHOD_OFS = 10, DRFS_MZ_ZIP_CDH_FILE_TIME_OFS = 12, DRFS_MZ_ZIP_CDH_FILE_DATE_OFS = 14, DRFS_MZ_ZIP_CDH_CRC32_OFS = 16, - DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, - DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, DRFS_MZ_ZIP_CDH_DISK_START_OFS = 34, DRFS_MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, DRFS_MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, DRFS_MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - // Local directory header offsets - DRFS_MZ_ZIP_LDH_SIG_OFS = 0, DRFS_MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, DRFS_MZ_ZIP_LDH_BIT_FLAG_OFS = 6, DRFS_MZ_ZIP_LDH_METHOD_OFS = 8, DRFS_MZ_ZIP_LDH_FILE_TIME_OFS = 10, - DRFS_MZ_ZIP_LDH_FILE_DATE_OFS = 12, DRFS_MZ_ZIP_LDH_CRC32_OFS = 14, DRFS_MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, DRFS_MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, - DRFS_MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, DRFS_MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, - // End of central directory offsets - DRFS_MZ_ZIP_ECDH_SIG_OFS = 0, DRFS_MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, DRFS_MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, DRFS_MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, - DRFS_MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, DRFS_MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, DRFS_MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, DRFS_MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -}; - -typedef struct -{ - void *m_p; - size_t m_size, m_capacity; - drfs_mz_uint m_element_size; -} drfs_mz_zip_array; - -struct drfs_mz_zip_internal_state_tag -{ - drfs_mz_zip_array m_central_dir; - drfs_mz_zip_array m_central_dir_offsets; - drfs_mz_zip_array m_sorted_central_dir_offsets; - void* *m_pFile; - void *m_pMem; - size_t m_mem_size; - size_t m_mem_capacity; -}; - -#define DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size -#define DRFS_MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] - -static DRFS_MZ_FORCEINLINE void drfs_mz_zip_array_clear(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray) -{ - pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); - memset(pArray, 0, sizeof(drfs_mz_zip_array)); -} - -static drfs_mz_bool drfs_mz_zip_array_ensure_capacity(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray, size_t min_new_capacity, drfs_mz_uint growing) -{ - void *pNew_p; size_t new_capacity = min_new_capacity; DRFS_MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return DRFS_MZ_TRUE; - if (growing) { new_capacity = DRFS_MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return DRFS_MZ_FALSE; - pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; - return DRFS_MZ_TRUE; -} - -static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_reserve(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray, size_t new_capacity, drfs_mz_uint growing) -{ - if (new_capacity > pArray->m_capacity) { if (!drfs_mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return DRFS_MZ_FALSE; } - return DRFS_MZ_TRUE; -} - -static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_resize(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray, size_t new_size, drfs_mz_uint growing) -{ - if (new_size > pArray->m_capacity) { if (!drfs_mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return DRFS_MZ_FALSE; } - pArray->m_size = new_size; - return DRFS_MZ_TRUE; -} - -static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_ensure_room(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray, size_t n) -{ - return drfs_mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, DRFS_MZ_TRUE); -} - -static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_push_back(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray, const void *pElements, size_t n) -{ - size_t orig_size = pArray->m_size; if (!drfs_mz_zip_array_resize(pZip, pArray, orig_size + n, DRFS_MZ_TRUE)) return DRFS_MZ_FALSE; - memcpy((drfs_mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); - return DRFS_MZ_TRUE; -} - -#ifndef DRFS_MINIZ_NO_TIME -static time_t drfs_mz_zip_dos_to_time_t(int dos_time, int dos_date) -{ - struct tm tm; - memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; - tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; - tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; - return mktime(&tm); -} -#endif - -static drfs_mz_bool drfs_mz_zip_reader_init_internal(drfs_mz_zip_archive *pZip, drfs_drfs_mz_uint32 flags) -{ - (void)flags; - if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_INVALID)) - return DRFS_MZ_FALSE; - - if (!pZip->m_pAlloc) pZip->m_pAlloc = drfs__def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = drfs__def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = drfs__def_realloc_func; - - pZip->m_zip_mode = DRFS_MZ_ZIP_MODE_READING; - pZip->m_archive_size = 0; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - - if (NULL == (pZip->m_pState = (drfs_mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(drfs_mz_zip_internal_state)))) - return DRFS_MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(drfs_mz_zip_internal_state)); - DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(drfs_mz_uint8)); - DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(drfs_drfs_mz_uint32)); - DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(drfs_drfs_mz_uint32)); - return DRFS_MZ_TRUE; -} - -static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_reader_filename_less(const drfs_mz_zip_array *pCentral_dir_array, const drfs_mz_zip_array *pCentral_dir_offsets, drfs_mz_uint l_index, drfs_mz_uint r_index) -{ - const drfs_mz_uint8 *pL = &DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, drfs_drfs_mz_uint32, l_index)), *pE; - const drfs_mz_uint8 *pR = &DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, drfs_drfs_mz_uint32, r_index)); - drfs_mz_uint l_len = DRFS_MZ_READ_LE16(pL + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = DRFS_MZ_READ_LE16(pR + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); - drfs_mz_uint8 l = 0, r = 0; - pL += DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + DRFS_MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = DRFS_MZ_TOLOWER(*pL)) != (r = DRFS_MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (l_len < r_len) : (l < r); -} - -#define DRFS_MZ_SWAP_UINT32(a, b) do { drfs_drfs_mz_uint32 t = a; a = b; b = t; } DRFS_MZ_MACRO_END - -// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by drfs_mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) -static void drfs_mz_zip_reader_sort_central_dir_offsets_by_filename(drfs_mz_zip_archive *pZip) -{ - drfs_mz_zip_internal_state *pState = pZip->m_pState; - const drfs_mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const drfs_mz_zip_array *pCentral_dir = &pState->m_central_dir; - drfs_drfs_mz_uint32 *pIndices = &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, drfs_drfs_mz_uint32, 0); - const int size = pZip->m_total_files; - int start = (size - 2) >> 1, end; - while (start >= 0) - { - int child, root = start; - for ( ; ; ) - { - if ((child = (root << 1) + 1) >= size) - break; - child += (((child + 1) < size) && (drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); - if (!drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - DRFS_MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - start--; - } - - end = size - 1; - while (end > 0) - { - int child, root = 0; - DRFS_MZ_SWAP_UINT32(pIndices[end], pIndices[0]); - for ( ; ; ) - { - if ((child = (root << 1) + 1) >= end) - break; - child += (((child + 1) < end) && drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); - if (!drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - DRFS_MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - end--; - } -} - -static drfs_mz_bool drfs_mz_zip_reader_read_central_dir(drfs_mz_zip_archive *pZip, drfs_drfs_mz_uint32 flags) -{ - drfs_mz_uint cdir_size, num_this_disk, cdir_disk_index; - drfs_mz_uint64 cdir_ofs; - drfs_mz_int64 cur_file_ofs; - const drfs_mz_uint8 *p; - drfs_drfs_mz_uint32 buf_u32[4096 / sizeof(drfs_drfs_mz_uint32)]; drfs_mz_uint8 *pBuf = (drfs_mz_uint8 *)buf_u32; - drfs_mz_bool sort_central_dir = ((flags & DRFS_MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); - // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. - if (pZip->m_archive_size < DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return DRFS_MZ_FALSE; - // Find the end of central directory record by scanning the file from the end towards the beginning. - cur_file_ofs = DRFS_MZ_MAX((drfs_mz_int64)pZip->m_archive_size - (drfs_mz_int64)sizeof(buf_u32), 0); - for ( ; ; ) - { - int i, n = (int)DRFS_MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (drfs_mz_uint)n) - return DRFS_MZ_FALSE; - for (i = n - 4; i >= 0; --i) - if (DRFS_MZ_READ_LE32(pBuf + i) == DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) - break; - if (i >= 0) - { - cur_file_ofs += i; - break; - } - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) - return DRFS_MZ_FALSE; - cur_file_ofs = DRFS_MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); - } - // Read and verify the end of central directory record. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return DRFS_MZ_FALSE; - if ((DRFS_MZ_READ_LE32(pBuf + DRFS_MZ_ZIP_ECDH_SIG_OFS) != DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || - ((pZip->m_total_files = DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) - return DRFS_MZ_FALSE; - - num_this_disk = DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); - cdir_disk_index = DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); - if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) - return DRFS_MZ_FALSE; - - if ((cdir_size = DRFS_MZ_READ_LE32(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) - return DRFS_MZ_FALSE; - - cdir_ofs = DRFS_MZ_READ_LE32(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_OFS_OFS); - if ((cdir_ofs + (drfs_mz_uint64)cdir_size) > pZip->m_archive_size) - return DRFS_MZ_FALSE; - - pZip->m_central_directory_file_ofs = cdir_ofs; - - if (pZip->m_total_files) - { - drfs_mz_uint i, n; - - // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. - if ((!drfs_mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, DRFS_MZ_FALSE)) || - (!drfs_mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, DRFS_MZ_FALSE))) - return DRFS_MZ_FALSE; - - if (sort_central_dir) - { - if (!drfs_mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, DRFS_MZ_FALSE)) - return DRFS_MZ_FALSE; - } - - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) - return DRFS_MZ_FALSE; - - // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). - p = (const drfs_mz_uint8 *)pZip->m_pState->m_central_dir.m_p; - for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) - { - drfs_mz_uint total_header_size, comp_size, decomp_size, disk_index; - if ((n < DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (DRFS_MZ_READ_LE32(p) != DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) - return DRFS_MZ_FALSE; - DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, i) = (drfs_drfs_mz_uint32)(p - (const drfs_mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - if (sort_central_dir) - DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, drfs_drfs_mz_uint32, i) = i; - comp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - decomp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - if (((!DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) - return DRFS_MZ_FALSE; - disk_index = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_DISK_START_OFS); - if ((disk_index != num_this_disk) && (disk_index != 1)) - return DRFS_MZ_FALSE; - if (((drfs_mz_uint64)DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_LOCAL_HEADER_OFS) + DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) - return DRFS_MZ_FALSE; - if ((total_header_size = DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS) + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS) + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) - return DRFS_MZ_FALSE; - n -= total_header_size; p += total_header_size; - } - } - - if (sort_central_dir) - drfs_mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - - return DRFS_MZ_TRUE; -} - -drfs_mz_bool drfs_mz_zip_reader_init(drfs_mz_zip_archive *pZip, drfs_mz_uint64 size, drfs_drfs_mz_uint32 flags) -{ - if ((!pZip) || (!pZip->m_pRead)) - return DRFS_MZ_FALSE; - if (!drfs_mz_zip_reader_init_internal(pZip, flags)) - return DRFS_MZ_FALSE; - pZip->m_archive_size = size; - if (!drfs_mz_zip_reader_read_central_dir(pZip, flags)) - { - drfs_mz_zip_reader_end(pZip); - return DRFS_MZ_FALSE; - } - return DRFS_MZ_TRUE; -} - -drfs_mz_uint drfs_mz_zip_reader_get_num_files(drfs_mz_zip_archive *pZip) -{ - return pZip ? pZip->m_total_files : 0; -} - -static DRFS_MZ_FORCEINLINE const drfs_mz_uint8 *drfs_mz_zip_reader_get_cdh(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index) -{ - if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_READING)) - return NULL; - return &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, file_index)); -} - -drfs_mz_bool drfs_mz_zip_reader_is_file_a_directory(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index) -{ - drfs_mz_uint filename_len, external_attr; - const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return DRFS_MZ_FALSE; - - // First see if the filename ends with a '/' character. - filename_len = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_len) - { - if (*(p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') - return DRFS_MZ_TRUE; - } - - // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. - // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. - // FIXME: Remove this check? Is it necessary - we already check the filename. - external_attr = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - if ((external_attr & 0x10) != 0) - return DRFS_MZ_TRUE; - - return DRFS_MZ_FALSE; -} - -drfs_mz_bool drfs_mz_zip_reader_file_stat(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, drfs_drfs_mz_zip_archive_file_stat *pStat) -{ - drfs_mz_uint n; - const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index); - if ((!p) || (!pStat)) - return DRFS_MZ_FALSE; - - // Unpack the central directory record. - pStat->m_file_index = file_index; - pStat->m_central_dir_ofs = DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, file_index); - pStat->m_version_made_by = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_VERSION_MADE_BY_OFS); - pStat->m_version_needed = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_VERSION_NEEDED_OFS); - pStat->m_bit_flag = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_BIT_FLAG_OFS); - pStat->m_method = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_METHOD_OFS); -#ifndef DRFS_MINIZ_NO_TIME - pStat->m_time = drfs_mz_zip_dos_to_time_t(DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILE_TIME_OFS), DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILE_DATE_OFS)); -#endif - pStat->m_crc32 = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_CRC32_OFS); - pStat->m_comp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - pStat->m_uncomp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - pStat->m_internal_attr = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_INTERNAL_ATTR_OFS); - pStat->m_external_attr = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - pStat->m_local_header_ofs = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_LOCAL_HEADER_OFS); - - // Copy as much of the filename and comment as possible. - n = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); n = DRFS_MZ_MIN(n, DRFS_MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); - memcpy(pStat->m_filename, p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; - - n = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS); n = DRFS_MZ_MIN(n, DRFS_MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); - pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS) + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; - - return DRFS_MZ_TRUE; -} - -drfs_mz_uint drfs_mz_zip_reader_get_filename(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, char *pFilename, drfs_mz_uint filename_buf_size) -{ - drfs_mz_uint n; - const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index); - if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } - n = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_buf_size) - { - n = DRFS_MZ_MIN(n, filename_buf_size - 1); - memcpy(pFilename, p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); - pFilename[n] = '\0'; - } - return n + 1; -} - -static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_reader_string_equal(const char *pA, const char *pB, drfs_mz_uint len, drfs_mz_uint flags) -{ - drfs_mz_uint i; - if (flags & DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE) - return 0 == memcmp(pA, pB, len); - for (i = 0; i < len; ++i) - if (DRFS_MZ_TOLOWER(pA[i]) != DRFS_MZ_TOLOWER(pB[i])) - return DRFS_MZ_FALSE; - return DRFS_MZ_TRUE; -} - -static DRFS_MZ_FORCEINLINE int drfs_mz_zip_reader_filename_compare(const drfs_mz_zip_array *pCentral_dir_array, const drfs_mz_zip_array *pCentral_dir_offsets, drfs_mz_uint l_index, const char *pR, drfs_mz_uint r_len) -{ - const drfs_mz_uint8 *pL = &DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, drfs_drfs_mz_uint32, l_index)), *pE; - drfs_mz_uint l_len = DRFS_MZ_READ_LE16(pL + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); - drfs_mz_uint8 l = 0, r = 0; - pL += DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + DRFS_MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = DRFS_MZ_TOLOWER(*pL)) != (r = DRFS_MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (int)(l_len - r_len) : (l - r); -} - -static int drfs_mz_zip_reader_locate_file_binary_search(drfs_mz_zip_archive *pZip, const char *pFilename) -{ - drfs_mz_zip_internal_state *pState = pZip->m_pState; - const drfs_mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const drfs_mz_zip_array *pCentral_dir = &pState->m_central_dir; - drfs_drfs_mz_uint32 *pIndices = &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, drfs_drfs_mz_uint32, 0); - const int size = pZip->m_total_files; - const drfs_mz_uint filename_len = (drfs_mz_uint)strlen(pFilename); - int l = 0, h = size - 1; - while (l <= h) - { - int m = (l + h) >> 1, file_index = pIndices[m], comp = drfs_mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); - if (!comp) - return file_index; - else if (comp < 0) - l = m + 1; - else - h = m - 1; - } - return -1; -} - -int drfs_mz_zip_reader_locate_file(drfs_mz_zip_archive *pZip, const char *pName, const char *pComment, drfs_mz_uint flags) -{ - drfs_mz_uint file_index; size_t name_len, comment_len; - if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_READING)) - return -1; - if (((flags & (DRFS_MZ_ZIP_FLAG_IGNORE_PATH | DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) - return drfs_mz_zip_reader_locate_file_binary_search(pZip, pName); - name_len = strlen(pName); if (name_len > 0xFFFF) return -1; - comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; - for (file_index = 0; file_index < pZip->m_total_files; file_index++) - { - const drfs_mz_uint8 *pHeader = &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, file_index)); - drfs_mz_uint filename_len = DRFS_MZ_READ_LE16(pHeader + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); - const char *pFilename = (const char *)pHeader + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - if (filename_len < name_len) - continue; - if (comment_len) - { - drfs_mz_uint file_extra_len = DRFS_MZ_READ_LE16(pHeader + DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = DRFS_MZ_READ_LE16(pHeader + DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS); - const char *pFile_comment = pFilename + filename_len + file_extra_len; - if ((file_comment_len != comment_len) || (!drfs_mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) - continue; - } - if ((flags & DRFS_MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) - { - int ofs = filename_len - 1; - do - { - if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) - break; - } while (--ofs >= 0); - ofs++; - pFilename += ofs; filename_len -= ofs; - } - if ((filename_len == name_len) && (drfs_mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) - return file_index; - } - return -1; -} - -drfs_mz_bool drfs_mz_zip_reader_extract_to_mem_no_alloc(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, void *pBuf, size_t buf_size, drfs_mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int status = DRFS_TINFL_STATUS_DONE; - drfs_mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; - drfs_drfs_mz_zip_archive_file_stat file_stat; - void *pRead_buf; - drfs_drfs_mz_uint32 local_header_u32[(DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(drfs_drfs_mz_uint32) - 1) / sizeof(drfs_drfs_mz_uint32)]; drfs_mz_uint8 *pLocal_header = (drfs_mz_uint8 *)local_header_u32; - drfs_tinfl_decompressor inflator; - - if ((buf_size) && (!pBuf)) - return DRFS_MZ_FALSE; - - if (!drfs_mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return DRFS_MZ_FALSE; - - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) - if (!file_stat.m_comp_size) - return DRFS_MZ_TRUE; - - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? - if (drfs_mz_zip_reader_is_file_a_directory(pZip, file_index)) - return DRFS_MZ_TRUE; - - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return DRFS_MZ_FALSE; - - // This function only supports stored and deflate. - if ((!(flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != DRFS_MZ_DEFLATED)) - return DRFS_MZ_FALSE; - - // Ensure supplied output buffer is large enough. - needed_size = (flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; - if (buf_size < needed_size) - return DRFS_MZ_FALSE; - - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return DRFS_MZ_FALSE; - if (DRFS_MZ_READ_LE32(pLocal_header) != DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return DRFS_MZ_FALSE; - - cur_file_ofs += DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE + DRFS_MZ_READ_LE16(pLocal_header + DRFS_MZ_ZIP_LDH_FILENAME_LEN_OFS) + DRFS_MZ_READ_LE16(pLocal_header + DRFS_MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return DRFS_MZ_FALSE; - - if ((flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) - return DRFS_MZ_FALSE; - return ((flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (drfs_mz_crc32(DRFS_MZ_CRC32_INIT, (const drfs_mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); - } - - // Decompress the file either directly from memory or from a file input buffer. - drfs_tinfl_init(&inflator); - - if (pZip->m_pState->m_pMem) - { - // Read directly from the archive in memory. - pRead_buf = (drfs_mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else if (pUser_read_buf) - { - // Use a user provided read buffer. - if (!user_read_buf_size) - return DRFS_MZ_FALSE; - pRead_buf = (drfs_mz_uint8 *)pUser_read_buf; - read_buf_size = user_read_buf_size; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - else - { - // Temporarily allocate a read buffer. - read_buf_size = DRFS_MZ_MIN(file_stat.m_comp_size, DRFS_MZ_ZIP_MAX_IO_BUF_SIZE); -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(drfs_drfs_mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(drfs_drfs_mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#endif - return DRFS_MZ_FALSE; - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return DRFS_MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - do - { - size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = DRFS_MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = DRFS_TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - in_buf_size = (size_t)read_buf_avail; - status = drfs_tinfl_decompress(&inflator, (drfs_mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (drfs_mz_uint8 *)pBuf, (drfs_mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? DRFS_TINFL_FLAG_HAS_MORE_INPUT : 0)); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - out_buf_ofs += out_buf_size; - } while (status == DRFS_TINFL_STATUS_NEEDS_MORE_INPUT); - - if (status == DRFS_TINFL_STATUS_DONE) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (drfs_mz_crc32(DRFS_MZ_CRC32_INIT, (const drfs_mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) - status = DRFS_TINFL_STATUS_FAILED; - } - - if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - - return status == DRFS_TINFL_STATUS_DONE; -} - -drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem_no_alloc(drfs_mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, drfs_mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int file_index = drfs_mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return DRFS_MZ_FALSE; - return drfs_mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -} - -drfs_mz_bool drfs_mz_zip_reader_extract_to_mem(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, void *pBuf, size_t buf_size, drfs_mz_uint flags) -{ - return drfs_mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -} - -drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem(drfs_mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, drfs_mz_uint flags) -{ - return drfs_mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -} - -void *drfs_mz_zip_reader_extract_to_heap(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, size_t *pSize, drfs_mz_uint flags) -{ - drfs_mz_uint64 comp_size, uncomp_size, alloc_size; - const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index); - void *pBuf; - - if (pSize) - *pSize = 0; - if (!p) - return NULL; - - comp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - uncomp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - - alloc_size = (flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(drfs_drfs_mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(drfs_drfs_mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#endif - return NULL; - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) - return NULL; - - if (!drfs_mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return NULL; - } - - if (pSize) *pSize = (size_t)alloc_size; - return pBuf; -} - -drfs_mz_bool drfs_mz_zip_reader_end(drfs_mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_READING)) - return DRFS_MZ_FALSE; - - if (pZip->m_pState) - { - drfs_mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; - drfs_mz_zip_array_clear(pZip, &pState->m_central_dir); - drfs_mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - drfs_mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - } - pZip->m_zip_mode = DRFS_MZ_ZIP_MODE_INVALID; - - return DRFS_MZ_TRUE; -} - -#endif // #ifndef DRFS_MINIZ_NO_ARCHIVE_APIS - -#ifdef __cplusplus -} -#endif - -#endif // DRFS_MINIZ_HEADER_FILE_ONLY - -#if defined(__GNUC__) - #pragma GCC diagnostic pop -#endif -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - - - - -typedef struct -{ - // The current index of the iterator. When this hits the file count, the iteration is finished. - unsigned int index; - - // The directory being iterated. - char directoryPath[DRFS_MAX_PATH]; - -}drfs_iterator_zip; - -typedef struct -{ - // The file index within the archive. - drfs_mz_uint index; - - // A pointer to the buffer containing the entire uncompressed data of the file. Unfortunately this is the only way I'm aware of for - // reading file data from miniz.c so we'll just stick with it for now. We use a pointer to an 8-bit type so we can easily calculate - // offsets. - drfs_mz_uint8* pData; - - // The size of the file in bytes so we can guard against overflowing reads. - size_t sizeInBytes; - - // The current position of the file's read pointer. - size_t readPointer; - -}drfs_openedfile_zip; - -static size_t drfs_drfs_mz_file_read_func(void *pOpaque, drfs_mz_uint64 file_ofs, void *pBuf, size_t n) -{ - // The opaque type is a pointer to a drfs_file object which represents the file of the archive. - drfs_file* pZipFile = (drfs_file*)pOpaque; - assert(pZipFile != NULL); - - if (!drfs_lock(pZipFile)) { - return 0; - } - - drfs_seek_nolock(pZipFile, (dr_int64)file_ofs, drfs_origin_start); - - size_t bytesRead; - drfs_result result = drfs_read_nolock(pZipFile, pBuf, (unsigned int)n, &bytesRead); - if (result != drfs_success) { - // Failed to read the file. - bytesRead = 0; - } - - drfs_unlock(pZipFile); - return (size_t)bytesRead; -} - - -static dr_bool32 drfs_is_valid_extension__zip(const char* extension) -{ - return drfs__stricmp(extension, "zip") == 0; -} - -static drfs_result drfs_open_archive__zip(drfs_file* pArchiveFile, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(pArchiveFile != NULL); - assert(pHandleOut != NULL); - assert(drfs_tell(pArchiveFile) == 0); - - *pHandleOut = NULL; - - // Only support read-only mode at the moment. - if ((accessMode & DRFS_WRITE) != 0) { - return drfs_permission_denied; - } - - - drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)malloc(sizeof(drfs_mz_zip_archive)); - if (pZip == NULL) { - return drfs_out_of_memory; - } - - memset(pZip, 0, sizeof(drfs_mz_zip_archive)); - - pZip->m_pRead = drfs_drfs_mz_file_read_func; - pZip->m_pIO_opaque = pArchiveFile; - if (!drfs_mz_zip_reader_init(pZip, drfs_size(pArchiveFile), 0)) { - free(pZip); - return drfs_invalid_archive; - } - - *pHandleOut = pZip; - return drfs_success; -} - -static void drfs_close_archive__zip(drfs_handle archive) -{ - assert(archive != NULL); - - drfs_mz_zip_reader_end((drfs_mz_zip_archive*)archive); - free(archive); -} - -static drfs_result drfs_get_file_info__zip(drfs_handle archive, const char* relativePath, drfs_file_info* fi) -{ - assert(archive != NULL); - - drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive; - int fileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath, NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE); - if (fileIndex == -1) - { - // We failed to locate the file, but there's a chance it could actually be a folder. Here's the problem - folders - // can be named such that they include a trailing slash. We'll want to check for that. Another problem is that - // sometimes the folders won't actually be included in the central directory at all which means we need to do a - // manual check across every file in the archive. - char relativePathWithSlash[DRFS_MAX_PATH]; - drfs__strcpy_s(relativePathWithSlash, sizeof(relativePathWithSlash), relativePath); - drfs__strcat_s(relativePathWithSlash, sizeof(relativePathWithSlash), "/"); - fileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath, NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE); - if (fileIndex == -1) - { - // We still couldn't find the directory even with the trailing slash. There's a chace it's a folder that's - // simply not included in the central directory. It's appears the "Send to -> Compressed (zipped) folder" - // functionality in Windows does this. - drfs_mz_uint numFiles = drfs_mz_zip_reader_get_num_files(pZip); - for (drfs_mz_uint iFile = 0; iFile < numFiles; ++iFile) - { - char filePath[DRFS_MAX_PATH]; - if (drfs_mz_zip_reader_get_filename(pZip, iFile, filePath, DRFS_MAX_PATH) > 0) - { - if (drfs_drpath_is_child(filePath, relativePath)) - { - // This file is within a folder with a path of relativePath which means we can imply that relativePath - // is a folder. - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), relativePath); - fi->sizeInBytes = 0; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY | DRFS_FILE_ATTRIBUTE_DIRECTORY; - - return drfs_success; - } - } - } - - return drfs_does_not_exist; - } - } - - assert(fileIndex != -1); - - if (fi != NULL) - { - drfs_drfs_mz_zip_archive_file_stat zipStat; - if (drfs_mz_zip_reader_file_stat(pZip, (drfs_mz_uint)fileIndex, &zipStat)) - { - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), relativePath); - fi->sizeInBytes = zipStat.m_uncomp_size; - fi->lastModifiedTime = (dr_uint64)zipStat.m_time; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY; - if (drfs_mz_zip_reader_is_file_a_directory(pZip, (drfs_mz_uint)fileIndex)) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_DIRECTORY; - } - - return drfs_success; - } - } - - return drfs_success; -} - -static drfs_handle drfs_begin_iteration__zip(drfs_handle archive, const char* relativePath) -{ - assert(relativePath != NULL); - - drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive; - assert(pZip != NULL); - - int directoryFileIndex = -1; - if (relativePath[0] == '\0') { - directoryFileIndex = 0; - } else { - directoryFileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath, NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE); - } - - if (directoryFileIndex == -1) - { - // The same issue applies here as documented in drfs_get_file_info__zip(). - char relativePathWithSlash[DRFS_MAX_PATH]; - drfs__strcpy_s(relativePathWithSlash, sizeof(relativePathWithSlash), relativePath); - drfs__strcat_s(relativePathWithSlash, sizeof(relativePathWithSlash), "/"); - directoryFileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath, NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE); - if (directoryFileIndex == -1) - { - // We still couldn't find the directory even with the trailing slash. There's a chace it's a folder that's - // simply not included in the central directory. It's appears the "Send to -> Compressed (zipped) folder" - // functionality in Windows does this. - drfs_mz_uint numFiles = drfs_mz_zip_reader_get_num_files(pZip); - for (drfs_mz_uint iFile = 0; iFile < numFiles; ++iFile) - { - char filePath[DRFS_MAX_PATH]; - if (drfs_mz_zip_reader_get_filename(pZip, iFile, filePath, DRFS_MAX_PATH) > 0) - { - if (drfs_drpath_is_child(filePath, relativePath)) - { - // This file is within a folder with a path of relativePath which means we can imply that relativePath - // is a folder. - goto on_success; - } - } - } - - return NULL; - } - } - - - -on_success:; - drfs_iterator_zip* pZipIterator = (drfs_iterator_zip*)malloc(sizeof(drfs_iterator_zip)); - if (pZipIterator != NULL) - { - pZipIterator->index = 0; - drfs__strcpy_s(pZipIterator->directoryPath, sizeof(pZipIterator->directoryPath), relativePath); - } - - return pZipIterator; -} - -static void drfs_end_iteration__zip(drfs_handle archive, drfs_handle iterator) -{ - (void)archive; - assert(archive != NULL); - assert(iterator != NULL); - - free(iterator); -} - -static dr_bool32 drfs_next_iteration__zip(drfs_handle archive, drfs_handle iterator, drfs_file_info* fi) -{ - (void)archive; - assert(archive != NULL); - assert(iterator != NULL); - - drfs_iterator_zip* pZipIterator = (drfs_iterator_zip*)iterator; - if (pZipIterator == NULL) { - return DR_FALSE; - } - - drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive; - while (pZipIterator->index < drfs_mz_zip_reader_get_num_files(pZip)) - { - unsigned int iFile = pZipIterator->index++; - - char filePath[DRFS_MAX_PATH]; - if (drfs_mz_zip_reader_get_filename(pZip, iFile, filePath, DRFS_MAX_PATH) > 0) - { - if (drfs_drpath_is_child(filePath, pZipIterator->directoryPath)) - { - if (fi != NULL) - { - drfs_drfs_mz_zip_archive_file_stat zipStat; - if (drfs_mz_zip_reader_file_stat(pZip, iFile, &zipStat)) - { - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), filePath); - fi->sizeInBytes = zipStat.m_uncomp_size; - fi->lastModifiedTime = (dr_uint64)zipStat.m_time; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY; - if (drfs_mz_zip_reader_is_file_a_directory(pZip, iFile)) { - fi->attributes |= DRFS_FILE_ATTRIBUTE_DIRECTORY; - } - - // If we have a directory we need to ensure we don't have a trailing slash. - if ((fi->attributes & DRFS_FILE_ATTRIBUTE_DIRECTORY) != 0) { - size_t absolutePathLen = strlen(fi->absolutePath); - if (absolutePathLen > 0 && (fi->absolutePath[absolutePathLen - 1] == '/' || fi->absolutePath[absolutePathLen - 1] == '\\')) { - fi->absolutePath[absolutePathLen - 1] = '\0'; - } - } - } - } - - return DR_TRUE; - } - } - } - - return DR_FALSE; -} - -static drfs_result drfs_open_file__zip(drfs_handle archive, const char* relativePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(archive != NULL); - assert(pHandleOut != NULL); - assert(relativePath != NULL); - - *pHandleOut = NULL; - - // Only supporting read-only for now. - if ((accessMode & DRFS_WRITE) != 0) { - return drfs_permission_denied; - } - - - drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive; - int fileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath, NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE); - if (fileIndex == -1) { - return drfs_does_not_exist; - } - - drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)malloc(sizeof(*pOpenedFile)); - if (pOpenedFile == NULL) { - return drfs_out_of_memory; - } - - pOpenedFile->pData = (drfs_mz_uint8*)drfs_mz_zip_reader_extract_to_heap(pZip, (drfs_mz_uint)fileIndex, &pOpenedFile->sizeInBytes, 0); - if (pOpenedFile->pData == NULL) { - free(pOpenedFile); - return drfs_unknown_error; - } - - pOpenedFile->index = (drfs_mz_uint)fileIndex; - pOpenedFile->readPointer = 0; - - *pHandleOut = pOpenedFile; - return drfs_success; -} - -static void drfs_close_file__zip(drfs_handle archive, drfs_handle file) -{ - drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file; - assert(pOpenedFile != NULL); - - drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive; - assert(pZip != NULL); - - pZip->m_pFree(pZip->m_pAlloc_opaque, pOpenedFile->pData); - free(pOpenedFile); -} - -static drfs_result drfs_read_file__zip(drfs_handle archive, drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - (void)archive; - assert(archive != NULL); - assert(file != NULL); - assert(pDataOut != NULL); - assert(bytesToRead > 0); - - drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file; - if (pOpenedFile == NULL) { - return drfs_invalid_args; - } - - size_t bytesAvailable = pOpenedFile->sizeInBytes - pOpenedFile->readPointer; - if (bytesAvailable < bytesToRead) { - bytesToRead = bytesAvailable; - } - - if (bytesToRead == 0) { - return drfs_at_end_of_file; // Nothing left to read. - } - - - memcpy(pDataOut, pOpenedFile->pData + pOpenedFile->readPointer, bytesToRead); - pOpenedFile->readPointer += bytesToRead; - - if (pBytesReadOut) { - *pBytesReadOut = bytesToRead; - } - - return drfs_success; -} - -static drfs_result drfs_write_file__zip(drfs_handle archive, drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - (void)archive; - (void)file; - (void)pData; - (void)bytesToWrite; - - assert(archive != NULL); - assert(file != NULL); - assert(pData != NULL); - assert(bytesToWrite > 0); - - // All files are read-only for now. - if (pBytesWrittenOut) { - *pBytesWrittenOut = 0; - } - - return drfs_permission_denied; -} - -static drfs_result drfs_seek_file__zip(drfs_handle archive, drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - (void)archive; - - assert(archive != NULL); - assert(file != NULL); - - drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file; - if (pOpenedFile == NULL) { - return drfs_invalid_args; - } - - dr_uint64 newPos = pOpenedFile->readPointer; - if (origin == drfs_origin_current) - { - if ((dr_int64)newPos + bytesToSeek >= 0) - { - newPos = (dr_uint64)((dr_int64)newPos + bytesToSeek); - } - else - { - // Trying to seek to before the beginning of the file. - return drfs_invalid_args; - } - } - else if (origin == drfs_origin_start) - { - assert(bytesToSeek >= 0); - newPos = (dr_uint64)bytesToSeek; - } - else if (origin == drfs_origin_end) - { - assert(bytesToSeek >= 0); - if ((dr_uint64)bytesToSeek <= pOpenedFile->sizeInBytes) - { - newPos = pOpenedFile->sizeInBytes - (dr_uint64)bytesToSeek; - } - else - { - // Trying to seek to before the beginning of the file. - return drfs_invalid_args; - } - } - else - { - // Should never get here. - return drfs_unknown_error; - } - - - if (newPos > pOpenedFile->sizeInBytes) { - return drfs_invalid_args; - } - - pOpenedFile->readPointer = (size_t)newPos; - return drfs_success; -} - -static dr_uint64 drfs_tell_file__zip(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file; - assert(pOpenedFile != NULL); - - return pOpenedFile->readPointer; -} - -static dr_uint64 drfs_file_size__zip(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file; - assert(pOpenedFile != NULL); - - return pOpenedFile->sizeInBytes; -} - -static void drfs_flush__zip(drfs_handle archive, drfs_handle file) -{ - (void)archive; - (void)file; - - assert(archive != NULL); - assert(file != NULL); - - // All files are read-only for now. -} - - -static void drfs_register_zip_backend(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drfs_archive_callbacks callbacks; - callbacks.is_valid_extension = drfs_is_valid_extension__zip; - callbacks.open_archive = drfs_open_archive__zip; - callbacks.close_archive = drfs_close_archive__zip; - callbacks.get_file_info = drfs_get_file_info__zip; - callbacks.begin_iteration = drfs_begin_iteration__zip; - callbacks.end_iteration = drfs_end_iteration__zip; - callbacks.next_iteration = drfs_next_iteration__zip; - callbacks.delete_file = NULL; - callbacks.move_file = NULL; - callbacks.create_directory = NULL; - callbacks.copy_file = NULL; - callbacks.open_file = drfs_open_file__zip; - callbacks.close_file = drfs_close_file__zip; - callbacks.read_file = drfs_read_file__zip; - callbacks.write_file = drfs_write_file__zip; - callbacks.seek_file = drfs_seek_file__zip; - callbacks.tell_file = drfs_tell_file__zip; - callbacks.file_size = drfs_file_size__zip; - callbacks.flush_file = drfs_flush__zip; - drfs_register_archive_backend(pContext, callbacks); -} -#endif //DR_FS_NO_ZIP - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Quake 2 PAK -// -/////////////////////////////////////////////////////////////////////////////// -#ifndef DR_FS_NO_PAK -typedef struct -{ - char path[64]; - -}drfs_path_pak; - -typedef struct -{ - // The file name. - char name[56]; - - // The position within the file of the first byte of the file. - unsigned int offset; - - // The size of the file, in bytes. - unsigned int sizeInBytes; - -}drfs_file_pak; - -typedef struct -{ - // A pointer to the archive file for reading data. - drfs_file* pArchiveFile; - - - // The 4-byte identifiers: "PACK" - char id[4]; - - // The offset of the directory. - unsigned int directoryOffset; - - // The size of the directory. This should a multiple of 64. - unsigned int directoryLength; - - - // The access mode. - unsigned int accessMode; - - // A pointer to the buffer containing the file information. The number of items in this array is equal to directoryLength / 64. - drfs_file_pak* pFiles; - -}drfs_archive_pak; - - -typedef struct -{ - // The current index of the iterator. When this hits childCount, the iteration is finished. - unsigned int index; - - // The directory being iterated. - char directoryPath[DRFS_MAX_PATH]; - - - // The number of directories that have previously been iterated. - unsigned int processedDirCount; - - // The directories that were previously iterated. - drfs_path_pak* pProcessedDirs; - -}drfs_iterator_pak; - -static dr_bool32 drfs_iterator_pak_append_processed_dir(drfs_iterator_pak* pIterator, const char* path) -{ - if (pIterator != NULL && path != NULL) - { - drfs_path_pak* pOldBuffer = pIterator->pProcessedDirs; - drfs_path_pak* pNewBuffer = (drfs_path_pak*)malloc(sizeof(drfs_path_pak) * (pIterator->processedDirCount + 1)); - - if (pNewBuffer != 0) - { - for (unsigned int iDst = 0; iDst < pIterator->processedDirCount; ++iDst) - { - pNewBuffer[iDst] = pOldBuffer[iDst]; - } - - drfs__strcpy_s(pNewBuffer[pIterator->processedDirCount].path, 64, path); - - - pIterator->pProcessedDirs = pNewBuffer; - pIterator->processedDirCount += 1; - - drfs_free(pOldBuffer); - - return 1; - } - } - - return 0; -} - -static dr_bool32 drfs_iterator_pak_has_dir_been_processed(drfs_iterator_pak* pIterator, const char* path) -{ - for (unsigned int i = 0; i < pIterator->processedDirCount; ++i) - { - if (strcmp(path, pIterator->pProcessedDirs[i].path) == 0) - { - return 1; - } - } - - return 0; -} - - -typedef struct -{ - // The offset of the first byte of the file's data. - size_t offsetInArchive; - - // The size of the file in bytes so we can guard against overflowing reads. - size_t sizeInBytes; - - // The current position of the file's read pointer. - size_t readPointer; - -}drfs_openedfile_pak; - - - -static drfs_archive_pak* drfs_pak_create(drfs_file* pArchiveFile, unsigned int accessMode) -{ - drfs_archive_pak* pak = (drfs_archive_pak*)malloc(sizeof(*pak)); - if (pak != NULL) - { - pak->pArchiveFile = pArchiveFile; - pak->directoryOffset = 0; - pak->directoryLength = 0; - pak->accessMode = accessMode; - pak->pFiles = NULL; - } - - return pak; -} - -static void drfs_pak_delete(drfs_archive_pak* pArchive) -{ - free(pArchive->pFiles); - free(pArchive); -} - - - - -static dr_bool32 drfs_is_valid_extension__pak(const char* extension) -{ - return drfs__stricmp(extension, "pak") == 0; -} - - -static drfs_result drfs_open_archive__pak(drfs_file* pArchiveFile, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(pArchiveFile != NULL); - assert(pHandleOut != NULL); - assert(drfs_tell(pArchiveFile) == 0); - - *pHandleOut = NULL; - - if (!drfs_lock(pArchiveFile)) { - return drfs_unknown_error; - } - - drfs_result result = drfs_success; - drfs_archive_pak* pak = drfs_pak_create(pArchiveFile, accessMode); - if (pak != NULL) - { - // First 4 bytes should equal "PACK" - if (drfs_read_nolock(pArchiveFile, pak->id, 4, NULL) == drfs_success) - { - if (pak->id[0] == 'P' && pak->id[1] == 'A' && pak->id[2] == 'C' && pak->id[3] == 'K') - { - if (drfs_read_nolock(pArchiveFile, &pak->directoryOffset, 4, NULL) == drfs_success) - { - if (drfs_read_nolock(pArchiveFile, &pak->directoryLength, 4, NULL) == drfs_success) - { - // We loaded the header just fine so now we want to allocate space for each file in the directory and load them. Note that - // this does not load the file data itself, just information about the files like their name and size. - if (pak->directoryLength % 64 == 0) - { - unsigned int fileCount = pak->directoryLength / 64; - if (fileCount > 0) - { - assert((sizeof(drfs_file_pak) * fileCount) == pak->directoryLength); - - pak->pFiles = (drfs_file_pak*)malloc(pak->directoryLength); - if (pak->pFiles != NULL) - { - // Seek to the directory listing before trying to read it. - if (drfs_seek_nolock(pArchiveFile, pak->directoryOffset, drfs_origin_start) == drfs_success) - { - size_t bytesRead; - if (drfs_read_nolock(pArchiveFile, pak->pFiles, pak->directoryLength, &bytesRead) == drfs_success && bytesRead == pak->directoryLength) - { - // All good! - } - else - { - // Failed to read the directory listing. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - else - { - // Failed to seek to the directory listing. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - else - { - // Failed to allocate memory for the file info buffer. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_out_of_memory; - } - } - } - else - { - // The directory length is not a multiple of 64 - something is wrong with the file. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - else - { - // Failed to read the directory length. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - else - { - // Failed to read the directory offset. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - else - { - // Not a pak file. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - else - { - // Failed to read the header. - drfs_pak_delete(pak); - pak = NULL; - result = drfs_invalid_archive; - } - } - - drfs_unlock(pArchiveFile); - *pHandleOut = pak; - return result; -} - -static void drfs_close_archive__pak(drfs_handle archive) -{ - drfs_archive_pak* pPak = (drfs_archive_pak*)archive; - assert(pPak != NULL); - - drfs_pak_delete(pPak); -} - -static drfs_result drfs_get_file_info__pak(drfs_handle archive, const char* relativePath, drfs_file_info* fi) -{ - // We can determine whether or not the path refers to a file or folder by checking it the path is parent of any - // files in the archive. If so, it's a folder, otherwise it's a file (so long as it exists). - drfs_archive_pak* pak = (drfs_archive_pak*)archive; - assert(pak != NULL); - - unsigned int fileCount = pak->directoryLength / 64; - for (unsigned int i = 0; i < fileCount; ++i) - { - drfs_file_pak* pFile = pak->pFiles + i; - if (strcmp(pFile->name, relativePath) == 0) - { - // It's a file. - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), relativePath); - fi->sizeInBytes = (dr_uint64)pFile->sizeInBytes; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY; - - return drfs_success; - } - else if (drfs_drpath_is_descendant(pFile->name, relativePath)) - { - // It's a directory. - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), relativePath); - fi->sizeInBytes = 0; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY | DRFS_FILE_ATTRIBUTE_DIRECTORY; - - return drfs_success; - } - } - - return drfs_does_not_exist; -} - -static drfs_handle drfs_begin_iteration__pak(drfs_handle archive, const char* relativePath) -{ - (void)archive; - assert(relativePath != NULL); - - drfs_iterator_pak* pIterator = (drfs_iterator_pak*)malloc(sizeof(drfs_iterator_pak)); - if (pIterator != NULL) - { - pIterator->index = 0; - drfs__strcpy_s(pIterator->directoryPath, sizeof(pIterator->directoryPath), relativePath); - pIterator->processedDirCount = 0; - pIterator->pProcessedDirs = NULL; - } - - return pIterator; -} - -static void drfs_end_iteration__pak(drfs_handle archive, drfs_handle iterator) -{ - (void)archive; - - drfs_iterator_pak* pIterator = (drfs_iterator_pak*)iterator; - assert(pIterator != NULL); - - free(pIterator); -} - -static dr_bool32 drfs_next_iteration__pak(drfs_handle archive, drfs_handle iterator, drfs_file_info* fi) -{ - drfs_iterator_pak* pIterator = (drfs_iterator_pak*)iterator; - assert(pIterator != NULL); - - drfs_archive_pak* pak = (drfs_archive_pak*)archive; - assert(pak != NULL); - - unsigned int fileCount = pak->directoryLength / 64; - while (pIterator->index < fileCount) - { - unsigned int iFile = pIterator->index++; - - drfs_file_pak* pFile = pak->pFiles + iFile; - if (drfs_drpath_is_child(pFile->name, pIterator->directoryPath)) - { - // It's a file. - drfs__strcpy_s(fi->absolutePath, DRFS_MAX_PATH, pFile->name); - fi->sizeInBytes = (dr_uint64)pFile->sizeInBytes; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY; - - return DR_TRUE; - } - else if (drfs_drpath_is_descendant(pFile->name, pIterator->directoryPath)) - { - // It's a directory. This needs special handling because we don't want to iterate over the same directory multiple times. - const char* childDirEnd = pFile->name + strlen(pIterator->directoryPath) + 1; // +1 for the slash. - while (childDirEnd[0] != '\0' && childDirEnd[0] != '/' && childDirEnd[0] != '\\') - { - childDirEnd += 1; - } - - char childDir[64]; - memcpy(childDir, pFile->name, childDirEnd - pFile->name); - childDir[childDirEnd - pFile->name] = '\0'; - - if (!drfs_iterator_pak_has_dir_been_processed(pIterator, childDir)) - { - // It's a directory. - drfs__strcpy_s(fi->absolutePath, DRFS_MAX_PATH, childDir); - fi->sizeInBytes = 0; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY | DRFS_FILE_ATTRIBUTE_DIRECTORY; - - drfs_iterator_pak_append_processed_dir(pIterator, childDir); - - return DR_TRUE; - } - } - } - - return DR_FALSE; -} - -static drfs_result drfs_open_file__pak(drfs_handle archive, const char* relativePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(relativePath != NULL); - assert(pHandleOut != NULL); - - // Only supporting read-only for now. - if ((accessMode & DRFS_WRITE) != 0) { - return drfs_permission_denied; - } - - - drfs_archive_pak* pak = (drfs_archive_pak*)archive; - assert(pak != NULL); - - for (unsigned int iFile = 0; iFile < (pak->directoryLength / 64); ++iFile) - { - if (strcmp(relativePath, pak->pFiles[iFile].name) == 0) - { - // We found the file. - drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)malloc(sizeof(*pOpenedFile)); - if (pOpenedFile != NULL) - { - pOpenedFile->offsetInArchive = pak->pFiles[iFile].offset; - pOpenedFile->sizeInBytes = pak->pFiles[iFile].sizeInBytes; - pOpenedFile->readPointer = 0; - - *pHandleOut = pOpenedFile; - return drfs_success; - } - } - } - - - return drfs_does_not_exist; -} - -static void drfs_close_file__pak(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file; - assert(pOpenedFile != NULL); - - free(pOpenedFile); -} - -static drfs_result drfs_read_file__pak(drfs_handle archive, drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - assert(pDataOut != NULL); - assert(bytesToRead > 0); - - drfs_archive_pak* pak = (drfs_archive_pak*)archive; - assert(pak != NULL); - - drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file; - assert(pOpenedFile != NULL); - - // The read pointer should never go past the file size. - assert(pOpenedFile->sizeInBytes >= pOpenedFile->readPointer); - - - size_t bytesAvailable = pOpenedFile->sizeInBytes - pOpenedFile->readPointer; - if (bytesAvailable < bytesToRead) { - bytesToRead = bytesAvailable; // Safe cast, as per the check above. - } - - if (!drfs_lock(pak->pArchiveFile)) { - return drfs_unknown_error; - } - - drfs_seek_nolock(pak->pArchiveFile, (dr_int64)(pOpenedFile->offsetInArchive + pOpenedFile->readPointer), drfs_origin_start); - drfs_result result = drfs_read_nolock(pak->pArchiveFile, pDataOut, bytesToRead, pBytesReadOut); - if (result == drfs_success) { - pOpenedFile->readPointer += bytesToRead; - } - - drfs_unlock(pak->pArchiveFile); - return result; -} - -static drfs_result drfs_write_file__pak(drfs_handle archive, drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - (void)archive; - (void)file; - (void)pData; - (void)bytesToWrite; - - assert(archive != NULL); - assert(file != NULL); - assert(pData != NULL); - assert(bytesToWrite > 0); - - // All files are read-only for now. - if (pBytesWrittenOut) { - *pBytesWrittenOut = 0; - } - - return drfs_permission_denied; -} - -static drfs_result drfs_seek_file__pak(drfs_handle archive, drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - (void)archive; - - drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file; - assert(pOpenedFile != NULL); - - dr_uint64 newPos = pOpenedFile->readPointer; - if (origin == drfs_origin_current) { - if ((dr_int64)newPos + bytesToSeek >= 0) { - newPos = (dr_uint64)((dr_int64)newPos + bytesToSeek); - } else { - return drfs_invalid_args; // Trying to seek to before the beginning of the file. - } - } else if (origin == drfs_origin_start) { - assert(bytesToSeek >= 0); - newPos = (dr_uint64)bytesToSeek; - } else if (origin == drfs_origin_end) { - assert(bytesToSeek >= 0); - if ((dr_uint64)bytesToSeek <= pOpenedFile->sizeInBytes) { - newPos = pOpenedFile->sizeInBytes - (dr_uint64)bytesToSeek; - } else { - return drfs_invalid_args; // Trying to seek to before the beginning of the file. - } - } else { - return drfs_unknown_error; // Should never get here. - } - - - if (newPos > pOpenedFile->sizeInBytes) { - return drfs_invalid_args; - } - - pOpenedFile->readPointer = (size_t)newPos; - return drfs_success; -} - -static dr_uint64 drfs_tell_file__pak(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file; - assert(pOpenedFile != NULL); - - return pOpenedFile->readPointer; -} - -static dr_uint64 drfs_file_size__pak(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file; - assert(pOpenedFile != NULL); - - return pOpenedFile->sizeInBytes; -} - -static void drfs_flush__pak(drfs_handle archive, drfs_handle file) -{ - (void)archive; - (void)file; - - assert(archive != NULL); - assert(file != NULL); - - // All files are read-only for now. -} - -static void drfs_register_pak_backend(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drfs_archive_callbacks callbacks; - callbacks.is_valid_extension = drfs_is_valid_extension__pak; - callbacks.open_archive = drfs_open_archive__pak; - callbacks.close_archive = drfs_close_archive__pak; - callbacks.get_file_info = drfs_get_file_info__pak; - callbacks.begin_iteration = drfs_begin_iteration__pak; - callbacks.end_iteration = drfs_end_iteration__pak; - callbacks.next_iteration = drfs_next_iteration__pak; - callbacks.delete_file = NULL; - callbacks.move_file = NULL; - callbacks.create_directory = NULL; - callbacks.copy_file = NULL; - callbacks.open_file = drfs_open_file__pak; - callbacks.close_file = drfs_close_file__pak; - callbacks.read_file = drfs_read_file__pak; - callbacks.write_file = drfs_write_file__pak; - callbacks.seek_file = drfs_seek_file__pak; - callbacks.tell_file = drfs_tell_file__pak; - callbacks.file_size = drfs_file_size__pak; - callbacks.flush_file = drfs_flush__pak; - drfs_register_archive_backend(pContext, callbacks); -} -#endif //DR_FS_NO_PAK - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Wavefront MTL -// -/////////////////////////////////////////////////////////////////////////////// -#ifndef DR_FS_NO_MTL -typedef struct -{ - // The byte offset within the archive - dr_uint64 offset; - - // The size of the file, in bytes. - dr_uint64 sizeInBytes; - - // The name of the material. The specification says this can be any length, but we're going to clamp it to 255 + null terminator which should be fine. - char name[256]; - -}drfs_file_mtl; - -typedef struct -{ - // A pointer to the archive's file so we can read data. - drfs_file* pArchiveFile; - - // The access mode. - unsigned int accessMode; - - // The buffer containing the list of files. - drfs_file_mtl* pFiles; - - // The number of files in the archive. - unsigned int fileCount; - -}drfs_archive_mtl; - -typedef struct -{ - // The current index of the iterator. When this hits the file count, the iteration is finished. - unsigned int index; - -}drfs_iterator_mtl; - -typedef struct -{ - // The offset within the archive file the first byte of the file is located. - dr_uint64 offsetInArchive; - - // The size of the file in bytes so we can guard against overflowing reads. - dr_uint64 sizeInBytes; - - // The current position of the file's read pointer. - dr_uint64 readPointer; - -}drfs_openedfile_mtl; - - -static drfs_archive_mtl* drfs_mtl_create(drfs_file* pArchiveFile, unsigned int accessMode) -{ - drfs_archive_mtl* mtl = (drfs_archive_mtl*)malloc(sizeof(drfs_archive_mtl)); - if (mtl != NULL) - { - mtl->pArchiveFile = pArchiveFile; - mtl->accessMode = accessMode; - mtl->pFiles = NULL; - mtl->fileCount = 0; - } - - return mtl; -} - -static void drfs_mtl_delete(drfs_archive_mtl* pArchive) -{ - free(pArchive->pFiles); - free(pArchive); -} - -static void drfs_mtl_addfile(drfs_archive_mtl* pArchive, drfs_file_mtl* pFile) -{ - if (pArchive != NULL && pFile != NULL) - { - drfs_file_mtl* pOldBuffer = pArchive->pFiles; - drfs_file_mtl* pNewBuffer = (drfs_file_mtl*)malloc(sizeof(drfs_file_mtl) * (pArchive->fileCount + 1)); - - if (pNewBuffer != 0) - { - for (unsigned int iDst = 0; iDst < pArchive->fileCount; ++iDst) { - pNewBuffer[iDst] = pOldBuffer[iDst]; - } - - pNewBuffer[pArchive->fileCount] = *pFile; - - pArchive->pFiles = pNewBuffer; - pArchive->fileCount += 1; - - free(pOldBuffer); - } - } -} - - -typedef struct -{ - dr_uint64 archiveSizeInBytes; - dr_uint64 bytesRemaining; - drfs_file* pFile; - char* chunkPointer; - char* chunkEnd; - char chunk[4096]; - unsigned int chunkSize; - -}drfs_openarchive_mtl_state; - -static dr_bool32 drfs_mtl_loadnextchunk(drfs_openarchive_mtl_state* pState) -{ - assert(pState != NULL); - - if (pState->bytesRemaining > 0) - { - pState->chunkSize = (pState->bytesRemaining > 4096) ? 4096 : (unsigned int)pState->bytesRemaining; - assert(pState->chunkSize); - - if (drfs_read_nolock(pState->pFile, pState->chunk, pState->chunkSize, NULL) == drfs_success) - { - pState->bytesRemaining -= pState->chunkSize; - pState->chunkPointer = pState->chunk; - pState->chunkEnd = pState->chunk + pState->chunkSize; - - return DR_TRUE; - } - else - { - // An error occured while reading. Just reset everything to make it look like an error occured. - pState->bytesRemaining = 0; - pState->chunkSize = 0; - pState->chunkPointer = pState->chunk; - pState->chunkEnd = pState->chunkPointer; - } - } - - return DR_FALSE; -} - -static dr_bool32 drfs_mtl_loadnewmtl(drfs_openarchive_mtl_state* pState) -{ - assert(pState != NULL); - - const char newmtl[7] = "newmtl"; - for (unsigned int i = 0; i < 6; ++i) - { - // Check if we need a new chunk. - if (pState->chunkPointer >= pState->chunkEnd) - { - if (!drfs_mtl_loadnextchunk(pState)) - { - return DR_FALSE; - } - } - - - if (pState->chunkPointer[0] != newmtl[i]) - { - return DR_FALSE; - } - - pState->chunkPointer += 1; - } - - // At this point the first 6 characters equal "newmtl". - return DR_TRUE; -} - -static dr_bool32 drfs_mtl_skipline(drfs_openarchive_mtl_state* pState) -{ - assert(pState != NULL); - - // Keep looping until we find a new line character. - while (pState->chunkPointer < pState->chunkEnd) - { - if (pState->chunkPointer[0] == '\n') - { - // Found the new line. Now move forward by one to get past the new line character. - pState->chunkPointer += 1; - if (pState->chunkPointer >= pState->chunkEnd) - { - return drfs_mtl_loadnextchunk(pState); - } - - return DR_TRUE; - } - - pState->chunkPointer += 1; - } - - // If we get here it means we got past the end of the chunk. We just read the next chunk and call this recursively. - if (drfs_mtl_loadnextchunk(pState)) - { - return drfs_mtl_skipline(pState); - } - - return DR_FALSE; -} - -static dr_bool32 drfs_mtl_skipwhitespace(drfs_openarchive_mtl_state* pState) -{ - assert(pState != NULL); - - while (pState->chunkPointer < pState->chunkEnd) - { - const char c = pState->chunkPointer[0]; - if (c != ' ' && c != '\t' && c != '\r' && c != '\n') - { - return DR_TRUE; - } - - pState->chunkPointer += 1; - } - - if (drfs_mtl_loadnextchunk(pState)) - { - return drfs_mtl_skipwhitespace(pState); - } - - return DR_FALSE; -} - -static dr_bool32 drfs_mtl_loadmtlname(drfs_openarchive_mtl_state* pState, void* dst, unsigned int dstSizeInBytes) -{ - assert(pState != NULL); - - // We loop over character by character until we find a whitespace, "#" character or the end of the file. - char* dst8 = (char*)dst; - while (dstSizeInBytes > 0 && pState->chunkPointer < pState->chunkEnd) - { - const char c = pState->chunkPointer[0]; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '#') - { - // We've found the end of the name. Null terminate and return. - *dst8 = '\0'; - return DR_TRUE; - } - else - { - *dst8++ = c; - dstSizeInBytes -= 1; - pState->chunkPointer += 1; - } - } - - // At this point we either ran out of space in the destination buffer or the chunk. - if (dstSizeInBytes > 0) - { - // We got to the end of the chunk, so we need to load the next chunk and call this recursively. - assert(pState->chunkPointer == pState->chunkEnd); - - if (drfs_mtl_loadnextchunk(pState)) - { - return drfs_mtl_loadmtlname(pState, dst8, dstSizeInBytes); - } - else - { - // We reached the end of the file, but the name may be valid. - return DR_TRUE; - } - } - else - { - // We ran out of room in the buffer. - return DR_FALSE; - } -} - - -static dr_bool32 drfs_is_valid_extension__mtl(const char* extension) -{ - return drfs__stricmp(extension, "mtl") == 0; -} - -static drfs_result drfs_open_archive__mtl(drfs_file* pArchiveFile, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(pArchiveFile != NULL); - assert(pHandleOut != NULL); - assert(drfs_tell(pArchiveFile) == 0); - - *pHandleOut = NULL; - - if (!drfs_lock(pArchiveFile)) { - return drfs_unknown_error; - } - - drfs_archive_mtl* mtl = drfs_mtl_create(pArchiveFile, accessMode); - if (mtl == NULL) { - return drfs_invalid_archive; - } - - drfs_result result = drfs_success; - - // We create a state object that is used to help us with chunk management. - drfs_openarchive_mtl_state state; - state.pFile = pArchiveFile; - state.archiveSizeInBytes = drfs_size_nolock(pArchiveFile); - state.bytesRemaining = state.archiveSizeInBytes; - state.chunkSize = 0; - state.chunkPointer = state.chunk; - state.chunkEnd = state.chunk; - if (drfs_mtl_loadnextchunk(&state)) - { - while (state.bytesRemaining > 0 || state.chunkPointer < state.chunkEnd) - { - ptrdiff_t bytesRemainingInChunk = state.chunkEnd - state.chunkPointer; - assert(bytesRemainingInChunk > 0); - - dr_uint64 newmtlOffset = state.archiveSizeInBytes - state.bytesRemaining - ((dr_uint64)bytesRemainingInChunk); - - if (drfs_mtl_loadnewmtl(&state)) - { - if (state.chunkPointer[0] == ' ' || state.chunkPointer[0] == '\t') - { - // We found a new material. We need to iterate until we hit the first whitespace, "#", or the end of the file. - if (drfs_mtl_skipwhitespace(&state)) - { - drfs_file_mtl file; - if (drfs_mtl_loadmtlname(&state, file.name, 256)) - { - // Everything worked out. We now need to create the file and add it to our list. At this point we won't know the size. We determine - // the size in a post-processing step later. - file.offset = newmtlOffset; - drfs_mtl_addfile(mtl, &file); - } - } - } - } - - // Move to the next line. - drfs_mtl_skipline(&state); - } - - - // The files will have been read at this point, but we need to do a post-processing step to retrieve the size of each file. - for (unsigned int iFile = 0; iFile < mtl->fileCount; ++iFile) - { - if (iFile < mtl->fileCount - 1) - { - // It's not the last item. The size of this item is the offset of the next file minus the offset of this file. - mtl->pFiles[iFile].sizeInBytes = mtl->pFiles[iFile + 1].offset - mtl->pFiles[iFile].offset; - } - else - { - // It's the last item. The size of this item is the size of the archive file minus the file's offset. - mtl->pFiles[iFile].sizeInBytes = state.archiveSizeInBytes - mtl->pFiles[iFile].offset; - } - } - } - else - { - drfs_mtl_delete(mtl); - mtl = NULL; - result = drfs_invalid_archive; - } - - drfs_unlock(pArchiveFile); - *pHandleOut = mtl; - return result; -} - -static void drfs_close_archive__mtl(drfs_handle archive) -{ - drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive; - assert(mtl != NULL); - - drfs_mtl_delete(mtl); -} - -static drfs_result drfs_get_file_info__mtl(drfs_handle archive, const char* relativePath, drfs_file_info* fi) -{ - drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive; - assert(mtl != NULL); - - for (unsigned int iFile = 0; iFile < mtl->fileCount; ++iFile) - { - if (strcmp(relativePath, mtl->pFiles[iFile].name) == 0) - { - // We found the file. - if (fi != NULL) - { - drfs__strcpy_s(fi->absolutePath, sizeof(fi->absolutePath), relativePath); - fi->sizeInBytes = mtl->pFiles[iFile].sizeInBytes; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY; - } - - return drfs_success; - } - } - - return drfs_does_not_exist; -} - -static drfs_handle drfs_begin_iteration__mtl(drfs_handle archive, const char* relativePath) -{ - assert(relativePath != NULL); - - drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive; - assert(mtl != NULL); - - if (mtl->fileCount > 0) - { - if (relativePath[0] == '\0' || (relativePath[0] == '/' && relativePath[1] == '\0')) // This is a flat archive, so no sub-folders. - { - drfs_iterator_mtl* pIterator = (drfs_iterator_mtl*)malloc(sizeof(*pIterator)); - if (pIterator != NULL) - { - pIterator->index = 0; - return pIterator; - } - } - } - - return NULL; -} - -static void drfs_end_iteration__mtl(drfs_handle archive, drfs_handle iterator) -{ - (void)archive; - - drfs_iterator_mtl* pIterator = (drfs_iterator_mtl*)iterator; - free(pIterator); -} - -static dr_bool32 drfs_next_iteration__mtl(drfs_handle archive, drfs_handle iterator, drfs_file_info* fi) -{ - drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive; - assert(mtl != NULL); - - drfs_iterator_mtl* pIterator = (drfs_iterator_mtl*)iterator; - assert(pIterator != NULL); - - if (pIterator->index < mtl->fileCount) - { - if (fi != NULL) - { - drfs__strcpy_s(fi->absolutePath, DRFS_MAX_PATH, mtl->pFiles[pIterator->index].name); - fi->sizeInBytes = mtl->pFiles[pIterator->index].sizeInBytes; - fi->lastModifiedTime = 0; - fi->attributes = DRFS_FILE_ATTRIBUTE_READONLY; - } - - pIterator->index += 1; - return DR_TRUE; - } - - return DR_FALSE; -} - -static drfs_result drfs_open_file__mtl(drfs_handle archive, const char* relativePath, unsigned int accessMode, drfs_handle* pHandleOut) -{ - assert(relativePath != NULL); - assert(pHandleOut != NULL); - - *pHandleOut = NULL; - - // Only supporting read-only for now. - if ((accessMode & DRFS_WRITE) != 0) { - return drfs_permission_denied; - } - - drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive; - assert(mtl != NULL); - - for (unsigned int iFile = 0; iFile < mtl->fileCount; ++iFile) - { - if (strcmp(relativePath, mtl->pFiles[iFile].name) == 0) - { - // We found the file. - drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)malloc(sizeof(drfs_openedfile_mtl)); - if (pOpenedFile != NULL) - { - pOpenedFile->offsetInArchive = mtl->pFiles[iFile].offset; - pOpenedFile->sizeInBytes = mtl->pFiles[iFile].sizeInBytes; - pOpenedFile->readPointer = 0; - - *pHandleOut = pOpenedFile; - return drfs_success; - } - } - } - - return drfs_does_not_exist; -} - -static void drfs_close_file__mtl(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file; - assert(pOpenedFile != NULL); - - free(pOpenedFile); -} - -static drfs_result drfs_read_file__mtl(drfs_handle archive, drfs_handle file, void* pDataOut, size_t bytesToRead, size_t* pBytesReadOut) -{ - assert(pDataOut != NULL); - assert(bytesToRead > 0); - - drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive; - assert(mtl != NULL); - - drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file; - assert(pOpenedFile != NULL); - - // The read pointer should never go past the file size. - assert(pOpenedFile->sizeInBytes >= pOpenedFile->readPointer); - - dr_uint64 bytesAvailable = pOpenedFile->sizeInBytes - pOpenedFile->readPointer; - if (bytesAvailable < bytesToRead) { - bytesToRead = (size_t)bytesAvailable; // Safe cast, as per the check above. - } - - if (!drfs_lock(mtl->pArchiveFile)) { - return drfs_unknown_error; - } - - drfs_seek_nolock(mtl->pArchiveFile, (dr_int64)(pOpenedFile->offsetInArchive + pOpenedFile->readPointer), drfs_origin_start); - drfs_result result = drfs_read_nolock(mtl->pArchiveFile, pDataOut, bytesToRead, pBytesReadOut); - if (result == drfs_success) { - pOpenedFile->readPointer += bytesToRead; - } - - return result; -} - -static drfs_result drfs_write_file__mtl(drfs_handle archive, drfs_handle file, const void* pData, size_t bytesToWrite, size_t* pBytesWrittenOut) -{ - (void)archive; - (void)file; - (void)pData; - (void)bytesToWrite; - - assert(archive != NULL); - assert(file != NULL); - assert(pData != NULL); - assert(bytesToWrite > 0); - - // All files are read-only for now. - if (pBytesWrittenOut) { - *pBytesWrittenOut = 0; - } - - return drfs_success; -} - -static drfs_result drfs_seek_file__mtl(drfs_handle archive, drfs_handle file, dr_int64 bytesToSeek, drfs_seek_origin origin) -{ - (void)archive; - - drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file; - assert(pOpenedFile != NULL); - - dr_uint64 newPos = pOpenedFile->readPointer; - if (origin == drfs_origin_current) { - if ((dr_int64)newPos + bytesToSeek >= 0) { - newPos = (dr_uint64)((dr_int64)newPos + bytesToSeek); - } else { - return drfs_invalid_args; // Trying to seek to before the beginning of the file. - } - } else if (origin == drfs_origin_start) { - assert(bytesToSeek >= 0); - newPos = (dr_uint64)bytesToSeek; - } else if (origin == drfs_origin_end) { - assert(bytesToSeek >= 0); - if ((dr_uint64)bytesToSeek <= pOpenedFile->sizeInBytes) { - newPos = pOpenedFile->sizeInBytes - (dr_uint64)bytesToSeek; - } else { - return drfs_invalid_args; // Trying to seek to before the beginning of the file. - } - } else { - return drfs_unknown_error; // Should never get here. - } - - - if (newPos > pOpenedFile->sizeInBytes) { - return drfs_invalid_args; - } - - pOpenedFile->readPointer = newPos; - return drfs_success; -} - -static dr_uint64 drfs_tell_file__mtl(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file; - assert(pOpenedFile != NULL); - - return pOpenedFile->readPointer; -} - -static dr_uint64 drfs_file_size__mtl(drfs_handle archive, drfs_handle file) -{ - (void)archive; - - drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file; - assert(pOpenedFile != NULL); - - return pOpenedFile->sizeInBytes; -} - -static void drfs_flush__mtl(drfs_handle archive, drfs_handle file) -{ - (void)archive; - (void)file; - - assert(archive != NULL); - assert(file != NULL); - - // All files are read-only for now. -} - - -static void drfs_register_mtl_backend(drfs_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drfs_archive_callbacks callbacks; - callbacks.is_valid_extension = drfs_is_valid_extension__mtl; - callbacks.open_archive = drfs_open_archive__mtl; - callbacks.close_archive = drfs_close_archive__mtl; - callbacks.get_file_info = drfs_get_file_info__mtl; - callbacks.begin_iteration = drfs_begin_iteration__mtl; - callbacks.end_iteration = drfs_end_iteration__mtl; - callbacks.next_iteration = drfs_next_iteration__mtl; - callbacks.delete_file = NULL; - callbacks.move_file = NULL; - callbacks.create_directory = NULL; - callbacks.copy_file = NULL; - callbacks.open_file = drfs_open_file__mtl; - callbacks.close_file = drfs_close_file__mtl; - callbacks.read_file = drfs_read_file__mtl; - callbacks.write_file = drfs_write_file__mtl; - callbacks.seek_file = drfs_seek_file__mtl; - callbacks.tell_file = drfs_tell_file__mtl; - callbacks.file_size = drfs_file_size__mtl; - callbacks.flush_file = drfs_flush__mtl; - drfs_register_archive_backend(pContext, callbacks); -} -#endif //DR_FS_NO_MTL - - - -#endif //DR_FS_IMPLEMENTATION - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_fsw.h b/source/engine/thirdparty/dr_libs/old/dr_fsw.h deleted file mode 100644 index 830e7fc..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_fsw.h +++ /dev/null @@ -1,1625 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. - -// ABOUT -// -// dr_fsw is a simple library for watching for changes to the file system. This is not a full-featured library -// and is only intended for basic use cases. -// -// Limitations: -// - Only Windows is supported at the moment. -// -// -// -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_FSW_IMPLEMENTATION -// #include "dr_fsw.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. -// -// Example: -// // Startup. -// drfsw_context* context = drfsw_create_context(); -// if (context == NULL) -// { -// // There was an error creating the context... -// } -// -// drfsw_add_directory(context, "C:/My/Folder"); -// drfsw_add_directory(context, "C:/My/Other/Folder"); -// -// ... -// -// // Meanwhile, in another thread... -// void MyOtherThreadEntryProc() -// { -// drfsw_event e; -// while (isMyApplicationStillAlive && drfsw_next_event(context, &e)) -// { -// switch (e.type) -// { -// case drfsw_event_type_created: OnFileCreated(e.absolutePath); break; -// case drfsw_event_type_deleted: OnFileDeleted(e.absolutePath); break; -// case drfsw_event_type_renamed: OnFileRenamed(e.absolutePath, e.absolutePathNew); break; -// case drfsw_event_type_updated: OnFileUpdated(e.absolutePath); break; -// default: break; -// } -// } -// } -// -// ... -// -// // Shutdown -// drfsw_context* contextOld = context; -// context = NULL; -// drfsw_delete_context(contextOld); -// -// Directories are watched recursively, so try to avoid using this on high level directories -// like "C:\". Also avoid watching a directory that is a descendant of another directory that's -// already being watched. -// -// It does not matter whether or not paths are specified with forward or back slashes; the -// library will normalize all of that internally depending on the platform. Note, however, -// that events always report their paths with forward slashes. -// -// You don't need to wait for events on a separate thread, however drfsw_next_event() is -// a blocking call, so it's usually best to do so. Alternatively, you can use -// drfsw_peek_event() which is the same, except non-blocking. Avoid using both -// drfsw_next_event() and drfsw_peek_event() at the same time because both will remove -// the event from the internal queue so it likely won't work the way you expect. -// -// The shutdown sequence is a bit strange, but since another thread is accessing that pointer, -// you should set any shared pointers to null before calling drfsw_delete_context(). That way, -// the next call to drfsw_next_event() will pass in a null pointer which will cause it to -// immediately return with zero and thus break the loop and terminate the thread. It is up to -// the application to ensure the pointer passed to drfsw_next_event() is valid. Deleting a context -// will cause a waiting call to drfsw_next_event() to return 0, however there is a chance that the -// context is deleted before drfsw_next_event() has entered into it's wait state. It's up to the -// application to make sure the context remains valid. -// -// -// -// QUICK NOTES -// - Files that are not on the machine's local file system will not be detected (such as files on a network drive). -// - In some cases, renaming files won't be detected. Instead it may be implemented as a delete/create pair. -// -// - Win32: Every directory that is watched becomes "in use" by the operating system. It is still possible -// to modify the files and folders inside the watched directory, however. -// - Win32: There is a known issue with the ReadDirectoryChangesW() watch technique (which is used internally) -// where some events won't get processed if a large number of files change in a short period of time. - -#ifndef dr_fsw_h -#define dr_fsw_h - -#ifdef __cplusplus -extern "C" { -#endif - -// The maximum length of a path in bytes, including the null terminator. If a path exceeds this amount, it will be set to an empty -// string. When this is changed the source file will need to be recompiled. Most of the time leaving this at 256 is fine, but it's -// not a problem to increase the size if you are encountering issues. Note that increasing this value will increase memory usage -// on both the heap and the stack. -#ifndef DRFSW_MAX_PATH -//#define DRFSW_MAX_PATH 256U -#define DRFSW_MAX_PATH 1024U -//#define DRFSW_MAX_PATH 4096U -#endif - -// The maximum size of the event queue before it overflows. -#define DRFSW_EVENT_QUEUE_SIZE 1024U - - -// The different event types. -typedef enum -{ - drfsw_event_type_created, - drfsw_event_type_deleted, - drfsw_event_type_renamed, - drfsw_event_type_updated - -} drfsw_event_type; - - -// Structure containing information about an event. -typedef struct -{ - // The type of the event: created, deleted, renamed or updated. - drfsw_event_type type; - - // The absolute path of the file. For renamed events, this is the old name. - char absolutePath[DRFSW_MAX_PATH]; - - // The new file name. This is only used for renamed events. For other event types, this will be an empty string. - char absolutePathNew[DRFSW_MAX_PATH]; - - // The absolute base path. For renamed events, this is the old base path. - char absoluteBasePath[DRFSW_MAX_PATH]; - - // The absolute base path for the new file name. This is only used for renamed events. For other event types, this will be an empty string. - char absoluteBasePathNew[DRFSW_MAX_PATH]; - -} drfsw_event; - - -typedef void* drfsw_context; - - -// Creates a file system watcher. -// -// This will create a background thread that will do the actual checking. -drfsw_context* drfsw_create_context(void); - -// Deletes the given file system watcher. -// -// This will not return until the thread watching for changes has returned. -// -// You do not need to remove the watched directories beforehand - this function will make sure everything is cleaned up properly. -void drfsw_delete_context(drfsw_context* pContext); - - -// Adds a directory to watch. This will watch for files and folders recursively. -int drfsw_add_directory(drfsw_context* pContext, const char* absolutePath); - -// Removes a watched directory. -void drfsw_remove_directory(drfsw_context* pContext, const char* absolutePath); - -// Helper for removing every watched directory. -void drfsw_remove_all_directories(drfsw_context* pContext); - -// Determines whether or not the given directory is being watched. -int drfsw_is_watching_directory(drfsw_context* pContext, const char* absolutePath); - - -// Waits for an event from the file system. -// -// This is a blocking function. Call drfsw_peek_event() to do a non-blocking call. If an error occurs, or the context is deleted, 0 -// will be returned and the memory pointed to by pEventOut will be undefined. -// -// This can be called from any thread, however it should not be called from multiple threads simultaneously. -// -// Use caution when using this combined with drfsw_peek_event(). In almost all cases you should use just one or the other at any -// given time. -// -// It is up to the application to ensure the context is still valid before calling this function. -// -// Example Usage: -// -// void MyFSWatcher() { -// drfsw_event e; -// while (isMyContextStillAlive && drfsw_next_event(context, e)) { -// // Do something with the event... -// } -// } -int drfsw_next_event(drfsw_context* pContext, drfsw_event* pEventOut); - -// Checks to see if there is a pending event, and if so, returns non-zero and fills the given structure with the event details. This -// removes the event from the queue. -// -// This can be called from any thread, however it should not be called from multiple threads simultaneously. -// -// It is up to the application to ensure the context is still valid before calling this function. -int drfsw_peek_event(drfsw_context* pContext, drfsw_event* pEventOut); - - -#ifdef __cplusplus -} -#endif - -#endif //dr_fsw_h - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_FSW_IMPLEMENTATION - -// NOTES: -// -// Win32 and ReadDirectoryChangesW -// -// Here is how watching for changes via the ReadDirectoryChangesW() works: -// 1) You create a handle to the directory with CreateFile() -// 2) You pass this handle to ReadDirectoryChangesW(), including a pointer to a function that is called when changes to the directory are made. -// 3) From the aforementioned callback, ReadDirectoryChangesW() needs to be called again -// -// There are, however, a lot of details that need to be handled correctly in order for this to work -// -// First of all, the callback passed to ReadDirectoryChangesW() will not be called unless the calling thread is in an alertable state. A thread -// is put into an alertable state with WaitForMultipleObjectsEx() (the Ex version is important since it has an extra parameter that lets you -// put the thread into an alertable state). Using this blocks the thread which means you need to create a worker thread in the background. - -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" -#endif - -#ifndef DRFSW_PRIVATE -#define DRFSW_PRIVATE static -#endif - -// The number of FILE_NOTIFY_INFORMATION structures in the buffer that's passed to ReadDirectoryChangesW() -#define WIN32_RDC_FNI_COUNT DRFSW_EVENT_QUEUE_SIZE - -#include - -#if defined(_WIN32) -#include - -DRFSW_PRIVATE void* drfsw_malloc(size_t sizeInBytes) -{ - return HeapAlloc(GetProcessHeap(), 0, sizeInBytes); -} - -DRFSW_PRIVATE void drfsw_free(void* p) -{ - HeapFree(GetProcessHeap(), 0, p); -} - -DRFSW_PRIVATE void drfsw_memcpy(void* dst, const void* src, size_t sizeInBytes) -{ - CopyMemory(dst, src, sizeInBytes); -} - -DRFSW_PRIVATE void drfsw_zeromemory(void* dst, size_t sizeInBytes) -{ - ZeroMemory(dst, sizeInBytes); -} -#else -#include -#include - -DRFSW_PRIVATE void* drfsw_malloc(size_t sizeInBytes) -{ - return malloc(sizeInBytes); -} - -DRFSW_PRIVATE void drfsw_free(void* p) -{ - free(p); -} - -DRFSW_PRIVATE void drfsw_memcpy(void* dst, const void* src, size_t sizeInBytes) -{ - memcpy(dst, src, sizeInBytes); -} - -DRFSW_PRIVATE void drfsw_zeromemory(void* dst, size_t sizeInBytes) -{ - memset(dst, 0, sizeInBytes); -} -#endif - - -DRFSW_PRIVATE int drfsw_strcpy(char* dst, unsigned int dstSizeInBytes, const char* src) -{ -#if defined(_MSC_VER) - return strcpy_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - char* iDst = dst; - const char* iSrc = src; - size_t remainingSizeInBytes = dstSizeInBytes; - while (remainingSizeInBytes > 0 && iSrc[0] != '\0') - { - iDst[0] = iSrc[0]; - - iDst += 1; - iSrc += 1; - remainingSizeInBytes -= 1; - } - - if (remainingSizeInBytes > 0) { - iDst[0] = '\0'; - } else { - dst[0] = '\0'; - return ERANGE; - } - - return 0; -#endif -} - - -DRFSW_PRIVATE int drfsw_event_init(drfsw_event* pEvent, drfsw_event_type type, const char* absolutePath, const char* absolutePathNew, const char* absoluteBasePath, const char* absoluteBasePathNew) -{ - if (pEvent != NULL) - { - pEvent->type = type; - - if (absolutePath != NULL) { - drfsw_strcpy(pEvent->absolutePath, DRFSW_MAX_PATH, absolutePath); - } else { - drfsw_zeromemory(pEvent->absolutePath, DRFSW_MAX_PATH); - } - - if (absolutePathNew != NULL) { - drfsw_strcpy(pEvent->absolutePathNew, DRFSW_MAX_PATH, absolutePathNew); - } else { - drfsw_zeromemory(pEvent->absolutePathNew, DRFSW_MAX_PATH); - } - - - if (absoluteBasePath != NULL) { - drfsw_strcpy(pEvent->absoluteBasePath, DRFSW_MAX_PATH, absoluteBasePath); - } else { - drfsw_zeromemory(pEvent->absoluteBasePath, DRFSW_MAX_PATH); - } - - if (absoluteBasePathNew != NULL) { - drfsw_strcpy(pEvent->absoluteBasePathNew, DRFSW_MAX_PATH, absoluteBasePathNew); - } else { - drfsw_zeromemory(pEvent->absoluteBasePathNew, DRFSW_MAX_PATH); - } - - return 1; - } - - return 0; -} - - -typedef struct -{ - // The buffer containing the events in the queue. - drfsw_event* pBuffer; - - // The size of the buffer, in drfsw_event's. - unsigned int bufferSize; - - // The number of items in the queue. - unsigned int count; - - // The index of the first item in the queue. - unsigned int indexFirst; - -#if defined(_WIN32) - // The semaphore for blocking in drfsw_next_event(). - HANDLE hSemaphore; - - // The mutex for synchronizing access to the buffer. This is needed because drfsw_next_event() will need to read the buffer while - // another thread is filling it with events. In addition, it will help to keep drfsw_next_event() and drfsw_peek_event() playing - // nicely with each other. - HANDLE hLock; -#endif - -} drfsw_event_queue; - -DRFSW_PRIVATE int drfsw_event_queue_init(drfsw_event_queue* pQueue) -{ - if (pQueue != NULL) - { - pQueue->pBuffer = NULL; - pQueue->bufferSize = 0; - pQueue->indexFirst = 0; - pQueue->count = 0; - -#if defined(_WIN32) - pQueue->hSemaphore = CreateSemaphoreW(NULL, 0, DRFSW_EVENT_QUEUE_SIZE, NULL); - if (pQueue->hSemaphore == NULL) - { - drfsw_free(pQueue->pBuffer); - return 0; - } - - pQueue->hLock = CreateEventW(NULL, FALSE, TRUE, NULL); - if (pQueue->hLock == NULL) - { - CloseHandle(pQueue->hSemaphore); - drfsw_free(pQueue->pBuffer); - return 0; - } -#endif - - return 1; - } - - return 0; -} - -DRFSW_PRIVATE void drfsw_event_queue_uninit(drfsw_event_queue* pQueue) -{ - if (pQueue != NULL) - { - drfsw_free(pQueue->pBuffer); - pQueue->pBuffer = NULL; - - pQueue->bufferSize = 0; - pQueue->indexFirst = 0; - pQueue->count = 0; - -#if defined(_WIN32) - CloseHandle(pQueue->hSemaphore); - pQueue->hSemaphore = NULL; - - CloseHandle(pQueue->hLock); - pQueue->hLock = NULL; -#endif - } -} - -DRFSW_PRIVATE unsigned int drfsw_event_queue_getcount(drfsw_event_queue* pQueue) -{ - if (pQueue != NULL) - { - return pQueue->count; - } - - return 0; -} - -DRFSW_PRIVATE void drfsw_event_queue_inflate(drfsw_event_queue* pQueue) -{ - if (pQueue != NULL) - { - unsigned int newBufferSize = pQueue->bufferSize + 1; - if (pQueue->bufferSize > 0) - { - newBufferSize = pQueue->bufferSize*2; - } - - drfsw_event* pOldBuffer = pQueue->pBuffer; - drfsw_event* pNewBuffer = (drfsw_event*)drfsw_malloc(newBufferSize * sizeof(drfsw_event)); - - for (unsigned int iDst = 0; iDst < pQueue->count; ++iDst) - { - unsigned int iSrc = (pQueue->indexFirst + iDst) % pQueue->bufferSize; - drfsw_memcpy(pNewBuffer + iDst, pOldBuffer + iSrc, sizeof(drfsw_event)); - } - - - pQueue->bufferSize = newBufferSize; - pQueue->pBuffer = pNewBuffer; - pQueue->indexFirst = 0; - - drfsw_free(pOldBuffer); - } -} - -DRFSW_PRIVATE int drfsw_event_queue_pushback(drfsw_event_queue* pQueue, drfsw_event* pEvent) -{ - if (pQueue != NULL) - { - if (pEvent != NULL) - { - unsigned int count = drfsw_event_queue_getcount(pQueue); - if (count == DRFSW_EVENT_QUEUE_SIZE) - { - // We've hit the limit. - return 0; - } - - if (count == pQueue->bufferSize) - { - drfsw_event_queue_inflate(pQueue); - assert(count < pQueue->bufferSize); - } - - - // Insert the value. - unsigned int iDst = (pQueue->indexFirst + pQueue->count) % pQueue->bufferSize; - drfsw_memcpy(pQueue->pBuffer + iDst, pEvent, sizeof(drfsw_event)); - - - // Increment the counter. - pQueue->count += 1; - - - return 1; - } - } - - return 0; -} - -DRFSW_PRIVATE int drfsw_event_queue_pop(drfsw_event_queue* pQueue, drfsw_event* pEventOut) -{ - if (pQueue != NULL && pQueue->count > 0) - { - if (pEventOut != NULL) - { - drfsw_memcpy(pEventOut, pQueue->pBuffer + pQueue->indexFirst, sizeof(drfsw_event)); - pQueue->indexFirst = (pQueue->indexFirst + 1) % pQueue->bufferSize; - } - - pQueue->count -= 1; - - - return 1; - } - - return 0; -} - - - -// A simple function for appending a relative path to an absolute path. This does not resolve "." and ".." components. -DRFSW_PRIVATE int drfsw_make_absolute_path(const char* absolutePart, const char* relativePart, char absolutePathOut[DRFSW_MAX_PATH]) -{ - size_t absolutePartLength = strlen(absolutePart); - size_t relativePartLength = strlen(relativePart); - - if (absolutePartLength > 0) - { - if (absolutePart[absolutePartLength - 1] == '/') - { - absolutePartLength -= 1; - } - - if (absolutePartLength > DRFSW_MAX_PATH) - { - absolutePartLength = DRFSW_MAX_PATH - 1; - } - } - - if (absolutePartLength + relativePartLength + 1 > DRFSW_MAX_PATH) - { - relativePartLength = DRFSW_MAX_PATH - 1 - absolutePartLength - 1; // -1 for the null terminate and -1 for the slash. - } - - - // Absolute part. - memcpy(absolutePathOut, absolutePart, absolutePartLength); - - // Slash. - absolutePathOut[absolutePartLength] = '/'; - - // Relative part. - memcpy(absolutePathOut + absolutePartLength + 1, relativePart, relativePartLength); - - // Null terminator. - absolutePathOut[absolutePartLength + 1 + relativePartLength] = '\0'; - - - return 1; -} - -// Replaces the back slashes with forward slashes in the given string. This operates on the string in place. -DRFSW_PRIVATE int drfsw_to_forward_slashes(char* path) -{ - if (path != NULL) - { - unsigned int counter = 0; - while (*path++ != '\0' && counter++ < DRFSW_MAX_PATH) - { - if (*path == '\\') - { - *path = '/'; - } - } - - return 1; - } - - return 0; -} - - -typedef struct -{ - // A pointer to the buffer containing pointers to the objects. - void** buffer; - - // The size of the buffer, in pointers. - unsigned int bufferSize; - - // The number of pointers in the list. - unsigned int count; - -} drfsw_list; - -DRFSW_PRIVATE int drfsw_list_init(drfsw_list* pList) -{ - if (pList != NULL) - { - pList->buffer = NULL; - pList->bufferSize = 0; - pList->count = 0; - - return 1; - } - - return 0; -} - -DRFSW_PRIVATE void drfsw_list_uninit(drfsw_list* pList) -{ - if (pList != NULL) - { - drfsw_free(pList->buffer); - } -} - -DRFSW_PRIVATE void drfsw_list_inflate(drfsw_list* pList) -{ - if (pList != NULL) - { - unsigned int newBufferSize = pList->bufferSize + 1; - if (pList->bufferSize > 0) - { - newBufferSize = pList->bufferSize*2; - } - - void** pOldBuffer = pList->buffer; - void** pNewBuffer = (void**)drfsw_malloc(newBufferSize*sizeof(void*)); - - // Move everything over to the new buffer. - for (unsigned int i = 0; i < pList->count; ++i) - { - pNewBuffer[i] = pOldBuffer[i]; - } - - - pList->bufferSize = newBufferSize; - pList->buffer = pNewBuffer; - } -} - -DRFSW_PRIVATE void drfsw_list_pushback(drfsw_list* pList, void* pItem) -{ - if (pList != NULL) - { - if (pList->count == pList->bufferSize) - { - drfsw_list_inflate(pList); - assert(pList->count < pList->bufferSize); - - pList->buffer[pList->count] = pItem; - pList->count += 1; - } - } -} - -DRFSW_PRIVATE void drfsw_list_removebyindex(drfsw_list* pList, unsigned int index) -{ - if (pList != NULL) - { - assert(index < pList->count); - assert(pList->count > 0); - - // Just move everything down one slot. - for (unsigned int i = index; index < pList->count - 1; ++i) - { - pList->buffer[i] = pList->buffer[i + 1]; - } - - pList->count -= 1; - } -} - - - -#if defined(_WIN32) -#define DRFSW_MAX_PATH_W (DRFSW_MAX_PATH / sizeof(wchar_t)) - -/////////////////////////////////////////////// -// ReadDirectoryChangesW - -static const int WIN32_RDC_PENDING_WATCH = (1 << 0); -static const int WIN32_RDC_PENDING_DELETE = (1 << 1); - - -// Replaces the forward slashes to back slashes for use with Win32. This operates on the string in place. -DRFSW_PRIVATE int drfsw_to_back_slashes_wchar(wchar_t* path) -{ - if (path != NULL) - { - unsigned int counter = 0; - while (*path++ != L'\0' && counter++ < DRFSW_MAX_PATH_W) - { - if (*path == L'/') - { - *path = L'\\'; - } - } - - return 1; - } - - return 0; -} - -// Converts a UTF-8 string to wchar_t for use with Win32. Free the returned pointer with drfsw_free(). -DRFSW_PRIVATE int drfsw_utf8_to_wchar(const char* str, wchar_t wstrOut[DRFSW_MAX_PATH_W]) -{ - int wcharsWritten = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstrOut, DRFSW_MAX_PATH_W); - if (wcharsWritten > 0) - { - assert((unsigned int)wcharsWritten <= DRFSW_MAX_PATH_W); - return 1; - } - - return 0; -} - -DRFSW_PRIVATE int drfsw_wchar_to_utf8(const wchar_t* wstr, int wstrCC, char pathOut[DRFSW_MAX_PATH]) -{ - int bytesWritten = WideCharToMultiByte(CP_UTF8, 0, wstr, wstrCC, pathOut, DRFSW_MAX_PATH - 1, NULL, NULL); - if (bytesWritten > 0) - { - assert((unsigned int)bytesWritten < DRFSW_MAX_PATH); - pathOut[bytesWritten] = '\0'; - - return 1; - } - - return 0; -} - -// Converts a UTF-8 path to wchar_t and converts the slashes to backslashes for use with Win32. Free the returned pointer with drfsw_free(). -DRFSW_PRIVATE int drfsw_to_win32_path_wchar(const char* path, wchar_t wpathOut[DRFSW_MAX_PATH_W]) -{ - if (drfsw_utf8_to_wchar(path, wpathOut)) - { - return drfsw_to_back_slashes_wchar(wpathOut); - } - - return 0; -} - -// Converts a wchar_t Win32 path to a char unix style path (forward slashes instead of back). -DRFSW_PRIVATE int drfsw_from_win32_path(const wchar_t* wpath, int wpathCC, char pathOut[DRFSW_MAX_PATH]) -{ - if (drfsw_wchar_to_utf8(wpath, wpathCC, pathOut)) - { - return drfsw_to_forward_slashes(pathOut); - } - - return 0; -} - - -DRFSW_PRIVATE VOID CALLBACK drfsw_win32_completionroutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped); -DRFSW_PRIVATE VOID CALLBACK drfsw_win32_schedulewatchAPC(ULONG_PTR dwParam); -DRFSW_PRIVATE VOID CALLBACK drfsw_win32_cancelioAPC(ULONG_PTR dwParam); - -typedef struct -{ - // Thelist containing pointers to the watched directory objects. This is not thread safe. - drfsw_list list; - - // The lock for synchronizing access to the list. - HANDLE hLock; - -} drfsw_directory_list_win32; - -// Structure representing the watcher context for the Win32 RDC method. -typedef struct -{ - // The list of watched directories. - drfsw_directory_list_win32 watchedDirectories; - - // The event queue. - drfsw_event_queue eventQueue; - - - // A handle to the watcher thread. - HANDLE hThread; - - // The event that will become signaled when the watcher thread needs to be terminated. - HANDLE hTerminateEvent; - - // The semaphore which is used when deleting a watched folder. This starts off at 0, and the maximum count is 1. When a watched - // directory is removed, the calling thread will wait on this semaphore while the worker thread does the deletion. - HANDLE hDeleteDirSemaphore; - - // Whether or not the watch thread needs to be terminated. - BOOL terminateThread; - -} drfsw_context_win32; - -DRFSW_PRIVATE drfsw_context* drfsw_create_context_win32(void); -DRFSW_PRIVATE void drfsw_delete_context_win32(drfsw_context_win32* pContext); -DRFSW_PRIVATE int drfsw_add_directory_win32(drfsw_context_win32* pContext, const char* absolutePath); -DRFSW_PRIVATE void drfsw_remove_directory_win32(drfsw_context_win32* pContext, const char* absolutePath); -DRFSW_PRIVATE void drfsw_remove_all_directories_win32(drfsw_context_win32* pContext); -DRFSW_PRIVATE int drfsw_is_watching_directory_win32(drfsw_context_win32* pContext, const char* absolutePath); -DRFSW_PRIVATE int drfsw_next_event_win32(drfsw_context_win32* pContext, drfsw_event* pEventOut); -DRFSW_PRIVATE int drfsw_peek_event_win32(drfsw_context_win32* pContext, drfsw_event* pEventOut); -DRFSW_PRIVATE void drfsw_postevent_win32(drfsw_context_win32* pContext, drfsw_event* pEvent); - - -// Structure representing a directory that's being watched with the Win32 RDC method. -typedef struct -{ - // A pointer to the context that owns this directory. - drfsw_context_win32* pContext; - - // The absolute path of the directory being watched. - char absolutePath[DRFSW_MAX_PATH]; - - // The handle representing the directory. This is created with CreateFile() which means the directory itself will become locked - // because the operating system see's it as "in use". It is possible to modify the files and folder inside the directory, though. - HANDLE hDirectory; - - // This is required for for ReadDirectoryChangesW(). - OVERLAPPED overlapped; - - // A pointer to the buffer containing the notification objects that is passed to the notification callback specified with - // ReadDirectoryChangesW(). This must be aligned to a DWORD boundary, but drfsw_malloc() will do that for us, so that should not - // be an issue. - FILE_NOTIFY_INFORMATION* pFNIBuffer1; - FILE_NOTIFY_INFORMATION* pFNIBuffer2; - - // The size of the file notification information buffer, in bytes. - DWORD fniBufferSizeInBytes; - - // Flags describing the state of the directory. - int flags; - -} drfsw_directory_win32; - -DRFSW_PRIVATE int drfsw_directory_win32_beginwatch(drfsw_directory_win32* pDirectory); - - -DRFSW_PRIVATE void drfsw_directory_win32_uninit(drfsw_directory_win32* pDirectory) -{ - if (pDirectory != NULL) - { - if (pDirectory->hDirectory != NULL) - { - CloseHandle(pDirectory->hDirectory); - pDirectory->hDirectory = NULL; - } - - drfsw_free(pDirectory->pFNIBuffer1); - pDirectory->pFNIBuffer1 = NULL; - - drfsw_free(pDirectory->pFNIBuffer2); - pDirectory->pFNIBuffer2 = NULL; - } -} - -DRFSW_PRIVATE int drfsw_directory_win32_init(drfsw_directory_win32* pDirectory, drfsw_context_win32* pContext, const char* absolutePath) -{ - if (pDirectory != NULL) - { - pDirectory->pContext = pContext; - drfsw_zeromemory(pDirectory->absolutePath, DRFSW_MAX_PATH); - pDirectory->hDirectory = NULL; - pDirectory->pFNIBuffer1 = NULL; - pDirectory->pFNIBuffer2 = NULL; - pDirectory->fniBufferSizeInBytes = 0; - pDirectory->flags = 0; - - size_t length = strlen(absolutePath); - if (length > 0) - { - memcpy(pDirectory->absolutePath, absolutePath, length); - pDirectory->absolutePath[length] = '\0'; - - wchar_t absolutePathWithBackSlashes[DRFSW_MAX_PATH_W]; - if (drfsw_to_win32_path_wchar(absolutePath, absolutePathWithBackSlashes)) - { - pDirectory->hDirectory = CreateFileW( - absolutePathWithBackSlashes, - FILE_LIST_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, - NULL); - if (pDirectory->hDirectory != INVALID_HANDLE_VALUE) - { - // From MSDN: - // - // Using a completion routine. To receive notification through a completion routine, do not associate the directory with a - // completion port. Specify a completion routine in lpCompletionRoutine. This routine is called whenever the operation has - // been completed or canceled while the thread is in an alertable wait state. The hEvent member of the OVERLAPPED structure - // is not used by the system, so you can use it yourself. - ZeroMemory(&pDirectory->overlapped, sizeof(pDirectory->overlapped)); - pDirectory->overlapped.hEvent = pDirectory; - - pDirectory->fniBufferSizeInBytes = WIN32_RDC_FNI_COUNT * sizeof(FILE_NOTIFY_INFORMATION); - pDirectory->pFNIBuffer1 = (FILE_NOTIFY_INFORMATION*)drfsw_malloc(pDirectory->fniBufferSizeInBytes); - pDirectory->pFNIBuffer2 = (FILE_NOTIFY_INFORMATION*)drfsw_malloc(pDirectory->fniBufferSizeInBytes); - if (pDirectory->pFNIBuffer1 != NULL && pDirectory->pFNIBuffer2 != NULL) - { - // At this point the directory is initialized, however it is not yet being watched. The watch needs to be triggered from - // the worker thread. To do this, we need to signal hPendingWatchEvent, however that needs to be done after the context - // has added the directory to it's internal list. - return 1; - } - else - { - drfsw_directory_win32_uninit(pDirectory); - } - } - else - { - drfsw_directory_win32_uninit(pDirectory); - } - } - else - { - drfsw_directory_win32_uninit(pDirectory); - } - } - } - - return 0; -} - -DRFSW_PRIVATE int drfsw_directory_win32_schedulewatch(drfsw_directory_win32* pDirectory) -{ - if (pDirectory != NULL) - { - pDirectory->flags |= WIN32_RDC_PENDING_WATCH; - QueueUserAPC(drfsw_win32_schedulewatchAPC, pDirectory->pContext->hThread, (ULONG_PTR)pDirectory); - - return 1; - } - - return 0; -} - -DRFSW_PRIVATE int drfsw_directory_win32_scheduledelete(drfsw_directory_win32* pDirectory) -{ - if (pDirectory != NULL) - { - pDirectory->flags |= WIN32_RDC_PENDING_DELETE; - QueueUserAPC(drfsw_win32_cancelioAPC, pDirectory->pContext->hThread, (ULONG_PTR)pDirectory); - - return 1; - } - - return 0; -} - -DRFSW_PRIVATE int drfsw_directory_win32_beginwatch(drfsw_directory_win32* pDirectory) -{ - // This function should only be called from the worker thread. - - if (pDirectory != NULL) - { - DWORD dwNotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION; - DWORD dwBytes = 0; - if (ReadDirectoryChangesW(pDirectory->hDirectory, pDirectory->pFNIBuffer1, pDirectory->fniBufferSizeInBytes, TRUE, dwNotifyFilter, &dwBytes, &pDirectory->overlapped, drfsw_win32_completionroutine)) - { - pDirectory->flags &= ~WIN32_RDC_PENDING_WATCH; - return 1; - } - } - - return 0; -} - - - - -DRFSW_PRIVATE int drfsw_directory_list_win32_init(drfsw_directory_list_win32* pDirectories) -{ - if (pDirectories != NULL) - { - drfsw_list_init(&pDirectories->list); - - pDirectories->hLock = CreateEvent(NULL, FALSE, TRUE, NULL); - if (pDirectories->hLock != NULL) - { - return 1; - } - } - - return 0; -} - -DRFSW_PRIVATE void drfsw_directory_list_win32_uninit(drfsw_directory_list_win32* pDirectories) -{ - if (pDirectories != NULL) - { - drfsw_list_uninit(&pDirectories->list); - - CloseHandle(pDirectories->hLock); - pDirectories->hLock = NULL; - } -} - - - - - -DRFSW_PRIVATE VOID CALLBACK drfsw_win32_completionroutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) -{ - drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)lpOverlapped->hEvent; - if (pDirectory != NULL) - { - if (dwErrorCode == ERROR_OPERATION_ABORTED) - { - // When we get here, CancelIo() was called on the directory. We treat this as a signal that the context has requested that the directory - // be deleted. At this point the directory has been removed from the context's internal list and we just need to uninitialize and free - // the directory object. - drfsw_context_win32* pContext = pDirectory->pContext; - drfsw_directory_win32_uninit(pDirectory); - drfsw_free(pDirectory); - - ReleaseSemaphore(pContext->hDeleteDirSemaphore, 1, NULL); - return; - } - - assert(dwNumberOfBytesTransfered >= sizeof(FILE_NOTIFY_INFORMATION)); - - // At this point we're not actually watching the directory - there is a chance that as we're executing this section there - // are changes to the file system whose events will go undetected. We need to call ReadDirectoryChangesW() again as soon as - // possible. This routine is always called from the worker thread, and only while it's in an alertable state. Therefore it - // is safe for us to use a simple front/back buffer type system to make it as quick as possible to resume watching operations. - FILE_NOTIFY_INFORMATION* temp = pDirectory->pFNIBuffer1; - pDirectory->pFNIBuffer1 = pDirectory->pFNIBuffer2; - pDirectory->pFNIBuffer2 = temp; - - - // Begin watching again (call ReadDirectoryChangesW() again) as soon as possible. At this point we are not currently watching - // for changes to the directory, so we need to start that before posting events. To start watching we need to send a signal to - // the worker thread which will do the actual call to ReadDirectoryChangesW(). - drfsw_directory_win32_schedulewatch(pDirectory); - - - // Now we loop through all of our notifications and post the event to the context for later processing by drfsw_next_event() - // and drfsw_peek_event(). - char absolutePathOld[DRFSW_MAX_PATH]; - char absoluteBasePathOld[DRFSW_MAX_PATH]; - drfsw_context_win32* pContext = pDirectory->pContext; // Just for convenience. - - - FILE_NOTIFY_INFORMATION* pFNI = pDirectory->pFNIBuffer2; - for (;;) - { - char relativePath[DRFSW_MAX_PATH]; - if (drfsw_from_win32_path(pFNI->FileName, pFNI->FileNameLength / sizeof(wchar_t), relativePath)) - { - char absolutePath[DRFSW_MAX_PATH]; - if (drfsw_make_absolute_path(pDirectory->absolutePath, relativePath, absolutePath)) - { - switch (pFNI->Action) - { - case FILE_ACTION_ADDED: - { - drfsw_event e; - if (drfsw_event_init(&e, drfsw_event_type_created, absolutePath, NULL, pDirectory->absolutePath, NULL)) - { - drfsw_postevent_win32(pContext, &e); - } - - break; - } - - case FILE_ACTION_REMOVED: - { - drfsw_event e; - if (drfsw_event_init(&e, drfsw_event_type_deleted, absolutePath, NULL, pDirectory->absolutePath, NULL)) - { - drfsw_postevent_win32(pContext, &e); - } - - break; - } - - case FILE_ACTION_RENAMED_OLD_NAME: - { - drfsw_strcpy(absolutePathOld, sizeof(absolutePathOld), absolutePath); - drfsw_strcpy(absoluteBasePathOld, sizeof(absoluteBasePathOld), pDirectory->absolutePath); - - break; - } - case FILE_ACTION_RENAMED_NEW_NAME: - { - drfsw_event e; - if (drfsw_event_init(&e, drfsw_event_type_renamed, absolutePathOld, absolutePath, absoluteBasePathOld, pDirectory->absolutePath)) - { - drfsw_postevent_win32(pContext, &e); - } - - break; - } - - case FILE_ACTION_MODIFIED: - { - drfsw_event e; - if (drfsw_event_init(&e, drfsw_event_type_updated, absolutePath, NULL, pDirectory->absolutePath, NULL)) - { - drfsw_postevent_win32(pContext, &e); - } - - break; - } - - default: break; - } - } - } - - - - if (pFNI->NextEntryOffset == 0) - { - break; - } - - pFNI = (FILE_NOTIFY_INFORMATION*)(((char*)pFNI) + pFNI->NextEntryOffset); - } - } -} - -DRFSW_PRIVATE VOID CALLBACK drfsw_win32_schedulewatchAPC(ULONG_PTR dwParam) -{ - drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)dwParam; - if (pDirectory != NULL) - { - if ((pDirectory->flags & WIN32_RDC_PENDING_WATCH) != 0) - { - drfsw_directory_win32_beginwatch(pDirectory); - } - } -} - -DRFSW_PRIVATE VOID CALLBACK drfsw_win32_cancelioAPC(ULONG_PTR dwParam) -{ - drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)dwParam; - if (pDirectory != NULL) - { - if ((pDirectory->flags & WIN32_RDC_PENDING_DELETE) != 0) - { - // We don't free the directory structure from here. Instead we just call CancelIo(). This will trigger - // the ERROR_OPERATION_ABORTED error in the notification callback which is where the real delete will - // occur. That is also where the synchronization lock is released that the thread that called - // drfsw_delete_directory() is waiting on. - CancelIo(pDirectory->hDirectory); - - // The directory needs to be removed from the context's list. The directory object will be freed in the - // notification callback in response to ERROR_OPERATION_ABORTED which will be triggered by the previous - // call to CancelIo(). - for (unsigned int i = 0; i < pDirectory->pContext->watchedDirectories.list.count; ++i) - { - if (pDirectory == pDirectory->pContext->watchedDirectories.list.buffer[i]) - { - drfsw_list_removebyindex(&pDirectory->pContext->watchedDirectories.list, i); - break; - } - } - } - } -} - - - - -DRFSW_PRIVATE DWORD WINAPI _WatcherThreadProc_RDC(drfsw_context_win32 *pContextRDC) -{ - while (!pContextRDC->terminateThread) - { - // Important that we use the Ex version here because we need to put the thread into an alertable state (last argument). If the thread is not put into - // an alertable state, ReadDirectoryChangesW() won't ever call the notification event. - DWORD rc = WaitForSingleObjectEx(pContextRDC->hTerminateEvent, INFINITE, TRUE); - switch (rc) - { - case WAIT_OBJECT_0 + 0: - { - // The context has signaled that it needs to be deleted. - pContextRDC->terminateThread = TRUE; - break; - } - - case WAIT_IO_COMPLETION: - default: - { - // Nothing to do. - break; - } - } - } - - return 0; -} - -DRFSW_PRIVATE drfsw_context* drfsw_create_context_win32() -{ - drfsw_context_win32* pContext = (drfsw_context_win32*)drfsw_malloc(sizeof(drfsw_context_win32)); - if (pContext != NULL) - { - if (drfsw_directory_list_win32_init(&pContext->watchedDirectories)) - { - if (drfsw_event_queue_init(&pContext->eventQueue)) - { - pContext->hTerminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - pContext->hDeleteDirSemaphore = CreateSemaphoreW(NULL, 0, 1, NULL); - pContext->terminateThread = FALSE; - - if (pContext->hTerminateEvent != NULL) - { - pContext->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_WatcherThreadProc_RDC, pContext, 0, NULL); - if (pContext->hThread != NULL) - { - // Everything went well. - } - else - { - CloseHandle(pContext->hTerminateEvent); - - drfsw_free(pContext); - pContext = NULL; - } - } - else - { - drfsw_free(pContext); - pContext = NULL; - } - } - } - } - - return (drfsw_context*)pContext; -} - -DRFSW_PRIVATE void drfsw_delete_context_win32(drfsw_context_win32* pContext) -{ - if (pContext != NULL) - { - // Every watched directory needs to be removed. - drfsw_remove_all_directories_win32(pContext); - - - // Signal the close event, and wait for the thread to finish. - SignalObjectAndWait(pContext->hTerminateEvent, pContext->hThread, INFINITE, FALSE); - - // The thread has finished, so close the handle. - CloseHandle(pContext->hThread); - pContext->hThread = NULL; - - - // We need to wait for the event queue to finish up before deleting the context for real. If we don't do this nextevent() may try - // to access the context and then crash. - WaitForSingleObject(pContext->eventQueue.hLock, INFINITE); - drfsw_event_queue_uninit(&pContext->eventQueue); // <-- This will close pContext->eventQueue.hLock so no need to call SetEvent(). - - - // The worker thread events need to be closed. - CloseHandle(pContext->hTerminateEvent); - pContext->hTerminateEvent = NULL; - - - // The semaphore we use for deleting directories. - CloseHandle(pContext->hDeleteDirSemaphore); - pContext->hDeleteDirSemaphore = NULL; - - - drfsw_directory_list_win32_uninit(&pContext->watchedDirectories); - - // Free the memory. - drfsw_free(pContext); - } -} - -DRFSW_PRIVATE drfsw_directory_win32* drfsw_find_directory_win32(drfsw_context_win32* pContext, const char* absolutePath, unsigned int* pIndexOut) -{ - assert(pContext != NULL); - - for (unsigned int iDirectory = 0; iDirectory < pContext->watchedDirectories.list.count; ++iDirectory) - { - drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)pContext->watchedDirectories.list.buffer[iDirectory]; - if (pDirectory != NULL) - { - if (strcmp(absolutePath, pDirectory->absolutePath) == 0) - { - if (pIndexOut != NULL) - { - *pIndexOut = iDirectory; - } - - return pDirectory; - } - } - } - - return NULL; -} - -DRFSW_PRIVATE int drfsw_add_directory_win32(drfsw_context_win32* pContext, const char* absolutePath) -{ - if (pContext != NULL) - { - drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)drfsw_malloc(sizeof(drfsw_directory_win32)); - if (pDirectory != NULL) - { - if (!drfsw_is_watching_directory_win32(pContext, absolutePath)) - { - if (drfsw_directory_win32_init(pDirectory, pContext, absolutePath)) - { - // At this point the directory has been initialized, but it's not yet being watched. To do this, we need to call ReadDirectoryChangesW() from - // the worker thread which means we need to signal an event which the worker thread will be waiting on. When the worker thread receives the - // signal, it will iterate over each directory in the context and check for the ones that are pending watching. Therefore, before signaling - // the event, we need to make sure the directory is added to the context's list. - WaitForSingleObject(pContext->watchedDirectories.hLock, INFINITE); - { - drfsw_list_pushback(&pContext->watchedDirectories.list, pDirectory); - } - SetEvent(pContext->watchedDirectories.hLock); - - // The directory is now in the list and we can send the signal. - drfsw_directory_win32_schedulewatch(pDirectory); - - - return 1; - } - else - { - drfsw_free(pDirectory); - pDirectory = NULL; - } - } - else - { - drfsw_free(pDirectory); - pDirectory = NULL; - } - } - } - - - - // An error occured if we got here. - return 0; -} - -DRFSW_PRIVATE void drfsw_remove_directory_win32_no_lock(drfsw_context_win32* pContext, const char* absolutePath) -{ - assert(pContext != NULL); - - unsigned int index; - drfsw_directory_win32* pDirectory = drfsw_find_directory_win32(pContext, absolutePath, &index); - if (pDirectory != NULL) - { - // When removing a directory, we need to call CancelIo() on the file handle we created for the directory. The problem is that - // this needs to be called on the worker thread in order for watcher notification callback function to get the correct error - // code. To do this we need to signal an event which the worker thread is waiting on. The worker thread will then call CancelIo() - // which in turn will trigger the correct error code in the notification callback. The notification callback is where the - // the object will be deleted for real and will release the synchronization lock that this function is waiting on below. - drfsw_directory_win32_scheduledelete(pDirectory); - - // Now we need to wait for the relevant event to become signaled. This will become signaled when the worker thread has finished - // deleting the file handle and whatnot from it's end. - WaitForSingleObject(pContext->hDeleteDirSemaphore, INFINITE); - } -} - -DRFSW_PRIVATE void drfsw_remove_directory_win32(drfsw_context_win32* pContext, const char* absolutePath) -{ - if (pContext != NULL) - { - WaitForSingleObject(pContext->watchedDirectories.hLock, INFINITE); - { - drfsw_remove_directory_win32_no_lock(pContext, absolutePath); - } - SetEvent(pContext->watchedDirectories.hLock); - } -} - -DRFSW_PRIVATE void drfsw_remove_all_directories_win32(drfsw_context_win32* pContext) -{ - if (pContext != NULL) - { - WaitForSingleObject(pContext->watchedDirectories.hLock, INFINITE); - { - for (unsigned int i = pContext->watchedDirectories.list.count; i > 0; --i) - { - drfsw_remove_directory_win32_no_lock(pContext, ((drfsw_directory_win32*)pContext->watchedDirectories.list.buffer[i - 1])->absolutePath); - } - } - SetEvent(pContext->watchedDirectories.hLock); - } -} - -DRFSW_PRIVATE int drfsw_is_watching_directory_win32(drfsw_context_win32* pContext, const char* absolutePath) -{ - if (pContext != NULL) - { - return drfsw_find_directory_win32(pContext, absolutePath, NULL) != NULL; - } - - return 0; -} - - -DRFSW_PRIVATE int drfsw_next_event_win32(drfsw_context_win32* pContext, drfsw_event* pEvent) -{ - int result = 0; - if (pContext != NULL && !pContext->terminateThread) - { - // Wait for either the semaphore or the thread to terminate. - HANDLE hEvents[2]; - hEvents[0] = pContext->hThread; - hEvents[1] = pContext->eventQueue.hSemaphore; - - DWORD rc = WaitForMultipleObjects(sizeof(hEvents) / sizeof(hEvents[0]), hEvents, FALSE, INFINITE); - switch (rc) - { - case WAIT_OBJECT_0 + 0: - { - // The thread has been terminated. - result = 0; - break; - } - - case WAIT_OBJECT_0 + 1: - { - // We're past the semaphore block, so now we can copy of the event. We need to lock the queue before doing this in case another thread wants - // to try pushing another event onto the queue. - if (!pContext->terminateThread) - { - DWORD eventLockResult = WaitForSingleObject(pContext->eventQueue.hLock, INFINITE); - if (eventLockResult == WAIT_OBJECT_0) - { - drfsw_event_queue_pop(&pContext->eventQueue, pEvent); - } - SetEvent(pContext->eventQueue.hLock); - - if (eventLockResult == WAIT_OBJECT_0) - { - result = 1; - } - else - { - // The lock returned early for some reason which means there must have been some kind of error or the context has been destroyed. - result = 0; - } - } - - break; - } - - default: break; - } - } - - return result; -} - -DRFSW_PRIVATE int drfsw_peek_event_win32(drfsw_context_win32* pContext, drfsw_event* pEvent) -{ - int result = 0; - if (pContext != NULL) - { - DWORD eventLockResult = WaitForSingleObject(pContext->eventQueue.hLock, INFINITE); - { - // Make sure we decrement our semaphore counter. Don't block here. - WaitForSingleObject(pContext->eventQueue.hSemaphore, 0); - - // Now we just copy over the data by popping it from the queue. - if (eventLockResult == WAIT_OBJECT_0) - { - if (drfsw_event_queue_getcount(&pContext->eventQueue) > 0) - { - drfsw_event_queue_pop(&pContext->eventQueue, pEvent); - result = 1; - } - else - { - result = 0; - } - } - else - { - // Waiting on the event queue lock failed for some reason. It could mean that the context has been deleted. - result = 0; - } - } - SetEvent(pContext->eventQueue.hLock); - } - - return result; -} - -DRFSW_PRIVATE void drfsw_postevent_win32(drfsw_context_win32* pContext, drfsw_event* pEvent) -{ - if (pContext != NULL && pEvent != NULL) - { - // Add the event to the queue. - WaitForSingleObject(pContext->eventQueue.hLock, INFINITE); - { - drfsw_event_queue_pushback(&pContext->eventQueue, pEvent); - } - SetEvent(pContext->eventQueue.hLock); - - - // Release the semaphore so that drfsw_next_event() can handle it. - ReleaseSemaphore(pContext->eventQueue.hSemaphore, 1, NULL); - } -} - - - -//////////////////////////////////// -// Public API for Win32 - -drfsw_context* drfsw_create_context() -{ - return drfsw_create_context_win32(); -} - -void drfsw_delete_context(drfsw_context* pContext) -{ - drfsw_delete_context_win32((drfsw_context_win32*)pContext); -} - - -int drfsw_add_directory(drfsw_context* pContext, const char* absolutePath) -{ - return drfsw_add_directory_win32((drfsw_context_win32*)pContext, absolutePath); -} - -void drfsw_remove_directory(drfsw_context* pContext, const char* absolutePath) -{ - drfsw_remove_directory_win32((drfsw_context_win32*)pContext, absolutePath); -} - -void drfsw_remove_all_directories(drfsw_context* pContext) -{ - drfsw_remove_all_directories_win32((drfsw_context_win32*)pContext); -} - -int drfsw_is_watching_directory(drfsw_context* pContext, const char* absolutePath) -{ - return drfsw_is_watching_directory_win32((drfsw_context_win32*)pContext, absolutePath); -} - - -int drfsw_next_event(drfsw_context* pContext, drfsw_event* pEventOut) -{ - return drfsw_next_event_win32((drfsw_context_win32*)pContext, pEventOut); -} - -int drfsw_peek_event(drfsw_context* pContext, drfsw_event* pEventOut) -{ - return drfsw_peek_event_win32((drfsw_context_win32*)pContext, pEventOut); -} - - -#endif // Win32 - - -#if defined(__clang__) - #pragma GCC diagnostic pop -#endif - -#endif //DR_FSW_IMPLEMENTATION - - - - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_gui.h b/source/engine/thirdparty/dr_libs/old/dr_gui.h deleted file mode 100644 index 7283223..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_gui.h +++ /dev/null @@ -1,17167 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. - -// QUICK NOTES -// -// General -// - dr_gui is a low-level GUI system that works on generic objects referred to as "elements". -// - An element is the most basic unit in dr_gui. It contains basic information about it's layout and hierarchy. -// - Elements can be used as the building blocks for more complex controls such as list boxes and scrollbars. -// - The layout of elements use floats instead of integers. The rationale for this is that it makes it easier to do certain -// layout arithmetic. For example, if you want to evenly distribute 3 elements across a fixed area, the integer based -// arithmetic can cause rounding errors which cause the elements to not sit flush against the area. By using float-based -// arithmetic we can avoid that particular issue. -// -// Hierarchy -// - An element can have a parent and any number of children. If an element does not have a parent, it is referred to as the -// top-level element. -// - When an element is deleted, it's children will be deleted as well. -// - Top-level elements do not have siblings. -// -// Event Handling -// - The application must notify dr_gui of application-generated events such as key strokes and mouse movements. These are -// referred to as inbound events. An event that is generated by dr_gui are referred to as outbound events. -// - Inbound events are used to generate outbound events. For example, a mouse-move inbound event will generate an outbound -// mouse-move event, and perhaps a mouse leave/enter pair. -// - Outbound events are posted and handled immediately. A call to drgui_post_inbound_event() will not return until all of -// the outbound events it generates have been handled. -// - Inbound events are not thread safe, however an application is free to post an inbound event from any thread so long as -// it does it's own synchronization. -// - Inbound events will typically specify the relevant top-level element and let dr_gui do the relevant processing required -// to generate the appropriate outbound events. For example, the mouse-move event will be specified with respect to the top- -// level element, but dr_gui will determine the exact child element that the mouse moved on and thus should receive the -// relevant outbound mouse-move event. -// - There are some special events that are handled differently to normal events. The best example is the paint events. The -// paint event is only called from drgui_draw(). -// - Key press/release events are only ever posted to the element that has the keyboard capture/focus which is set with -// drgui_capture_keyboard(). Thus, when posting an inbound key event, a top-level element is not required when posting -// those events. The relevant context is still required, however. -// -// Global Outbound Event Handling -// - At times dr_gui will need to notify the host application in order for certain functionality to work properly. For example. -// when the mouse is captured it won't work 100% correct unless the host application has a chance to capture the mouse against -// the container window. Because dr_gui has no notion of a window system it relies on the host application to handle this -// properly. -// - A global outbound event handler should be implemented for each of the following events: -// - on_dirty: Called when a region of an element is marked as dirty and needs to be redrawn. The application will want to -// invalidate the container window to trigger an operating system redraw. Set this with drgui_set_global_on_dirty(). -// - on_capture_mouse: Called when the mouse is captured and gives the application the opportunity to capture the mouse against -// the container window at the operating system level. Set with drgui_set_global_on_capture_mouse(). -// - on_release_mouse: Called when the mouse is released. The opposite of on_capture_mouse. -// - on_capture_keyboard: Called when an element is given the keyboard focus and gives the application the opportunity to -// apply the keyboard focus to the container window. Set with drgui_set_global_on_capture_keyboard(). -// - on_release_keyboard: Called when an element loses the keyboard focus. The opposite of on_capture_keyboard. -// - on_change_cursor: Called when the current cursor needs to be changed as a result of the mouse moving over a new element. -// -// Layout -// - An element's data structure does not store it's relative position but instead stores it's absolute position. The rationale -// for this is that storing it as relative complicates absolute positioning calculations because it would need to do a recursive -// traversal of the element's ancestors. -// - Child elements can be scaled by setting an element's inner scale. The inner scale does not scale the element itself - only -// it's children. -// - When an element is drawn, everything is scaled by it's inner scale. For example, if the inner scale is 2x and a 100x100 quad -// is drawn, the quad will be scaled to 200x200. An exception to this rule is fonts, which are never scaled. This 0s because -// text is always drawn based on the size of the font. -// - Applications should only need to work on unscaled coordinates. That is, an application should never need to worry about -// manual scaling, except for fonts. When positioning and sizing child elements, they should be done based on unscaled -// coordinates. -// - Use the inner scale system for DPI awareness. -// - The inner scale is applied recursively. That is, if a top level element has it's inner scale set to 2x and one of it's -// children has an inner scale of 2x, the actual inner scale of the child element will be 4x. -// -// -// Drawing/Painting -// - Drawing is one of the more complex parts of the GUI because it can be a bit unintuitive regarding exactly when an element -// is drawn and when a drawing function is allowed to be called. -// - To draw an element, call drgui_draw(). This takes a pointer to the element to draw and the rectangle region that should -// be redrawn. Any children that fall inside the specified rectangle region will be redrawn as well. You do not want to call -// drgui_draw() on a parent element and then again on it's children because dr_gui will do that automatically. -// - drgui_draw() does not draw anything directly, but rather calls painting callback routines which is where the actual -// drawing takes place. -// - Sometimes an application will need to be told when a region of an element is dirty and needs redrawing. An example is -// event-driven, non real-time applications such as normal desktop applications. To mark an element as dirty, you call the -// drgui_dirty() function which takes the element that is dirty, and the rectangle region that needs to be redrawn. This -// does not redraw the element immediately, but instead posts an on_dirty event for the application. Marking regions as dirty -// is not strictly required, but you should prefer it for event-driven applications that require painting operations to be -// performed at specific times (such as inside Win32's WM_PAINT messages). -// - Some operations will cause a region of an element to become dirty - such as when it is resized. dr_gui will -// automatically mark the relevant regions as dirty which in turn will cause a paint message to be posted. If this is not -// required, it can be disabled with drgui_disable_auto_dirty(). You may want to disable automatic dirtying if you are -// running a real-time application like a game which would redraw the entire GUI every frame anyway and thus not require -// handling of the paint message. -// - Real-time application guidelines (games, etc.): -// - drgui_disable_auto_dirty() -// - drgui_draw(pTopLevelElement, 0, 0, viewportWidth, viewportHeight) at the end of every frame after your main loop. -// - - -// -// OPTIONS -// -// #define DRGUI_NO_DR_2D -// Disable dr_2d integration. Disabling dr_2d will require you to implement your own drawing callbacks. -// -// #define DRGUI_NO_TEXT_EDITING -// Disables the text box control and text engine. - - -// -// EXAMPLES -// -// Basic Drawing: -// -// drgui_draw(pTopLevelElement, 0, 0, drgui_get_width(pTopLevelElement), drgui_get_height(pTopLevelElement)); -// -// ------------------------- -// -// Event-Driven Drawing (Win32): -// -// void my_global_on_dirty_win32(drgui_element* pElement, drgui_rect relativeRect) { -// drgui_rect absoluteRect = relativeRect; -// drgui_make_rect_absolute(pElement, &absoluteRect); -// -// RECT rect; -// rect.left = absoluteRect.left; -// rect.top = absoluteRect.top; -// rect.right = absoluteRect.right; -// rect.height = absoluteRect.bottom; -// InvalidateRect((HWND)drgui_get_user_data(drgui_find_top_level_element(pElement)), &rect, FALSE); -// } -// -// ... -// -// LRESULT CALLBACK MyWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { -// ... -// drgui_element* pTopLevelElement = (drgui_element*)GetWindowLongPtr(hWnd, 0); -// if (pTopLevelElement != NULL) { -// switch (msg) { -// ... -// case WM_PAINT: -// { -// RECT rect; -// if (GetUpdateRect(hWnd, &rect, FALSE)) { -// drgui_draw(pTopLevelElement, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); -// } -// -// break; -// } -// ... -// } -// } -// ... -// } -// - - - -#ifndef dr_gui_h -#define dr_gui_h - -#ifndef DRGUI_NO_DR_2D -// If you're using easy_draw integration, set the path below to the relative location of dr_2d. By default, the -// following structure is assumed: -// -// - dr_libs -// - dr_2d.h -// - dr_gui.h -#include "dr_2d.h" -#endif - -#include - -#ifndef DRGUI_MAX_FONT_FAMILY_LENGTH -#define DRGUI_MAX_FONT_FAMILY_LENGTH 128 -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct drgui_context drgui_context; -typedef struct drgui_element drgui_element; -typedef struct drgui_color drgui_color; -typedef struct drgui_rect drgui_rect; -typedef struct drgui_painting_callbacks drgui_painting_callbacks; -typedef struct drgui_font drgui_font; -typedef struct drgui_image drgui_image; -typedef struct drgui_font_metrics drgui_font_metrics; -typedef struct drgui_glyph_metrics drgui_glyph_metrics; - -typedef unsigned char drgui_byte; -typedef unsigned int drgui_key; - -typedef void* drgui_resource; - -/// Common system cursors. -typedef enum -{ - drgui_cursor_none, - drgui_cursor_default, - drgui_cursor_arrow = drgui_cursor_default, - drgui_cursor_text, - drgui_cursor_cross, - drgui_cursor_size_ns, // North/South resize arrows. - drgui_cursor_size_we, // West/East resize arrows. - drgui_cursor_size_nesw, // North/East, South/West resize arrows. - drgui_cursor_size_nwse // North/West, South/East resize arrows. -} drgui_cursor_type; - -/// Font weights. -typedef enum -{ - drgui_font_weight_medium, - drgui_font_weight_thin, - drgui_font_weight_extra_light, - drgui_font_weight_light, - drgui_font_weight_semi_light, - drgui_font_weight_book, - drgui_font_weight_semi_bold, - drgui_font_weight_bold, - drgui_font_weight_extra_bold, - drgui_font_weight_heavy, - drgui_font_weight_extra_heavy, - - drgui_font_weight_normal = drgui_font_weight_medium, - drgui_font_weight_default = drgui_font_weight_medium - -} drgui_font_weight; - -/// Font slants. -typedef enum -{ - drgui_font_slant_none, - drgui_font_slant_italic, - drgui_font_slant_oblique - -} drgui_font_slant; - -/// Image formats. -typedef enum -{ - drgui_image_format_rgba8, - drgui_image_format_bgra8, - drgui_image_format_argb8, -} drgui_image_format; - - -/// Font metrics. -struct drgui_font_metrics -{ - int ascent; - int descent; - int lineHeight; - int spaceWidth; -}; - -/// Glyph metrics. -struct drgui_glyph_metrics -{ - int width; - int height; - int originX; - int originY; - int advanceX; - int advanceY; -}; - - -/// Structure representing an RGBA color. Color components are specified in the range of 0 - 255. -struct drgui_color -{ - drgui_byte r; - drgui_byte g; - drgui_byte b; - drgui_byte a; -}; - -/// Structure representing a rectangle. -struct drgui_rect -{ - float left; - float top; - float right; - float bottom; -}; - - -#define DRGUI_IMAGE_DRAW_BACKGROUND (1 << 0) -#define DRGUI_IMAGE_HINT_NO_ALPHA (1 << 1) -#define DRGUI_IMAGE_DRAW_BOUNDS (1 << 2) -#define DRGUI_IMAGE_CLIP_BOUNDS (1 << 3) //< Clips the image to the bounds -#define DRGUI_IMAGE_ALIGN_CENTER (1 << 4) - -#define DRGUI_READ (1 << 0) -#define DRGUI_WRITE (1 << 1) - -#define DRGUI_FONT_NO_CLEARTYPE (1 << 0) - -typedef struct -{ - /// The destination position on the x axis. This is ignored if the DR2D_IMAGE_ALIGN_CENTER option is set. - float dstX; - - /// The destination position on the y axis. This is ignored if the DR2D_IMAGE_ALIGN_CENTER option is set. - float dstY; - - /// The destination width. - float dstWidth; - - /// The destination height. - float dstHeight; - - - /// The source offset on the x axis. - float srcX; - - /// The source offset on the y axis. - float srcY; - - /// The source width. - float srcWidth; - - /// The source height. - float srcHeight; - - - /// The position of the destination's bounds on the x axis. - float dstBoundsX; - - /// The position of the destination's bounds on the y axis. - float dstBoundsY; - - /// The width of the destination's bounds. - float dstBoundsWidth; - - /// The height of the destination's bounds. - float dstBoundsHeight; - - - /// The foreground tint color. This is not applied to the background color, and the alpha component is ignored. - drgui_color foregroundTint; - - /// The background color. Only used if the DR2D_IMAGE_DRAW_BACKGROUND option is set. - drgui_color backgroundColor; - - /// The bounds color. This color is used for the region of the bounds that sit on the outside of the destination rectangle. This will - /// usually be set to the same value as backgroundColor, but it could also be used to draw a border around the image. - drgui_color boundsColor; - - - /// Flags for controlling how the image should be drawn. - unsigned int options; - -} drgui_draw_image_args; - - -typedef void (* drgui_callback)(); - -typedef void (* drgui_on_move_proc) (drgui_element* pElement, float newRelativePosX, float newRelativePosY); -typedef void (* drgui_on_size_proc) (drgui_element* pElement, float newWidth, float newHeight); -typedef void (* drgui_on_mouse_enter_proc) (drgui_element* pElement); -typedef void (* drgui_on_mouse_leave_proc) (drgui_element* pElement); -typedef void (* drgui_on_mouse_move_proc) (drgui_element* pElement, int relativeMousePosX, int relativeMousePosY, int stateFlags); -typedef void (* drgui_on_mouse_button_down_proc) (drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); -typedef void (* drgui_on_mouse_button_up_proc) (drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); -typedef void (* drgui_on_mouse_button_dblclick_proc)(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); -typedef void (* drgui_on_mouse_wheel_proc) (drgui_element* pElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags); -typedef void (* drgui_on_key_down_proc) (drgui_element* pElement, drgui_key key, int stateFlags); -typedef void (* drgui_on_key_up_proc) (drgui_element* pElement, drgui_key key, int stateFlags); -typedef void (* drgui_on_printable_key_down_proc) (drgui_element* pElement, unsigned int character, int stateFlags); -typedef void (* drgui_on_paint_proc) (drgui_element* pElement, drgui_rect relativeRect, void* pPaintData); -typedef void (* drgui_on_dirty_proc) (drgui_element* pElement, drgui_rect relativeRect); -typedef bool (* drgui_on_hittest_proc) (drgui_element* pElement, float relativePosX, float relativePosY); -typedef void (* drgui_on_capture_mouse_proc) (drgui_element* pElement); -typedef void (* drgui_on_release_mouse_proc) (drgui_element* pElement); -typedef void (* drgui_on_capture_keyboard_proc) (drgui_element* pElement, drgui_element* pPrevCapturedElement); -typedef void (* drgui_on_release_keyboard_proc) (drgui_element* pElement, drgui_element* pNewCapturedElement); -typedef void (* drgui_on_change_cursor_proc) (drgui_element* pElement, drgui_cursor_type cursor); -typedef void (* drgui_on_delete_element_proc) (drgui_element* pElement); -typedef void (* drgui_on_log) (drgui_context* pContext, const char* message); - -typedef void (* drgui_draw_begin_proc) (void* pPaintData); -typedef void (* drgui_draw_end_proc) (void* pPaintData); -typedef void (* drgui_set_clip_proc) (drgui_rect relativeRect, void* pPaintData); -typedef void (* drgui_get_clip_proc) (drgui_rect* pRectOut, void* pPaintData); -typedef void (* drgui_draw_line_proc) (float startX, float startY, float endX, float endY, float width, drgui_color color, void* pPaintData); -typedef void (* drgui_draw_rect_proc) (drgui_rect relativeRect, drgui_color color, void* pPaintData); -typedef void (* drgui_draw_rect_outline_proc) (drgui_rect relativeRect, drgui_color color, float outlineWidth, void* pPaintData); -typedef void (* drgui_draw_rect_with_outline_proc) (drgui_rect relativeRect, drgui_color color, float outlineWidth, drgui_color outlineColor, void* pPaintData); -typedef void (* drgui_draw_round_rect_proc) (drgui_rect relativeRect, drgui_color color, float radius, void* pPaintData); -typedef void (* drgui_draw_round_rect_outline_proc) (drgui_rect relativeRect, drgui_color color, float radius, float outlineWidth, void* pPaintData); -typedef void (* drgui_draw_round_rect_with_outline_proc) (drgui_rect relativeRect, drgui_color color, float radius, float outlineWidth, drgui_color outlineColor, void* pPaintData); -typedef void (* drgui_draw_text_proc) (drgui_resource font, const char* text, int textLengthInBytes, float posX, float posY, drgui_color color, drgui_color backgroundColor, void* pPaintData); -typedef void (* drgui_draw_image_proc) (drgui_resource image, drgui_draw_image_args* pArgs, void* pPaintData); - -typedef drgui_resource (* drgui_create_font_proc) (void* pPaintingContext, const char* family, unsigned int size, drgui_font_weight weight, drgui_font_slant slant, float rotation, unsigned int flags); -typedef void (* drgui_delete_font_proc) (drgui_resource font); -typedef unsigned int (* drgui_get_font_size_proc) (drgui_resource font); -typedef bool (* drgui_get_font_metrics_proc) (drgui_resource font, drgui_font_metrics* pMetricsOut); -typedef bool (* drgui_get_glyph_metrics_proc) (drgui_resource font, unsigned int utf32, drgui_glyph_metrics* pMetricsOut); -typedef bool (* drgui_measure_string_proc) (drgui_resource font, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut); -typedef bool (* drgui_get_text_cursor_position_from_point_proc)(drgui_resource font, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); -typedef bool (* drgui_get_text_cursor_position_from_char_proc) (drgui_resource font, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - -typedef drgui_resource (* drgui_create_image_proc) (void* pPaintingContext, unsigned int width, unsigned int height, drgui_image_format format, unsigned int stride, const void* pImageData); -typedef void (* drgui_delete_image_proc) (drgui_resource image); -typedef drgui_image_format (* drgui_get_optimal_image_format_proc)(void* pPaintingContext); -typedef void (* drgui_get_image_size_proc) (drgui_resource image, unsigned int* pWidthOut, unsigned int* pHeightOut); -typedef void* (* drgui_map_image_data_proc) (drgui_resource image, unsigned int accessFlags); -typedef void (* drgui_unmap_image_data_proc) (drgui_resource image); - -typedef bool (* drgui_visible_iteration_proc)(drgui_element* pElement, drgui_rect *pRelativeRect, void* pUserData); - - -// Key state flags. -#define DRGUI_MOUSE_BUTTON_LEFT_DOWN (1 << 0) -#define DRGUI_MOUSE_BUTTON_RIGHT_DOWN (1 << 1) -#define DRGUI_MOUSE_BUTTON_MIDDLE_DOWN (1 << 2) -#define DRGUI_MOUSE_BUTTON_4_DOWN (1 << 3) -#define DRGUI_MOUSE_BUTTON_5_DOWN (1 << 4) -#define DRGUI_KEY_STATE_SHIFT_DOWN (1 << 5) // Whether or not a shift key is down at the time the input event is handled. -#define DRGUI_KEY_STATE_CTRL_DOWN (1 << 6) // Whether or not a ctrl key is down at the time the input event is handled. -#define DRGUI_KEY_STATE_ALT_DOWN (1 << 7) // Whether or not an alt key is down at the time the input event is handled. -#define DRGUI_KEY_STATE_AUTO_REPEATED (1 << 31) // Whether or not the key press is generated due to auto-repeating. Only used with key down events. - -// Common mouse buttons. -#define DRGUI_MOUSE_BUTTON_LEFT 1 -#define DRGUI_MOUSE_BUTTON_RIGHT 2 -#define DRGUI_MOUSE_BUTTON_MIDDLE 3 - -// Common key codes. -#define DRGUI_BACKSPACE 0xff08 -#define DRGUI_SHIFT 0xff10 -#define DRGUI_ESCAPE 0xff1b -#define DRGUI_PAGE_UP 0xff55 -#define DRGUI_PAGE_DOWN 0xff56 -#define DRGUI_END 0xff57 -#define DRGUI_HOME 0xff50 -#define DRGUI_ARROW_LEFT 0x8fb -#define DRGUI_ARROW_UP 0x8fc -#define DRGUI_ARROW_RIGHT 0x8fd -#define DRGUI_ARROW_DOWN 0x8fe -#define DRGUI_DELETE 0xffff -#define DRGUI_F1 0xffbe -#define DRGUI_F2 0xffbf -#define DRGUI_F3 0xffc0 -#define DRGUI_F4 0xffc1 -#define DRGUI_F5 0xffc2 -#define DRGUI_F6 0xffc3 -#define DRGUI_F7 0xffc4 -#define DRGUI_F8 0xffc5 -#define DRGUI_F9 0xffc6 -#define DRGUI_F10 0xffc7 -#define DRGUI_F11 0xffc8 -#define DRGUI_F12 0xffc9 - -static size_t drgui_strcpy(char* dst, size_t dstSize, const char* src) -{ - if (strcpy_s(dst, dstSize, src) == 0) { - return strlen(dst); - } - - return 0; -} - -static inline size_t drgui_key_to_string(drgui_key key, char* strOut, size_t strOutSize) -{ - if (strOut == NULL || strOutSize == 0) { - return 0; - } - - if (strOutSize == 1) { - strOut[0] = '\0'; - return 0; - } - - - switch (key) - { - case DRGUI_BACKSPACE: return drgui_strcpy(strOut, strOutSize, "Backspace"); - case DRGUI_SHIFT: return drgui_strcpy(strOut, strOutSize, "Shift"); - case DRGUI_ESCAPE: return drgui_strcpy(strOut, strOutSize, "Escape"); - case DRGUI_PAGE_UP: return drgui_strcpy(strOut, strOutSize, "Page Up"); - case DRGUI_PAGE_DOWN: return drgui_strcpy(strOut, strOutSize, "Page Down"); - case DRGUI_END: return drgui_strcpy(strOut, strOutSize, "End"); - case DRGUI_HOME: return drgui_strcpy(strOut, strOutSize, "Home"); - case DRGUI_ARROW_LEFT: return drgui_strcpy(strOut, strOutSize, "Arrow Left"); - case DRGUI_ARROW_UP: return drgui_strcpy(strOut, strOutSize, "Arrow Up"); - case DRGUI_ARROW_RIGHT: return drgui_strcpy(strOut, strOutSize, "Arrow Right"); - case DRGUI_ARROW_DOWN: return drgui_strcpy(strOut, strOutSize, "Arrow Down"); - case DRGUI_DELETE: return drgui_strcpy(strOut, strOutSize, "Delete"); - case DRGUI_F1: return drgui_strcpy(strOut, strOutSize, "F1"); - case DRGUI_F2: return drgui_strcpy(strOut, strOutSize, "F2"); - case DRGUI_F3: return drgui_strcpy(strOut, strOutSize, "F3"); - case DRGUI_F4: return drgui_strcpy(strOut, strOutSize, "F4"); - case DRGUI_F5: return drgui_strcpy(strOut, strOutSize, "F5"); - case DRGUI_F6: return drgui_strcpy(strOut, strOutSize, "F6"); - case DRGUI_F7: return drgui_strcpy(strOut, strOutSize, "F7"); - case DRGUI_F8: return drgui_strcpy(strOut, strOutSize, "F8"); - case DRGUI_F9: return drgui_strcpy(strOut, strOutSize, "F9"); - case DRGUI_F10: return drgui_strcpy(strOut, strOutSize, "F10"); - case DRGUI_F11: return drgui_strcpy(strOut, strOutSize, "F11"); - case DRGUI_F12: return drgui_strcpy(strOut, strOutSize, "F12"); - } - - if (key >= 32 && key <= 126) { - strOut[0] = (char)key; - strOut[1] = '\0'; - return 1; - } - - // TODO: Non-ascii characters. - return 0; -} - -static inline drgui_key drgui_key_parse(const char* str) -{ - if (str == NULL || str[0] == '\0') { - return 0; - } - - if (_stricmp(str, "backspace") == 0) return DRGUI_BACKSPACE; - if (_stricmp(str, "shift") == 0) return DRGUI_SHIFT; - if (_stricmp(str, "escape") == 0) return DRGUI_ESCAPE; - if (_stricmp(str, "page up") == 0 || _stricmp(str, "pageup") == 0) return DRGUI_PAGE_UP; - if (_stricmp(str, "page down") == 0 || _stricmp(str, "pagedown") == 0) return DRGUI_PAGE_DOWN; - if (_stricmp(str, "end") == 0) return DRGUI_END; - if (_stricmp(str, "home") == 0) return DRGUI_HOME; - if (_stricmp(str, "arrow left") == 0 || _stricmp(str, "arrowleft") == 0) return DRGUI_ARROW_LEFT; - if (_stricmp(str, "arrow up") == 0 || _stricmp(str, "arrowup") == 0) return DRGUI_ARROW_UP; - if (_stricmp(str, "arrow right") == 0 || _stricmp(str, "arrowright") == 0) return DRGUI_ARROW_RIGHT; - if (_stricmp(str, "arrow down") == 0 || _stricmp(str, "arrowdown") == 0) return DRGUI_ARROW_DOWN; - if (_stricmp(str, "delete") == 0) return DRGUI_BACKSPACE; - - if (str[0] == 'F' || str[0] == 'f') { - if (str[1] == '1') { - if (str[2] == '\0') { - return DRGUI_F1; - } else { - if (str[2] == '0' && str[2] == '\0') return DRGUI_F10; - if (str[2] == '1' && str[2] == '\0') return DRGUI_F11; - if (str[2] == '2' && str[2] == '\0') return DRGUI_F12; - } - } - if (str[1] == '2' && str[2] == '\0') return DRGUI_F2; - if (str[1] == '3' && str[2] == '\0') return DRGUI_F3; - if (str[1] == '4' && str[2] == '\0') return DRGUI_F4; - if (str[1] == '5' && str[2] == '\0') return DRGUI_F5; - if (str[1] == '6' && str[2] == '\0') return DRGUI_F6; - if (str[1] == '7' && str[2] == '\0') return DRGUI_F7; - if (str[1] == '8' && str[2] == '\0') return DRGUI_F8; - if (str[1] == '9' && str[2] == '\0') return DRGUI_F9; - } - - - // ASCII characters. - if (str[0] >= 32 && str[0] <= 126 && str[1] == '\0') { - return str[0]; - } - - if (_stricmp(str, "tab") == 0) { - return '\t'; - } - - - // TODO: Non-ascii characters. - return 0; -} - - -/// Structure containing callbacks for painting routines. -struct drgui_painting_callbacks -{ - drgui_draw_begin_proc drawBegin; - drgui_draw_end_proc drawEnd; - - drgui_set_clip_proc setClip; - drgui_get_clip_proc getClip; - - drgui_draw_line_proc drawLine; - drgui_draw_rect_proc drawRect; - drgui_draw_rect_outline_proc drawRectOutline; - drgui_draw_rect_with_outline_proc drawRectWithOutline; - drgui_draw_round_rect_proc drawRoundRect; - drgui_draw_round_rect_outline_proc drawRoundRectOutline; - drgui_draw_round_rect_with_outline_proc drawRoundRectWithOutline; - drgui_draw_text_proc drawText; - drgui_draw_image_proc drawImage; - - drgui_create_font_proc createFont; - drgui_delete_font_proc deleteFont; - drgui_get_font_size_proc getFontSize; - drgui_get_font_metrics_proc getFontMetrics; - drgui_get_glyph_metrics_proc getGlyphMetrics; - drgui_measure_string_proc measureString; - drgui_get_text_cursor_position_from_point_proc getTextCursorPositionFromPoint; - drgui_get_text_cursor_position_from_char_proc getTextCursorPositionFromChar; - - drgui_create_image_proc createImage; - drgui_delete_image_proc deleteImage; - drgui_get_optimal_image_format_proc getOptimalImageFormat; - drgui_get_image_size_proc getImageSize; - drgui_map_image_data_proc mapImageData; - drgui_unmap_image_data_proc unmapImageData; -}; - -struct drgui_image -{ - /// A pointer to the context that owns this image. - drgui_context* pContext; - - /// The resource handle that is passed around to the callback functions. - drgui_resource hResource; -}; - -struct drgui_font -{ - /// A pointer to the context that owns this font. - drgui_context* pContext; - - /// The font family. - char family[DRGUI_MAX_FONT_FAMILY_LENGTH]; - - /// The base size of the font. This is set to the value that was used to create the font in the first place. - unsigned int size; - - /// The font's weight. - drgui_font_weight weight; - - /// The fon't slant. - drgui_font_slant slant; - - /// The fon't rotation. - float rotation; - - /// The font's flags. Can be a combination of the following: - /// DRGUI_FONT_NO_CLEARTYPE - unsigned int flags; - - /// The internal font. This is created by the rendering backend. - drgui_resource internalFont; -}; - - -struct drgui_element -{ - /// A pointer to the context that owns this element. This should never be null for valid elements. - drgui_context* pContext; - - - /// A pointer to the parent element. This can be null in which case this element is the parent. - drgui_element* pParent; - - /// A pointer to the first child element. - drgui_element* pFirstChild; - - /// A pointer to the last child element. - drgui_element* pLastChild; - - /// A pointer to the next sibling element. - drgui_element* pNextSibling; - - /// A pointer ot the previous sibing element. - drgui_element* pPrevSibling; - - - /// A pointer to the next dead element. When an element is deleted during an event handler it is not deleted straight away but - /// rather at the end of the current batch of event processing. Dead elements are stored in a linked list, with this pointer - /// acting as the link between items. This will be null if the element is the last in the list, or is not marked as dead. Note - /// that this should not be used to check if the element is marked as dead - use the IS_ELEMENT_DEAD flag instead. - drgui_element* pNextDeadElement; - - - /// The type of the element, as a string. This is only every used by the host application, and is intended to be used as way - /// to selectively perform certain operations on specific types of GUI elements. - char type[64]; - - - /// The absolute position of the element on the x axis. A position of 0 is the left side of the surface it is attached to. - float absolutePosX; - - /// The absolute position of the element on the y axis. A position of 0 is the top of the surface it is attached to. - float absolutePosY; - - /// The width of the element. - float width; - - /// The height of the element. - float height; - - - /// The cursor. Defaults to drge_cursor_default. - drgui_cursor_type cursor; - - /// Boolean flags. - unsigned int flags; - - // The region of the element that's dirty. - drgui_rect dirtyRect; - - - /// The function to call when the element's relative position moves. - drgui_on_move_proc onMove; - - /// The function to call when the element's size changes. - drgui_on_size_proc onSize; - - /// The function to call when the mouse enters the given element. - drgui_on_mouse_enter_proc onMouseEnter; - - /// The function to call when the mouse leaves the given element. - drgui_on_mouse_leave_proc onMouseLeave; - - /// The function to call when the mouse is moved while over the element. - drgui_on_mouse_move_proc onMouseMove; - - /// The function to call when a mouse buttonis pressed while over the element. - drgui_on_mouse_button_down_proc onMouseButtonDown; - - /// The function to call when a mouse button is released while over the element. - drgui_on_mouse_button_up_proc onMouseButtonUp; - - /// The function to call when a mouse button is double-clicked while over the element. - drgui_on_mouse_button_dblclick_proc onMouseButtonDblClick; - - /// The function to call when the mouse wheel it turned while over the element. - drgui_on_mouse_wheel_proc onMouseWheel; - - /// The function to call when a key on the keyboard is pressed or auto-repeated. - drgui_on_key_down_proc onKeyDown; - - /// The function to call when a key on the keyboard is released. - drgui_on_key_up_proc onKeyUp; - - /// The function to call when a printable character is pressed or auto-repeated. This would be used for text editing. - drgui_on_printable_key_down_proc onPrintableKeyDown; - - /// The function to call when the paint event is received. - drgui_on_paint_proc onPaint; - - /// The function to call when the element is marked as dirty. - drgui_on_dirty_proc onDirty; - - /// The function to call when a hit test needs to be performed. - drgui_on_hittest_proc onHitTest; - - /// The event handler to call when an element receives the mouse focus. - drgui_on_capture_mouse_proc onCaptureMouse; - - /// The event handler to call when an element loses the mouse focus. - drgui_on_release_mouse_proc onReleaseMouse; - - /// The event handler to call when an element receives the keyboard focus. - drgui_on_capture_keyboard_proc onCaptureKeyboard; - - /// The event handler to call when an element loses the keyboard focus. - drgui_on_release_keyboard_proc onReleaseKeyboard; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data. - drgui_byte pExtraData[1]; -}; - -struct drgui_context -{ - /// The paiting context. - void* pPaintingContext; - - /// The painting callbacks. - drgui_painting_callbacks paintingCallbacks; - - - /// The inbound event counter. This is incremented with drgui_begin_inbound_event() and decremented with - /// drgui_end_inbound_event(). We use this to determine whether or not an inbound event is being processed. - int inboundEventCounter; - - /// The outbound event counter that we use as the "lock" for outbound events. All outbound events are posted from - /// inbound events, and all inbound events are already synchronized so we don't need to use a mutex. This is mainly - /// used as a way to check for erroneous outbound event generation. - int outboundEventLockCounter; - - /// A pointer to the first element that has been marked as dead. Elements marked as dead are stored as a linked list. - drgui_element* pFirstDeadElement; - - /// A pointer to the element that is sitting directly under the mouse. This is updated on every inbound mouse move event - /// and is used for determining when a mouse enter/leave event needs to be posted. - drgui_element* pElementUnderMouse; - - /// A pointer to the element with the mouse capture. - drgui_element* pElementWithMouseCapture; - - /// A pointer to the element with the keyboard focus. - drgui_element* pElementWithKeyboardCapture; - - /// A pointer to the element that wants the keyboard focus. If for some reason an element isn't able to immediately - /// capture the keyboard (such as while in the middle of a release_keyboard event handler) this will be set to that - /// particular element. This will then be used to capture the keyboard at a later time when it is able. - drgui_element* pElementWantingKeyboardCapture; - - /// The current cursor. - drgui_cursor_type currentCursor; - - /// Boolean flags. - unsigned int flags; - - - /// The global event callback to call when an element is marked as dirty. - drgui_on_dirty_proc onGlobalDirty; - - /// The global event handler to call when an element captures the mouse. - drgui_on_capture_mouse_proc onGlobalCaptureMouse; - - /// The global event handler to call when an element releases the mouse. - drgui_on_release_mouse_proc onGlobalReleaseMouse; - - /// The global event handler to call when an element captures the keyboard. - drgui_on_capture_keyboard_proc onGlobalCaptureKeyboard; - - /// The global event handler to call when an element releases the keyboard. - drgui_on_release_keyboard_proc onGlobalReleaseKeyboard; - - /// The global event handler to call when the system cursor needs to change. - drgui_on_change_cursor_proc onChangeCursor; - - /// The function to call when an element is deleted. - drgui_on_delete_element_proc onDeleteElement; - - - /// The function to call when a log message is posted. - drgui_on_log onLog; - - - - /// A pointer to the top level element that was passed in from the last inbound mouse move event. - drgui_element* pLastMouseMoveTopLevelElement; - - /// The position of the mouse that was passed in from the last inbound mouse move event. - float lastMouseMovePosX; - float lastMouseMovePosY; - - - // A pointer to the list of dirty elements. - drgui_element** ppDirtyElements; - - // The size of the buffer containing the dirty elements. - size_t dirtyElementBufferSize; - - // The number of dirty top-level elements. - size_t dirtyElementCount; - - /// The counter to use when determining whether or not an on_dirty event needs to be posted. This is incremented with - /// drgui_begin_auto_dirty() and decremented with drgui_end_auto_dirty(). When the counter is decremented and hits - /// zero, the on_dirty event will be posted. - unsigned int dirtyCounter; -}; - - - -///////////////////////////////////////////////////////////////// -// -// CORE API -// -///////////////////////////////////////////////////////////////// - -/// Creates a context. -drgui_context* drgui_create_context(); - -/// Deletes a context and everything that it created. -void drgui_delete_context(drgui_context* pContext); - - - -///////////////////////////////////////////////////////////////// -// Events - -/// Posts a mouse leave inbound event. -/// -/// @remarks -/// The intention behind this event is to allow the application to let dr_gui know that the mouse have left the window. Since dr_gui does -/// not have any notion of a window it must rely on the host application to notify it. -void drgui_post_inbound_event_mouse_leave(drgui_element* pTopLevelElement); - -/// Posts a mouse move inbound event. -void drgui_post_inbound_event_mouse_move(drgui_element* pTopLevelElement, int mousePosX, int mousePosY, int stateFlags); - -/// Posts a mouse button down inbound event. -void drgui_post_inbound_event_mouse_button_down(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags); - -/// Posts a mouse button up inbound event. -void drgui_post_inbound_event_mouse_button_up(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags); - -/// Posts a mouse button double-clicked inbound event. -void drgui_post_inbound_event_mouse_button_dblclick(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags); - -/// Posts a mouse wheel inbound event. -void drgui_post_inbound_event_mouse_wheel(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags); - -/// Posts a key down inbound event. -void drgui_post_inbound_event_key_down(drgui_context* pContext, drgui_key key, int stateFlags); - -/// Posts a key up inbound event. -void drgui_post_inbound_event_key_up(drgui_context* pContext, drgui_key key, int stateFlags); - -/// Posts a printable key down inbound event. -/// -/// @remarks -/// The \c character argument should be a UTF-32 code point. -void drgui_post_inbound_event_printable_key_down(drgui_context* pContext, unsigned int character, int stateFlags); - - -/// Registers the global on_dirty event callback. -/// -/// @remarks -/// This is called whenever a region of an element is marked as dirty and allows an application to mark the region of the -/// container window as dirty to trigger an operating system level repaint of the window. -void drgui_set_global_on_dirty(drgui_context* pContext, drgui_on_dirty_proc onDirty); - -/// Registers the global on_capture_mouse event callback. -/// -/// @remarks -/// This is called whenever an element receives an the mouse capture and allows an application to do operating system level -/// mouse captures against the container window or whatnot. -/// @par -/// The advantage of using a global event callback is that it can be set once at the context level rather than many times -/// at the element level. -void drgui_set_global_on_capture_mouse(drgui_context* pContext, drgui_on_capture_mouse_proc onCaptureMouse); - -/// Registers the global on_release_mouse event callback. -/// -/// @remarks -/// This is called whenever an element loses an the mouse capture and allows an application to do operating system level -/// mouse releases against the container window or whatnot. -/// @par -/// The advantage of using a global event callback is that it can be set once at the context level rather than many times -/// at the element level. -void drgui_set_global_on_release_mouse(drgui_context* pContext, drgui_on_release_mouse_proc onReleaseMouse); - -/// Registers the global on_capture_keyboard event callback. -/// -/// @remarks -/// This is called whenever an element receives an the keyboard capture and allows an application to do an operating system level -/// keyboard focus against the container window or whatnot. -/// @par -/// The advantage of using a global event callback is that it can be set once at the context level rather than many times -/// at the element level. -void drgui_set_global_on_capture_keyboard(drgui_context* pContext, drgui_on_capture_keyboard_proc onCaptureKeyboard); - -/// Registers the global on_release_keyboard event callback. -/// -/// @remarks -/// This is called whenever an element loses an the keyboard capture and allows an application to do an operating system level -/// keyboard release against the container window or whatnot. -/// @par -/// The advantage of using a global event callback is that it can be set once at the context level rather than many times -/// at the element level. -void drgui_set_global_on_release_keyboard(drgui_context* pContext, drgui_on_capture_keyboard_proc onReleaseKeyboard); - -/// Sets the global on_change_cursor event callback. -/// -/// @remarks -/// This is called whenever the operating system needs to change the cursor. -void drgui_set_global_on_change_cursor(drgui_context* pContext, drgui_on_change_cursor_proc onChangeCursor); - -/// Sets the function to call when an element is deleted. -void drgui_set_on_delete_element(drgui_context* pContext, drgui_on_delete_element_proc onDeleteElement); - - -/// Registers the callback to call when a log message is posted. -void drgui_set_on_log(drgui_context* pContext, drgui_on_log onLog); - - - - -///////////////////////////////////////////////////////////////// -// Elements - -/// Creates an element. -drgui_element* drgui_create_element(drgui_context* pContext, drgui_element* pParent, size_t extraDataSize, const void* pExtraData); - -/// Deletes and element. -void drgui_delete_element(drgui_element* pElement); - - -/// Retrieves the size of the extra data of the given element, in bytes. -size_t drgui_get_extra_data_size(drgui_element* pElement); - -/// Retrieves a pointer to the extra data of the given element. -void* drgui_get_extra_data(drgui_element* pElement); - - -/// Sets the type of the element. -/// -/// The type name cannot be more than 63 characters in length. -bool drgui_set_type(drgui_element* pElement, const char* type); - -/// Retrieves the type fo the element. -const char* drgui_get_type(drgui_element* pElement); - -/// Determines whether or not the given element is of the given type. -bool drgui_is_of_type(drgui_element* pElement, const char* type); - - -/// Hides the given element. -void drgui_hide(drgui_element *pElement); - -/// Shows the given element. -void drgui_show(drgui_element* pElement); - -/// Determines whether or not the element is marked as visible. -/// -/// @remarks -/// This is a direct accessor for the internal visible flag of the element and is not recursive. Thus, if this element is -/// marked as visible, but it's parent is invisible, it will still return true. Use drgui_is_visible_recursive() to do -/// a recursive visibility check. -bool drgui_is_visible(const drgui_element* pElement); - -/// Recursively determines whether or not the element is marked as visible. -bool drgui_is_visible_recursive(const drgui_element* pElement); - - -/// Disables clipping against the parent for the given element. -void drgui_disable_clipping(drgui_element* pElement); - -/// Enables clipping against the parent for the given element. -void drgui_enable_clipping(drgui_element* pElement); - -/// Determines whether or not clipping is enabled for the given element. -bool drgui_is_clipping_enabled(const drgui_element* pElement); - - -/// Sets the element that should receive all future mouse related events. -/// -/// @remarks -/// Release the mouse capture with drgui_release_mosue(). -void drgui_capture_mouse(drgui_element* pElement); - -/// Releases the mouse capture. -void drgui_release_mouse(drgui_context* pContext); - -/// Releases the mouse capture without posting the global-scoped event. Should only be used in very specific cases, usually in combination with awkward interop with the window system. -void drgui_release_mouse_no_global_notify(drgui_context* pContext); - -/// Retrieves a pointer to the element with the mouse capture. -drgui_element* drgui_get_element_with_mouse_capture(drgui_context* pContext); - -/// Determines whether or not the given element has the mouse capture. -bool drgui_has_mouse_capture(drgui_element* pElement); - - -/// Sets the element that should receive all future keyboard related events. -/// -/// @remarks -/// Releases the keyboard capture with drgui_release_keyboard(). -void drgui_capture_keyboard(drgui_element* pElement); - -/// Releases the keyboard capture. -void drgui_release_keyboard(drgui_context* pContext); - -/// Releases the keyboard capture without posting the global-scoped event. Should only be used in very specific cases, usually in combination with awkward interop with the window system. -void drgui_release_keyboard_no_global_notify(drgui_context* pContext); - -/// Retrieves a pointer to the element with the keyboard capture. -drgui_element* drgui_get_element_with_keyboard_capture(drgui_context* pContext); - -/// Determines whether or not the given element has the keyboard capture. -bool drgui_has_keyboard_capture(drgui_element* pElement); - - -/// Sets the cursor to use when the mouse enters the given GUI element. -void drgui_set_cursor(drgui_element* pElement, drgui_cursor_type cursor); - -/// Retrieves the cursor to use when the mouse enters the given GUI element. -drgui_cursor_type drgui_get_cursor(drgui_element* pElement); - - -//// Events //// - -/// Registers the on_move event callback. -void drgui_set_on_move(drgui_element* pElement, drgui_on_move_proc callback); - -/// Registers the on_size event callback. -void drgui_set_on_size(drgui_element* pElement, drgui_on_size_proc callback); - -/// Registers the on_mouse_enter event callback. -void drgui_set_on_mouse_enter(drgui_element* pElement, drgui_on_mouse_enter_proc callback); - -/// Registers the on_mouse_leave event callback. -void drgui_set_on_mouse_leave(drgui_element* pElement, drgui_on_mouse_leave_proc callback); - -/// Registers the on_mouse_move event callback. -void drgui_set_on_mouse_move(drgui_element* pElement, drgui_on_mouse_move_proc callback); - -/// Registers the on_mouse_button_down event callback. -void drgui_set_on_mouse_button_down(drgui_element* pElement, drgui_on_mouse_button_down_proc callback); - -/// Registers the on_mouse_button_up event callback. -void drgui_set_on_mouse_button_up(drgui_element* pElement, drgui_on_mouse_button_up_proc callback); - -/// Registers the on_mouse_button_down event callback. -void drgui_set_on_mouse_button_dblclick(drgui_element* pElement, drgui_on_mouse_button_dblclick_proc callback); - -/// Registers the on_mouse_wheel event callback. -void drgui_set_on_mouse_wheel(drgui_element* pElement, drgui_on_mouse_wheel_proc callback); - -/// Registers the on_key_down event callback. -void drgui_set_on_key_down(drgui_element* pElement, drgui_on_key_down_proc callback); - -/// Registers the on_key_up event callback. -void drgui_set_on_key_up(drgui_element* pElement, drgui_on_key_up_proc callback); - -/// Registers the on_printable_key_down event callback. -void drgui_set_on_printable_key_down(drgui_element* pElement, drgui_on_printable_key_down_proc callback); - -/// Registers the on_paint event callback. -void drgui_set_on_paint(drgui_element* pElement, drgui_on_paint_proc callback); - -/// Registers the on_dirty event callback. -void drgui_set_on_dirty(drgui_element* pElement, drgui_on_dirty_proc callback); - -/// Registers the on_hittest event callback. -void drgui_set_on_hittest(drgui_element* pElement, drgui_on_hittest_proc callback); - -/// Registers the on_capture_mouse event callback. -void drgui_set_on_capture_mouse(drgui_element* pElement, drgui_on_capture_mouse_proc callback); - -/// Registers the on_release_mouse event callback. -void drgui_set_on_release_mouse(drgui_element* pElement, drgui_on_release_mouse_proc callback); - -/// Registers the on_capture_keyboard event callback. -void drgui_set_on_capture_keyboard(drgui_element* pElement, drgui_on_capture_keyboard_proc callback); - -/// Registers the on_release_keyboard event callback. -void drgui_set_on_release_keyboard(drgui_element* pElement, drgui_on_release_keyboard_proc callback); - - - -//// Containment and Hit Detection //// - -/// Determines whether or not the given point is inside the bounds of the given element. -/// -/// @remarks -/// This only checks if the point is inside the bounds of the element and does not take hit testing into account. This difference -/// with this one and drgui_is_point_inside_element() is that the latter will use hit testing. -bool drgui_is_point_inside_element_bounds(const drgui_element* pElement, float absolutePosX, float absolutePosY); - -/// Determines whether or not the given point is inside the given element. -/// -/// @remarks -/// This will use hit testing to determine whether or not the point is inside the element. -bool drgui_is_point_inside_element(drgui_element* pElement, float absolutePosX, float absolutePosY); - -/// Finds the element under the given point taking mouse pass-through and hit testing into account. -drgui_element* drgui_find_element_under_point(drgui_element* pTopLevelElement, float absolutePosX, float absolutePosY); - -/// Determines whether or not the given element is currently sitting directly under the mouse. -bool drgui_is_element_under_mouse(drgui_element* pTopLevelElement); - - - -//// Hierarchy //// - -// Retrieves the parent of the given element. -drgui_element* drgui_get_parent(drgui_element* pChildElement); - -/// Detaches the given element from it's parent. -void drgui_detach(drgui_element* pChildElement); - -/// Attaches the given element as a child of the given parent element, and appends it to the end of the children list. -void drgui_append(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Attaches the given element as a child of the given parent element, and prepends it to the end of the children list. -void drgui_prepend(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Appends the given element to the given sibling. -void drgui_append_sibling(drgui_element* pElementToAppend, drgui_element* pElementToAppendTo); - -/// Prepends the given element to the given sibling. -void drgui_prepend_sibling(drgui_element* pElementToPrepend, drgui_element* pElementToPrependTo); - -/// Retrieves a pointer to the given element's top-level ancestor. -/// -/// @remarks -/// If pElement is the top level element, the return value will be pElement. -drgui_element* drgui_find_top_level_element(drgui_element* pElement); - -/// Determines whether or not the given element is the parent of the other. -/// -/// @remarks -/// This is not recursive. Use drgui_is_ancestor() to do a recursive traversal. -bool drgui_is_parent(drgui_element* pParentElement, drgui_element* pChildElement); - -/// Determines whether or not the given element is a child of the other. -/// -/// @remarks -/// This is not recursive. Use drgui_is_descendant() to do a recursive traversal. -bool drgui_is_child(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Determines whether or not the given element is an ancestor of the other. -bool drgui_is_ancestor(drgui_element* pAncestorElement, drgui_element* pChildElement); - -/// Determines whether or not the given element is a descendant of the other. -bool drgui_is_descendant(drgui_element* pChildElement, drgui_element* pAncestorElement); - -/// Determines whether or not the given element is itself or a descendant. -bool drgui_is_self_or_ancestor(drgui_element* pAncestorElement, drgui_element* pChildElement); - -/// Determines whether or not the given element is itself or a descendant. -bool drgui_is_self_or_descendant(drgui_element* pChildElement, drgui_element* pAncestorElement); - - - -//// Layout //// - -/// Sets the absolute position of the given element. -void drgui_set_absolute_position(drgui_element* pElement, float positionX, float positionY); - -/// Retrieves the absolute position of the given element. -void drgui_get_absolute_position(const drgui_element* pElement, float* positionXOut, float* positionYOut); -float drgui_get_absolute_position_x(const drgui_element* pElement); -float drgui_get_absolute_position_y(const drgui_element* pElement); - - -/// Sets the relative position of the given element. -void drgui_set_relative_position(drgui_element* pElement, float relativePosX, float relativePosY); - -/// Retrieves the relative position of the given element. -void drgui_get_relative_position(const drgui_element* pElement, float* relativePosXOut, float* relativePosYOut); -float drgui_get_relative_position_x(const drgui_element* pElement); -float drgui_get_relative_position_y(const drgui_element* pElement); - - -/// Sets the size of the given element. -void drgui_set_size(drgui_element* pElement, float width, float height); - -/// Retrieves the size of the given element. -void drgui_get_size(const drgui_element* pElement, float* widthOut, float* heightOut); -float drgui_get_width(const drgui_element* pElement); -float drgui_get_height(const drgui_element* pElement); - - - -/// Retrieves the absolute rectangle for the given element. -drgui_rect drgui_get_absolute_rect(const drgui_element* pElement); - -/// Retrieves the relative rectangle for the given element. -drgui_rect drgui_get_relative_rect(const drgui_element* pElement); - -/// Retrieves the local rectangle for the given element. -/// -/// @remarks -/// The local rectangle is equivalent to drgui_make_rect(0, 0, drgui_get_width(pElement), drgui_get_height(pElement)); -drgui_rect drgui_get_local_rect(const drgui_element* pElement); - - - -//// Painting //// - -/// Registers the custom painting callbacks. -/// -/// @remarks -/// This can only be called once, so it should always be done after initialization. This will fail if called -/// more than once. -bool drgui_register_painting_callbacks(drgui_context* pContext, void* pPaintingContext, drgui_painting_callbacks callbacks); - - -/// Performs a recursive traversal of all visible elements in the given rectangle. -/// -/// @param pParentElement [in] A pointer to the element to iterate. -/// -/// @remarks -/// pParentElement will be included in the iteration is it is within the rectangle. -/// @par -/// The rectangle should be relative to pParentElement. -/// @par -/// The iteration callback function takes a pointer to a rectangle structure that represents the visible portion of the -/// element. This pointer can be modified by the callback to create an adjusted rectangle which can be used for clipping. -bool drgui_iterate_visible_elements(drgui_element* pParentElement, drgui_rect relativeRect, drgui_visible_iteration_proc callback, void* pUserData); - - -/// Disable's automatic dirtying of elements. -void drgui_disable_auto_dirty(drgui_context* pContext); - -/// Enable's automatic dirtying of elements. -void drgui_enable_auto_dirty(drgui_context* pContext); - -/// Determines whether or not automatic dirtying is enabled. -bool drgui_is_auto_dirty_enabled(drgui_context* pContext); - - -/// Begins accumulating a dirty rectangle. -/// -/// Returns a pointer to the top level element that was made dirty. -drgui_element* drgui_begin_dirty(drgui_element* pElement); - -/// Ends accumulating a dirty rectangle, and requests a redraw from the backend if the counter reaches zero. -void drgui_end_dirty(drgui_element* pElement); - -/// Marks a region of the given element as dirty. -/// -/// @remarks -/// This will not redraw the element immediately, but instead post a paint event. -void drgui_dirty(drgui_element* pElement, drgui_rect relativeRect); - - -/// Draws the given element. -/// -/// @remarks -/// Do not call this on one element, then again on it's children. Any children that fall inside the specified -/// rectangle will also be redrawn. -/// @par -/// This will call painting event handlers which will give the application time to do custom drawing. -/// @par -/// When using easy_draw to do drawing, pPaintData must be set to a pointer to the relevant easydraw_surface object. -void drgui_draw(drgui_element* pElement, drgui_rect relativeRect, void* pPaintData); - -/// Retrieves the current clipping rectangle. -void drgui_get_clip(drgui_element* pElement, drgui_rect* pRelativeRect, void* pPaintData); - -/// Sets the clipping rectangle to apply to all future draw operations on this element. -void drgui_set_clip(drgui_element* pElement, drgui_rect relativeRect, void* pPaintData); - -/// Draws a rectangle on the given element. -void drgui_draw_rect(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, void* pPaintData); - -/// Draws the outline of a rectangle on the given element. -void drgui_draw_rect_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float outlineWidth, void* pPaintData); - -/// Draws a filled rectangle with an outline on the given element. -void drgui_draw_rect_with_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float outlineWidth, drgui_color outlineColor, void* pPaintData); - -/// Draws a rectangle with rounded corners on the given element. -void drgui_draw_round_rect(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float radius, void* pPaintData); - -/// Draws the outline of a rectangle with rounded corners on the given element. -void drgui_draw_round_rect_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float radius, float outlineWidth, void* pPaintData); - -/// Draws a filled rectangle and it's outline with rounded corners on the given element. -void drgui_draw_round_rect_with_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float radius, float outlineWidth, drgui_color outlineColor, void* pPaintData); - -/// Draws a run of text on the given element. -/// -/// @remarks -/// This does not do any complex formatting like multiple lines and whatnot. Complex formatting can be achieved with multiple -/// calls to this function. -/// @par -/// \c textSizeInBytes can be -1 in which case the text string is treated as null terminated. -void drgui_draw_text(drgui_element* pElement, drgui_font* pFont, const char* text, int textLengthInBytes, float posX, float posY, drgui_color color, drgui_color backgroundColor, void* pPaintData); - -/// Draws an image. -void drgui_draw_image(drgui_element* pElement, drgui_image* pImage, drgui_draw_image_args* pArgs, void* pPaintData); - - -/// Creates a font resource. -drgui_font* drgui_create_font(drgui_context* pContext, const char* family, unsigned int size, drgui_font_weight weight, drgui_font_slant slant, float rotation, unsigned int flags); - -/// Deletes a font resource. -void drgui_delete_font(drgui_font* pFont); - -/// Retrieves the metrics of the given font. -bool drgui_get_font_metrics(drgui_font* pFont, drgui_font_metrics* pMetricsOut); - -/// Retrieves the metrics of the glyph for the given character when rendered with the given font. -bool drgui_get_glyph_metrics(drgui_font* pFont, unsigned int utf32, drgui_glyph_metrics* pMetricsOut); - -/// Retrieves the dimensions of the given string when drawn with the given font. -/// -/// @remarks -/// When the length of the text is 0, the width will be set to 0 and the height will be set to the line height. -bool drgui_measure_string(drgui_font* pFont, const char* text, size_t textLengthInBytes, float* pWidthOut, float* pHeightOut); - -/// Retrieves the position to place a text cursor based on the given point for the given string when drawn with the given font. -bool drgui_get_text_cursor_position_from_point(drgui_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); - -/// Retrieves the position to palce a text cursor based on the character at the given index for the given string when drawn with the given font. -bool drgui_get_text_cursor_position_from_char(drgui_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - - - -/// Creates an image that can be passed to drgui_draw_image(). -/// -/// @remarks -/// The dimensions and format of an image are immutable. If these need to change, then the image needs to be deleted and re-created. -/// @par -/// If pData is NULL, the default image data is undefined. -/// @par -/// If stride is set to 0, it is assumed to be tightly packed. -/// @par -/// Use drgui_map_image_data() and drgui_unmap_image_data() to update or retrieve image data. -drgui_image* drgui_create_image(drgui_context* pContext, unsigned int width, unsigned int height, drgui_image_format format, unsigned int stride, const void* pData); - -/// Deletes the given image. -void drgui_delete_image(drgui_image* pImage); - -/// Retrieves the size of the given image. -void drgui_get_image_size(drgui_image* pImage, unsigned int* pWidthOut, unsigned int* pHeightOut); - -/// Retrieves the optimal image format for the given context. -drgui_image_format drgui_get_optimal_image_format(drgui_context* pContext); - -/// Retrieves a pointer to a buffer representing the given image's data. -/// -/// Call drgui_unmap_image_data() when you are done with this function. -/// -/// Use this function to access an image's data. The returned pointer does not necessarilly point to the image's actual data, so when -/// writing to this pointer, nothing is actually updated until drgui_unmap_image_data() is called. -/// -/// The returned data will contain the image data at the time of the mapping. -void* drgui_map_image_data(drgui_image* pImage, unsigned int accessFlags); - -/// Unmaps the given image data. -void drgui_unmap_image_data(drgui_image* pImage); - - - -///////////////////////////////////////////////////////////////// -// -// HIGH-LEVEL API -// -///////////////////////////////////////////////////////////////// - -//// Hit Testing and Layout //// - -/// An on_size event callback that resizes every child element to that of the parent. -void drgui_on_size_fit_children_to_parent(drgui_element* pElement, float newWidth, float newHeight); - -/// An on_hit_test event callback that can be used to always fail the mouse hit test. -bool drgui_pass_through_hit_test(drgui_element* pElement, float mousePosX, float mousePosY); - - -//// Painting //// - -/// Draws a border around the given element. -void drgui_draw_border(drgui_element* pElement, float borderWidth, drgui_color color, void* pUserData); - - - -///////////////////////////////////////////////////////////////// -// -// UTILITY API -// -///////////////////////////////////////////////////////////////// - -/// Creates a color object from a set of RGBA color components. -drgui_color drgui_rgba(drgui_byte r, drgui_byte g, drgui_byte b, drgui_byte a); - -/// Creates a color object from a set of RGB color components. -drgui_color drgui_rgb(drgui_byte r, drgui_byte g, drgui_byte b); - -/// Clamps the given rectangle to another. -drgui_rect drgui_clamp_rect(drgui_rect rect, drgui_rect other); - -/// Clamps the given rectangle to the given element and returns whether or not any of it is contained within the element's rectangle. -bool drgui_clamp_rect_to_element(const drgui_element* pElement, drgui_rect* pRelativeRect); - -/// Converts the given rectangle from absolute to relative to the given element. -drgui_rect drgui_make_rect_relative(const drgui_element* pElement, drgui_rect* pRect); - -/// Converts the given rectangle from relative to absolute based on the given element. -drgui_rect drgui_make_rect_absolute(const drgui_element* pElement, drgui_rect* pRect); - -/// Converts the given point from absolute to relative to the given element. -void drgui_make_point_relative(const drgui_element* pElement, float* positionX, float* positionY); - -/// Converts the given point from relative to absolute based on the given element. -void drgui_make_point_absolute(const drgui_element* pElement, float* positionX, float* positionY); - -/// Creates a drgui_rect object. -drgui_rect drgui_make_rect(float left, float top, float right, float bottom); - -/// Creates an inside-out rectangle. -/// -/// @remarks -/// An inside our rectangle is a negative-dimension rectangle with each edge at the extreme edges. The left edge will be at the -/// right-most side and the right edge will be at the left-most side. The same applies for the top and bottom edges. -drgui_rect drgui_make_inside_out_rect(); - -/// Expands the given rectangle on all sides by the given amount. -/// -/// @remarks -/// This will increase the width and height of the rectangle by x 2. -/// @par -/// The growth amount can be negative, in which case it will be shrunk. Note that this does not do any checking to ensure the rectangle -/// contains positive dimensions after a shrink. -drgui_rect drgui_grow_rect(drgui_rect rect, float amount); - -/// Scales the given rectangle. -/// -/// @param scaleX [in] The scale to apply to and -/// @param scaleY [in] The scale to apply to and -/// -/// @remarks -/// This will modify the and properties which means the rectangle will change position. To adjust only the size, scale the -/// rectangle manually. -drgui_rect drgui_scale_rect(drgui_rect rect, float scaleX, float scaleY); - -/// Offsets the given rectangle. -drgui_rect drgui_offset_rect(drgui_rect rect, float offsetX, float offsetY); - -/// Creates a rectangle that contains both of the given rectangles. -drgui_rect drgui_rect_union(drgui_rect rect0, drgui_rect rect1); - -/// Determines whether or not the given rectangle contains the given point. -/// -/// @remarks -/// An important not here is that if the position is sitting on the right or bottom border, false will be returned. If, however, the point -/// is sitting on the left or top border, true will be returned. The reason for this is that elements may sit exactly side-by-side with -/// each other, and if we use this function to determine if a point is contained within an element (which we do), we would end up having -/// this return true for both elements, which we don't want. -bool drgui_rect_contains_point(drgui_rect rect, float posX, float posY); - -/// Determines whether or not two rectangles are equal. -bool drgui_rect_equal(drgui_rect rect0, drgui_rect rect1); - -/// Determines whether or not the given rectangle has any volume (width and height > 0). -bool drgui_rect_has_volume(drgui_rect rect); - - - -///////////////////////////////////////////////////////////////// -// -// EASY_DRAW-SPECIFIC API -// -///////////////////////////////////////////////////////////////// -#ifndef DRGUI_NO_DR_2D - -/// A covenience function for creating a new context and registering the easy_draw painting callbacks. -/// -/// @remarks -/// This is equivalent to drgui_create_context() followed by drgui_register_dr_2d_callbacks(). -drgui_context* drgui_create_context_dr_2d(dr2d_context* pDrawingContext); - -/// Registers the drawing callbacks for use with easy_draw. -/// -/// @remarks -/// The user data of each callback is assumed to be a pointer to an easydraw_surface object. -void drgui_register_dr_2d_callbacks(drgui_context* pContext, dr2d_context* pDrawingContext); - -#endif - - -#ifdef __cplusplus -} -#endif - -#endif //dr_gui_h - - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_GUI_IMPLEMENTATION -#include -#include -#include -#include -#include -#include - -#ifndef DRGUI_PRIVATE -#define DRGUI_PRIVATE static -#endif - -///////////////////////////////////////////////////////////////// -// -// PRIVATE CORE API -// -///////////////////////////////////////////////////////////////// - - -// Context Flags -#define IS_CONTEXT_DEAD (1U << 0) -#define IS_AUTO_DIRTY_DISABLED (1U << 1) -#define IS_RELEASING_KEYBOARD (1U << 2) - -// Element Flags -#define IS_ELEMENT_HIDDEN (1U << 0) -#define IS_ELEMENT_CLIPPING_DISABLED (1U << 1) -#define IS_ELEMENT_DEAD (1U << 31) - - -static int drgui__strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ -#ifdef _MSC_VER - return strcpy_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t i; - for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstSizeInBytes) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -#endif -} - -int drgui__strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ -#ifdef _MSC_VER - return strncpy_s(dst, dstSizeInBytes, src, count); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return EINVAL; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - size_t maxcount = count; - if (count == ((size_t)-1) || count >= dstSizeInBytes) { // -1 = _TRUNCATE - maxcount = dstSizeInBytes - 1; - } - - size_t i; - for (i = 0; i < maxcount && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (src[i] == '\0' || i == count || count == ((size_t)-1)) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return ERANGE; -#endif -} - - -/// Increments the inbound event counter -/// -/// @remarks -/// This is called from every drgui_post_inbound_event_*() function and is used to keep track of whether or -/// not an inbound event is being processed. We need to track this because if we are in the middle of event -/// processing and an element is deleted, we want to delay it's deletion until the end of the event processing. -/// @par -/// Use drgui_end_inbound_event() to decrement the counter. -void drgui_begin_inbound_event(drgui_context* pContext); - -/// Decrements the inbound event counter. -/// -/// @remarks -/// This is called from every drgui_post_inbound_event_*() function. -/// @par -/// When the internal counter reaches zero, deleted elements will be garbage collected. -void drgui_end_inbound_event(drgui_context* pContext); - -/// Determines whether or not inbound events are being processed. -/// -/// @remarks -/// This is used to determine whether or not an element can be deleted immediately or should be garbage collected -/// at the end of event processing. -bool drgui_is_handling_inbound_event(const drgui_context* pContext); - - -/// Increments the outbound event counter. -/// -/// @remarks -/// This will validate that the given element is allowed to have an event posted. When false is returned, nothing -/// will have been locked and the outbound event should be cancelled. -/// @par -/// This will return false if the given element has been marked as dead, or if there is some other reason it should -/// not be receiving events. -bool drgui_begin_outbound_event(drgui_element* pElement); - -/// Decrements the outbound event counter. -void drgui_end_outbound_event(drgui_element* pElement); - -/// Determines whether or not and outbound event is being processed. -bool drgui_is_handling_outbound_event(drgui_context* pContext); - - -/// Marks the given element as dead. -void drgui_mark_element_as_dead(drgui_element* pElement); - -/// Determines whether or not the given element is marked as dead. -bool drgui_is_element_marked_as_dead(const drgui_element* pElement); - -/// Deletes every element that has been marked as dead. -void drgui_delete_elements_marked_as_dead(drgui_context* pContext); - - -/// Marks the given context as deleted. -void drgui_mark_context_as_dead(drgui_context* pContext); - -/// Determines whether or not the given context is marked as dead. -bool drgui_is_context_marked_as_dead(const drgui_context* pContext); - - -/// Deletes the given context for real. -/// -/// If a context is deleted during the processing of an inbound event it will not be deleting immediately - this -/// will delete the context for real. -void drgui_delete_context_for_real(drgui_context* pContext); - -/// Deletes the given element for real. -/// -/// Sometimes an element will not be deleted straight away but instead just marked as dead. We use this to delete -/// the given element for real. -void drgui_delete_element_for_real(drgui_element* pElement); - - -/// Orphans the given element without triggering a redraw of the parent nor the child. -void drgui_detach_without_redraw(drgui_element* pChildElement); - -/// Appends the given element without first detaching it from the old parent, nor does it post a redraw. -void drgui_append_without_detach_or_redraw(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Appends the given element without first detaching it from the old parent. -void drgui_append_without_detach(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Prepends the given element without first detaching it from the old parent, nor does it post a redraw. -void drgui_prepend_without_detach_or_redraw(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Prepends the given element without first detaching it from the old parent. -void drgui_prepend_without_detach(drgui_element* pChildElement, drgui_element* pParentElement); - -/// Appends an element to another as it's sibling, but does not detach it from the previous parent nor trigger a redraw. -void drgui_append_sibling_without_detach_or_redraw(drgui_element* pElementToAppend, drgui_element* pElementToAppendTo); - -/// Appends an element to another as it's sibling, but does not detach it from the previous parent. -void drgui_append_sibling_without_detach(drgui_element* pElementToAppend, drgui_element* pElementToAppendTo); - -/// Prepends an element to another as it's sibling, but does not detach it from the previous parent nor trigger a redraw. -void drgui_prepend_sibling_without_detach_or_redraw(drgui_element* pElementToPrepend, drgui_element* pElementToPrependTo); - -/// Prepends an element to another as it's sibling, but does not detach it from the previous parent. -void drgui_prepend_sibling_without_detach(drgui_element* pElementToPrepend, drgui_element* pElementToPrependTo); - - -/// Begins accumulating an invalidation rectangle. -void drgui_begin_auto_dirty(drgui_element* pElement); - -/// Ends accumulating the invalidation rectangle and posts on_dirty is auto-dirty is enabled. -void drgui_end_auto_dirty(drgui_element* pElement); - -/// Marks the given region of the given top level element as dirty, but only if automatic dirtying is enabled. -/// -/// @remarks -/// This is equivalent to drgui_begin_auto_dirty() immediately followed by drgui_end_auto_dirty(). -void drgui_auto_dirty(drgui_element* pTopLevelElement, drgui_rect rect); - - -/// Recursively applies the given offset to the absolute positions of the children of the given element. -/// -/// @remarks -/// This is called when the absolute position of an element is changed. -void drgui_apply_offset_to_children_recursive(drgui_element* pParentElement, float offsetX, float offsetY); - - -/// The function to call when the mouse may have entered into a new element. -void drgui_update_mouse_enter_and_leave_state(drgui_context* pContext, drgui_element* pNewElementUnderMouse); - - -/// Functions for posting outbound events. -void drgui_post_outbound_event_move(drgui_element* pElement, float newRelativePosX, float newRelativePosY); -void drgui_post_outbound_event_size(drgui_element* pElement, float newWidth, float newHeight); -void drgui_post_outbound_event_mouse_enter(drgui_element* pElement); -void drgui_post_outbound_event_mouse_leave(drgui_element* pElement); -void drgui_post_outbound_event_mouse_move(drgui_element* pElement, int relativeMousePosX, int relativeMousePosY, int stateFlags); -void drgui_post_outbound_event_mouse_button_down(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); -void drgui_post_outbound_event_mouse_button_up(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); -void drgui_post_outbound_event_mouse_button_dblclick(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); -void drgui_post_outbound_event_mouse_wheel(drgui_element* pElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags); -void drgui_post_outbound_event_key_down(drgui_element* pElement, drgui_key key, int stateFlags); -void drgui_post_outbound_event_key_up(drgui_element* pElement, drgui_key key, int stateFlags); -void drgui_post_outbound_event_printable_key_down(drgui_element* pElement, unsigned int character, int stateFlags); -void drgui_post_outbound_event_dirty(drgui_element* pElement, drgui_rect relativeRect); -void drgui_post_outbound_event_dirty_global(drgui_element* pElement, drgui_rect relativeRect); -void drgui_post_outbound_event_capture_mouse(drgui_element* pElement); -void drgui_post_outbound_event_capture_mouse_global(drgui_element* pElement); -void drgui_post_outbound_event_release_mouse(drgui_element* pElement); -void drgui_post_outbound_event_release_mouse_global(drgui_element* pElement); -void drgui_post_outbound_event_capture_keyboard(drgui_element* pElement, drgui_element* pPrevCapturedElement); -void drgui_post_outbound_event_capture_keyboard_global(drgui_element* pElement, drgui_element* pPrevCapturedElement); -void drgui_post_outbound_event_release_keyboard(drgui_element* pElement, drgui_element* pNewCapturedElement); -void drgui_post_outbound_event_release_keyboard_global(drgui_element* pElement, drgui_element* pNewCapturedElement); - -/// Posts a log message. -void drgui_log(drgui_context* pContext, const char* message); - - -void drgui_begin_inbound_event(drgui_context* pContext) -{ - assert(pContext != NULL); - - pContext->inboundEventCounter += 1; -} - -void drgui_end_inbound_event(drgui_context* pContext) -{ - assert(pContext != NULL); - assert(pContext->inboundEventCounter > 0); - - pContext->inboundEventCounter -= 1; - - - // Here is where we want to clean up any elements that are marked as dead. When events are being handled elements are not deleted - // immediately but instead only marked for deletion. This function will be called at the end of event processing which makes it - // an appropriate place for cleaning up dead elements. - if (!drgui_is_handling_inbound_event(pContext)) - { - drgui_delete_elements_marked_as_dead(pContext); - - // If the context has been marked for deletion than we will need to delete that too. - if (drgui_is_context_marked_as_dead(pContext)) - { - drgui_delete_context_for_real(pContext); - } - } -} - -bool drgui_is_handling_inbound_event(const drgui_context* pContext) -{ - assert(pContext != NULL); - - return pContext->inboundEventCounter > 0; -} - - - -bool drgui_begin_outbound_event(drgui_element* pElement) -{ - assert(pElement != NULL); - assert(pElement->pContext != NULL); - - - // We want to cancel the outbound event if the element is marked as dead. - if (drgui_is_element_marked_as_dead(pElement)) { - drgui_log(pElement->pContext, "WARNING: Attemping to post an event to an element that is marked for deletion."); - return false; - } - - - // At this point everything should be fine so we just increment the count (which should never go above 1) and return true. - pElement->pContext->outboundEventLockCounter += 1; - - return true; -} - -void drgui_end_outbound_event(drgui_element* pElement) -{ - assert(pElement != NULL); - assert(pElement->pContext != NULL); - assert(pElement->pContext->outboundEventLockCounter > 0); - - pElement->pContext->outboundEventLockCounter -= 1; -} - -bool drgui_is_handling_outbound_event(drgui_context* pContext) -{ - assert(pContext != NULL); - return pContext->outboundEventLockCounter > 0; -} - - -void drgui_mark_element_as_dead(drgui_element* pElement) -{ - assert(pElement != NULL); - assert(pElement->pContext != NULL); - - pElement->flags |= IS_ELEMENT_DEAD; - - - if (pElement->pContext->pFirstDeadElement != NULL) { - pElement->pNextDeadElement = pElement->pContext->pFirstDeadElement; - } - - pElement->pContext->pFirstDeadElement = pElement; -} - -bool drgui_is_element_marked_as_dead(const drgui_element* pElement) -{ - if (pElement == NULL) { - return false; - } - - return (pElement->flags & IS_ELEMENT_DEAD) != 0; -} - -void drgui_delete_elements_marked_as_dead(drgui_context* pContext) -{ - assert(pContext != NULL); - - while (pContext->pFirstDeadElement != NULL) - { - drgui_element* pDeadElement = pContext->pFirstDeadElement; - pContext->pFirstDeadElement = pContext->pFirstDeadElement->pNextDeadElement; - - drgui_delete_element_for_real(pDeadElement); - } -} - - -void drgui_mark_context_as_dead(drgui_context* pContext) -{ - assert(pContext != NULL); - assert(!drgui_is_context_marked_as_dead(pContext)); - - pContext->flags |= IS_CONTEXT_DEAD; -} - -bool drgui_is_context_marked_as_dead(const drgui_context* pContext) -{ - assert(pContext != NULL); - - return (pContext->flags & IS_CONTEXT_DEAD) != 0; -} - - - -void drgui_delete_context_for_real(drgui_context* pContext) -{ - assert(pContext != NULL); - - // All elements marked as dead need to be deleted. - drgui_delete_elements_marked_as_dead(pContext); - - free(pContext); -} - -void drgui_delete_element_for_real(drgui_element* pElementToDelete) -{ - assert(pElementToDelete != NULL); - - drgui_context* pContext = pElementToDelete->pContext; - - // If the element is marked as dead - if (drgui_is_element_marked_as_dead(pElementToDelete)) { - if (pContext->pFirstDeadElement == pElementToDelete) { - pContext->pFirstDeadElement = pContext->pFirstDeadElement->pNextDeadElement; - } else { - drgui_element* pPrevDeadElement = pContext->pFirstDeadElement; - while (pPrevDeadElement != NULL) { - if (pPrevDeadElement->pNextDeadElement == pElementToDelete) { - break; - } - - pPrevDeadElement = pPrevDeadElement->pNextDeadElement; - } - - if (pPrevDeadElement != NULL) { - pElementToDelete->pNextDeadElement = pElementToDelete->pNextDeadElement; - } - } - } - - free(pElementToDelete); -} - - -void drgui_detach_without_redraw(drgui_element* pElement) -{ - if (pElement->pParent != NULL) { - if (pElement->pParent->pFirstChild == pElement) { - pElement->pParent->pFirstChild = pElement->pNextSibling; - } - - if (pElement->pParent->pLastChild == pElement) { - pElement->pParent->pLastChild = pElement->pPrevSibling; - } - - - if (pElement->pPrevSibling != NULL) { - pElement->pPrevSibling->pNextSibling = pElement->pNextSibling; - } - - if (pElement->pNextSibling != NULL) { - pElement->pNextSibling->pPrevSibling = pElement->pPrevSibling; - } - } - - pElement->pParent = NULL; - pElement->pPrevSibling = NULL; - pElement->pNextSibling = NULL; -} - -void drgui_append_without_detach_or_redraw(drgui_element* pChildElement, drgui_element* pParentElement) -{ - pChildElement->pParent = pParentElement; - if (pChildElement->pParent != NULL) { - if (pChildElement->pParent->pLastChild != NULL) { - pChildElement->pPrevSibling = pChildElement->pParent->pLastChild; - pChildElement->pPrevSibling->pNextSibling = pChildElement; - } - - if (pChildElement->pParent->pFirstChild == NULL) { - pChildElement->pParent->pFirstChild = pChildElement; - } - - pChildElement->pParent->pLastChild = pChildElement; - } -} - -void drgui_append_without_detach(drgui_element* pChildElement, drgui_element* pParentElement) -{ - drgui_append_without_detach_or_redraw(pChildElement, pParentElement); - drgui_auto_dirty(pChildElement, drgui_make_rect(0, 0, pChildElement->width, pChildElement->height)); -} - -void drgui_prepend_without_detach_or_redraw(drgui_element* pChildElement, drgui_element* pParentElement) -{ - pChildElement->pParent = pParentElement; - if (pChildElement->pParent != NULL) { - if (pChildElement->pParent->pFirstChild != NULL) { - pChildElement->pNextSibling = pChildElement->pParent->pFirstChild; - pChildElement->pNextSibling->pPrevSibling = pChildElement; - } - - if (pChildElement->pParent->pLastChild == NULL) { - pChildElement->pParent->pLastChild = pChildElement; - } - - pChildElement->pParent->pFirstChild = pChildElement; - } -} - -void drgui_prepend_without_detach(drgui_element* pChildElement, drgui_element* pParentElement) -{ - drgui_prepend_without_detach_or_redraw(pChildElement, pParentElement); - drgui_auto_dirty(pChildElement, drgui_make_rect(0, 0, pChildElement->width, pChildElement->height)); -} - -void drgui_append_sibling_without_detach_or_redraw(drgui_element* pElementToAppend, drgui_element* pElementToAppendTo) -{ - assert(pElementToAppend != NULL); - assert(pElementToAppendTo != NULL); - - pElementToAppend->pParent = pElementToAppendTo->pParent; - if (pElementToAppend->pParent != NULL) - { - pElementToAppend->pNextSibling = pElementToAppendTo->pNextSibling; - pElementToAppend->pPrevSibling = pElementToAppendTo; - - pElementToAppendTo->pNextSibling->pPrevSibling = pElementToAppend; - pElementToAppendTo->pNextSibling = pElementToAppend; - - if (pElementToAppend->pParent->pLastChild == pElementToAppendTo) { - pElementToAppend->pParent->pLastChild = pElementToAppend; - } - } -} - -void drgui_append_sibling_without_detach(drgui_element* pElementToAppend, drgui_element* pElementToAppendTo) -{ - drgui_append_sibling_without_detach_or_redraw(pElementToAppend, pElementToAppendTo); - drgui_auto_dirty(pElementToAppend, drgui_make_rect(0, 0, pElementToAppend->width, pElementToAppend->height)); -} - -void drgui_prepend_sibling_without_detach_or_redraw(drgui_element* pElementToPrepend, drgui_element* pElementToPrependTo) -{ - assert(pElementToPrepend != NULL); - assert(pElementToPrependTo != NULL); - - pElementToPrepend->pParent = pElementToPrependTo->pParent; - if (pElementToPrepend->pParent != NULL) - { - pElementToPrepend->pPrevSibling = pElementToPrependTo->pNextSibling; - pElementToPrepend->pNextSibling = pElementToPrependTo; - - pElementToPrependTo->pPrevSibling->pNextSibling = pElementToPrepend; - pElementToPrependTo->pNextSibling = pElementToPrepend; - - if (pElementToPrepend->pParent->pFirstChild == pElementToPrependTo) { - pElementToPrepend->pParent->pFirstChild = pElementToPrepend; - } - } -} - -void drgui_prepend_sibling_without_detach(drgui_element* pElementToPrepend, drgui_element* pElementToPrependTo) -{ - drgui_prepend_sibling_without_detach_or_redraw(pElementToPrepend, pElementToPrependTo); - drgui_auto_dirty(pElementToPrepend, drgui_make_rect(0, 0, pElementToPrepend->width, pElementToPrepend->height)); -} - - -void drgui_begin_auto_dirty(drgui_element* pElement) -{ - assert(pElement != NULL); - assert(pElement->pContext != NULL); - - if (drgui_is_auto_dirty_enabled(pElement->pContext)) { - drgui_begin_dirty(pElement); - } -} - -void drgui_end_auto_dirty(drgui_element* pElement) -{ - assert(pElement != NULL); - - drgui_context* pContext = pElement->pContext; - assert(pContext != NULL); - - if (drgui_is_auto_dirty_enabled(pContext)) { - drgui_end_dirty(pElement); - } -} - -void drgui_auto_dirty(drgui_element* pElement, drgui_rect relativeRect) -{ - assert(pElement != NULL); - assert(pElement->pContext != NULL); - - if (drgui_is_auto_dirty_enabled(pElement->pContext)) { - drgui_dirty(pElement, relativeRect); - } -} - - -void drgui__change_cursor(drgui_element* pElement, drgui_cursor_type cursor) -{ - if (pElement == NULL || pElement->pContext == NULL) { - return; - } - - pElement->pContext->currentCursor = cursor; - - if (pElement->pContext->onChangeCursor) { - pElement->pContext->onChangeCursor(pElement, cursor); - } -} - - - -void drgui_apply_offset_to_children_recursive(drgui_element* pParentElement, float offsetX, float offsetY) -{ - assert(pParentElement != NULL); - - for (drgui_element* pChild = pParentElement->pFirstChild; pChild != NULL; pChild = pChild->pNextSibling) - { - drgui_begin_auto_dirty(pParentElement); - { - drgui_auto_dirty(pParentElement, drgui_get_local_rect(pParentElement)); - pChild->absolutePosX += offsetX; - pChild->absolutePosY += offsetY; - - drgui_apply_offset_to_children_recursive(pChild, offsetX, offsetY); - } - drgui_end_auto_dirty(pParentElement); - } -} - -DRGUI_PRIVATE void drgui_post_on_mouse_leave_recursive(drgui_context* pContext, drgui_element* pNewElementUnderMouse, drgui_element* pOldElementUnderMouse) -{ - (void)pContext; - - drgui_element* pOldAncestor = pOldElementUnderMouse; - while (pOldAncestor != NULL) - { - bool isOldElementUnderMouse = pNewElementUnderMouse == pOldAncestor || drgui_is_ancestor(pOldAncestor, pNewElementUnderMouse); - if (!isOldElementUnderMouse) - { - drgui_post_outbound_event_mouse_leave(pOldAncestor); - } - - pOldAncestor = pOldAncestor->pParent; - } -} - -DRGUI_PRIVATE void drgui_post_on_mouse_enter_recursive(drgui_context* pContext, drgui_element* pNewElementUnderMouse, drgui_element* pOldElementUnderMouse) -{ - if (pNewElementUnderMouse == NULL) { - return; - } - - - if (pNewElementUnderMouse->pParent != NULL) { - drgui_post_on_mouse_enter_recursive(pContext, pNewElementUnderMouse->pParent, pOldElementUnderMouse); - } - - bool wasNewElementUnderMouse = pOldElementUnderMouse == pNewElementUnderMouse || drgui_is_ancestor(pNewElementUnderMouse, pOldElementUnderMouse); - if (!wasNewElementUnderMouse) - { - drgui_post_outbound_event_mouse_enter(pNewElementUnderMouse); - } -} - -void drgui_update_mouse_enter_and_leave_state(drgui_context* pContext, drgui_element* pNewElementUnderMouse) -{ - if (pContext == NULL) { - return; - } - - drgui_element* pOldElementUnderMouse = pContext->pElementUnderMouse; - if (pOldElementUnderMouse != pNewElementUnderMouse) - { - // We don't change the enter and leave state if an element is capturing the mouse. - if (pContext->pElementWithMouseCapture == NULL) - { - pContext->pElementUnderMouse = pNewElementUnderMouse; - - drgui_cursor_type newCursor = drgui_cursor_default; - if (pNewElementUnderMouse != NULL) { - newCursor = pNewElementUnderMouse->cursor; - } - - - // It's intuitive to check that the new cursor is different to the old one before trying to change it, but that is not actually - // what we want to do. We'll let the event handler manage it themselves because it's possible the window manager might do some - // window-specific cursor management and the old and new elements are on different windows. - drgui__change_cursor(pNewElementUnderMouse, newCursor); - - - - // The the event handlers below, remember that ancestors are considered hovered if a descendant is the element under the mouse. - - // on_mouse_leave - drgui_post_on_mouse_leave_recursive(pContext, pNewElementUnderMouse, pOldElementUnderMouse); - - // on_mouse_enter - drgui_post_on_mouse_enter_recursive(pContext, pNewElementUnderMouse, pOldElementUnderMouse); - } - } -} - - -void drgui_post_outbound_event_move(drgui_element* pElement, float newRelativePosX, float newRelativePosY) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMove) { - pElement->onMove(pElement, newRelativePosX, newRelativePosY); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_size(drgui_element* pElement, float newWidth, float newHeight) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onSize) { - pElement->onSize(pElement, newWidth, newHeight); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_enter(drgui_element* pElement) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMouseEnter) { - pElement->onMouseEnter(pElement); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_leave(drgui_element* pElement) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMouseLeave) { - pElement->onMouseLeave(pElement); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_move(drgui_element* pElement, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) -{ - if (pElement->onMouseMove) { - pElement->onMouseMove(pElement, relativeMousePosX, relativeMousePosY, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_button_down(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMouseButtonDown) { - pElement->onMouseButtonDown(pElement, mouseButton, relativeMousePosX, relativeMousePosY, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_button_up(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMouseButtonUp) { - pElement->onMouseButtonUp(pElement, mouseButton, relativeMousePosX, relativeMousePosY, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_button_dblclick(drgui_element* pElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMouseButtonDblClick) { - pElement->onMouseButtonDblClick(pElement, mouseButton, relativeMousePosX, relativeMousePosY, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_mouse_wheel(drgui_element* pElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onMouseWheel) { - pElement->onMouseWheel(pElement, delta, relativeMousePosX, relativeMousePosY, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_key_down(drgui_element* pElement, drgui_key key, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onKeyDown) { - pElement->onKeyDown(pElement, key, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_key_up(drgui_element* pElement, drgui_key key, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onKeyUp) { - pElement->onKeyUp(pElement, key, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - -void drgui_post_outbound_event_printable_key_down(drgui_element* pElement, unsigned int character, int stateFlags) -{ - if (drgui_begin_outbound_event(pElement)) - { - if (pElement->onPrintableKeyDown) { - pElement->onPrintableKeyDown(pElement, character, stateFlags); - } - - drgui_end_outbound_event(pElement); - } -} - - -void drgui_post_outbound_event_dirty(drgui_element* pElement, drgui_rect relativeRect) -{ - if (pElement != NULL) - { - if (pElement->onDirty) { - pElement->onDirty(pElement, relativeRect); - } - } -} - -void drgui_post_outbound_event_dirty_global(drgui_element* pElement, drgui_rect relativeRect) -{ - if (pElement != NULL && pElement->pContext != NULL) - { - if (pElement->pContext->onGlobalDirty) { - pElement->pContext->onGlobalDirty(pElement, relativeRect); - } - } -} - -void drgui_post_outbound_event_capture_mouse(drgui_element* pElement) -{ - if (pElement != NULL) - { - if (pElement->onCaptureMouse) { - pElement->onCaptureMouse(pElement); - } - } -} - -void drgui_post_outbound_event_capture_mouse_global(drgui_element* pElement) -{ - if (pElement != NULL && pElement->pContext != NULL) - { - if (pElement->pContext->onGlobalCaptureMouse) { - pElement->pContext->onGlobalCaptureMouse(pElement); - } - } -} - -void drgui_post_outbound_event_release_mouse(drgui_element* pElement) -{ - if (pElement != NULL) - { - if (pElement->onReleaseMouse) { - pElement->onReleaseMouse(pElement); - } - } -} - -void drgui_post_outbound_event_release_mouse_global(drgui_element* pElement) -{ - if (pElement != NULL && pElement->pContext != NULL) - { - if (pElement->pContext->onGlobalReleaseMouse) { - pElement->pContext->onGlobalReleaseMouse(pElement); - } - } -} - - -void drgui_post_outbound_event_capture_keyboard(drgui_element* pElement, drgui_element* pPrevCapturedElement) -{ - if (pElement != NULL) - { - if (pElement->onCaptureKeyboard) { - pElement->onCaptureKeyboard(pElement, pPrevCapturedElement); - } - } -} - -void drgui_post_outbound_event_capture_keyboard_global(drgui_element* pElement, drgui_element* pPrevCapturedElement) -{ - if (pElement != NULL && pElement->pContext != NULL) - { - if (pElement->pContext->onGlobalCaptureKeyboard) { - pElement->pContext->onGlobalCaptureKeyboard(pElement, pPrevCapturedElement); - } - } -} - -void drgui_post_outbound_event_release_keyboard(drgui_element* pElement, drgui_element* pNewCapturedElement) -{ - if (pElement != NULL) - { - if (pElement->onReleaseKeyboard) { - pElement->onReleaseKeyboard(pElement, pNewCapturedElement); - } - } -} - -void drgui_post_outbound_event_release_keyboard_global(drgui_element* pElement, drgui_element* pNewCapturedElement) -{ - if (pElement != NULL && pElement->pContext != NULL) - { - if (pElement->pContext->onGlobalReleaseKeyboard) { - pElement->pContext->onGlobalReleaseKeyboard(pElement, pNewCapturedElement); - } - } -} - - -void drgui_log(drgui_context* pContext, const char* message) -{ - if (pContext != NULL) - { - if (pContext->onLog) { - pContext->onLog(pContext, message); - } - } -} - - -///////////////////////////////////////////////////////////////// -// -// CORE API -// -///////////////////////////////////////////////////////////////// - -drgui_context* drgui_create_context() -{ - drgui_context* pContext = (drgui_context*)calloc(1, sizeof(drgui_context)); - if (pContext != NULL) { - pContext->currentCursor = drgui_cursor_default; - } - - return pContext; -} - -void drgui_delete_context(drgui_context* pContext) -{ - if (pContext == NULL) { - return; - } - - - // Make sure the mouse capture is released. - if (pContext->pElementWithMouseCapture != NULL) - { - drgui_log(pContext, "WARNING: Deleting the GUI context while an element still has the mouse capture."); - drgui_release_mouse(pContext); - } - - // Make sure the keyboard capture is released. - if (pContext->pElementWithKeyboardCapture != NULL) - { - drgui_log(pContext, "WARNING: Deleting the GUI context while an element still has the keyboard capture."); - drgui_release_keyboard(pContext); - } - - - if (drgui_is_handling_inbound_event(pContext)) - { - // An inbound event is still being processed - we don't want to delete the context straight away because we can't - // trust external event handlers to not try to access the context later on. To do this we just set the flag that - // the context is deleted. It will then be deleted for real at the end of the inbound event handler. - drgui_mark_context_as_dead(pContext); - } - else - { - // An inbound event is not being processed, so delete the context straight away. - drgui_delete_context_for_real(pContext); - } -} - - - -///////////////////////////////////////////////////////////////// -// Events - -void drgui_post_inbound_event_mouse_leave(drgui_element* pTopLevelElement) -{ - if (pTopLevelElement == NULL) { - return; - } - - drgui_context* pContext = pTopLevelElement->pContext; - if (pContext == NULL) { - return; - } - - drgui_begin_inbound_event(pContext); - { - // We assume that was previously under the mouse was either pTopLevelElement itself or one of it's descendants. - drgui_update_mouse_enter_and_leave_state(pContext, NULL); - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_mouse_move(drgui_element* pTopLevelElement, int mousePosX, int mousePosY, int stateFlags) -{ - if (pTopLevelElement == NULL || pTopLevelElement->pContext == NULL) { - return; - } - - - drgui_begin_inbound_event(pTopLevelElement->pContext); - { - /// A pointer to the top level element that was passed in from the last inbound mouse move event. - pTopLevelElement->pContext->pLastMouseMoveTopLevelElement = pTopLevelElement; - - /// The position of the mouse that was passed in from the last inbound mouse move event. - pTopLevelElement->pContext->lastMouseMovePosX = (float)mousePosX; - pTopLevelElement->pContext->lastMouseMovePosY = (float)mousePosY; - - - - // The first thing we need to do is find the new element that's sitting under the mouse. - drgui_element* pNewElementUnderMouse = drgui_find_element_under_point(pTopLevelElement, (float)mousePosX, (float)mousePosY); - - // Now that we know which element is sitting under the mouse we need to check if the mouse has entered into a new element. - drgui_update_mouse_enter_and_leave_state(pTopLevelElement->pContext, pNewElementUnderMouse); - - - drgui_element* pEventReceiver = pTopLevelElement->pContext->pElementWithMouseCapture; - if (pEventReceiver == NULL) - { - pEventReceiver = pNewElementUnderMouse; - } - - if (pEventReceiver != NULL) - { - float relativeMousePosX = (float)mousePosX; - float relativeMousePosY = (float)mousePosY; - drgui_make_point_relative(pEventReceiver, &relativeMousePosX, &relativeMousePosY); - - drgui_post_outbound_event_mouse_move(pEventReceiver, (int)relativeMousePosX, (int)relativeMousePosY, stateFlags); - } - } - drgui_end_inbound_event(pTopLevelElement->pContext); -} - -void drgui_post_inbound_event_mouse_button_down(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags) -{ - if (pTopLevelElement == NULL || pTopLevelElement->pContext == NULL) { - return; - } - - drgui_context* pContext = pTopLevelElement->pContext; - drgui_begin_inbound_event(pContext); - { - drgui_element* pEventReceiver = pContext->pElementWithMouseCapture; - if (pEventReceiver == NULL) - { - pEventReceiver = pContext->pElementUnderMouse; - - if (pEventReceiver == NULL) - { - // We'll get here if this message is posted without a prior mouse move event. - pEventReceiver = drgui_find_element_under_point(pTopLevelElement, (float)mousePosX, (float)mousePosY); - } - } - - - if (pEventReceiver != NULL) - { - float relativeMousePosX = (float)mousePosX; - float relativeMousePosY = (float)mousePosY; - drgui_make_point_relative(pEventReceiver, &relativeMousePosX, &relativeMousePosY); - - drgui_post_outbound_event_mouse_button_down(pEventReceiver, mouseButton, (int)relativeMousePosX, (int)relativeMousePosY, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_mouse_button_up(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags) -{ - if (pTopLevelElement == NULL || pTopLevelElement->pContext == NULL) { - return; - } - - drgui_context* pContext = pTopLevelElement->pContext; - drgui_begin_inbound_event(pContext); - { - drgui_element* pEventReceiver = pContext->pElementWithMouseCapture; - if (pEventReceiver == NULL) - { - pEventReceiver = pContext->pElementUnderMouse; - - if (pEventReceiver == NULL) - { - // We'll get here if this message is posted without a prior mouse move event. - pEventReceiver = drgui_find_element_under_point(pTopLevelElement, (float)mousePosX, (float)mousePosY); - } - } - - - if (pEventReceiver != NULL) - { - float relativeMousePosX = (float)mousePosX; - float relativeMousePosY = (float)mousePosY; - drgui_make_point_relative(pEventReceiver, &relativeMousePosX, &relativeMousePosY); - - drgui_post_outbound_event_mouse_button_up(pEventReceiver, mouseButton, (int)relativeMousePosX, (int)relativeMousePosY, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_mouse_button_dblclick(drgui_element* pTopLevelElement, int mouseButton, int mousePosX, int mousePosY, int stateFlags) -{ - if (pTopLevelElement == NULL || pTopLevelElement->pContext == NULL) { - return; - } - - drgui_context* pContext = pTopLevelElement->pContext; - drgui_begin_inbound_event(pContext); - { - drgui_element* pEventReceiver = pContext->pElementWithMouseCapture; - if (pEventReceiver == NULL) - { - pEventReceiver = pContext->pElementUnderMouse; - - if (pEventReceiver == NULL) - { - // We'll get here if this message is posted without a prior mouse move event. - pEventReceiver = drgui_find_element_under_point(pTopLevelElement, (float)mousePosX, (float)mousePosY); - } - } - - - if (pEventReceiver != NULL) - { - float relativeMousePosX = (float)mousePosX; - float relativeMousePosY = (float)mousePosY; - drgui_make_point_relative(pEventReceiver, &relativeMousePosX, &relativeMousePosY); - - drgui_post_outbound_event_mouse_button_dblclick(pEventReceiver, mouseButton, (int)relativeMousePosX, (int)relativeMousePosY, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_mouse_wheel(drgui_element* pTopLevelElement, int delta, int mousePosX, int mousePosY, int stateFlags) -{ - if (pTopLevelElement == NULL || pTopLevelElement->pContext == NULL) { - return; - } - - drgui_context* pContext = pTopLevelElement->pContext; - drgui_begin_inbound_event(pContext); - { - drgui_element* pEventReceiver = pContext->pElementWithMouseCapture; - if (pEventReceiver == NULL) - { - pEventReceiver = pContext->pElementUnderMouse; - - if (pEventReceiver == NULL) - { - // We'll get here if this message is posted without a prior mouse move event. - pEventReceiver = drgui_find_element_under_point(pTopLevelElement, (float)mousePosX, (float)mousePosY); - } - } - - - if (pEventReceiver != NULL) - { - float relativeMousePosX = (float)mousePosX; - float relativeMousePosY = (float)mousePosY; - drgui_make_point_relative(pEventReceiver, &relativeMousePosX, &relativeMousePosY); - - drgui_post_outbound_event_mouse_wheel(pEventReceiver, delta, (int)relativeMousePosX, (int)relativeMousePosY, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_key_down(drgui_context* pContext, drgui_key key, int stateFlags) -{ - if (pContext == NULL) { - return; - } - - drgui_begin_inbound_event(pContext); - { - if (pContext->pElementWithKeyboardCapture != NULL) { - drgui_post_outbound_event_key_down(pContext->pElementWithKeyboardCapture, key, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_key_up(drgui_context* pContext, drgui_key key, int stateFlags) -{ - if (pContext == NULL) { - return; - } - - drgui_begin_inbound_event(pContext); - { - if (pContext->pElementWithKeyboardCapture != NULL) { - drgui_post_outbound_event_key_up(pContext->pElementWithKeyboardCapture, key, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - -void drgui_post_inbound_event_printable_key_down(drgui_context* pContext, unsigned int character, int stateFlags) -{ - if (pContext == NULL) { - return; - } - - drgui_begin_inbound_event(pContext); - { - if (pContext->pElementWithKeyboardCapture != NULL) { - drgui_post_outbound_event_printable_key_down(pContext->pElementWithKeyboardCapture, character, stateFlags); - } - } - drgui_end_inbound_event(pContext); -} - - - -void drgui_set_global_on_dirty(drgui_context * pContext, drgui_on_dirty_proc onDirty) -{ - if (pContext != NULL) { - pContext->onGlobalDirty = onDirty; - } -} - -void drgui_set_global_on_capture_mouse(drgui_context* pContext, drgui_on_capture_mouse_proc onCaptureMouse) -{ - if (pContext != NULL) { - pContext->onGlobalCaptureMouse = onCaptureMouse; - } -} - -void drgui_set_global_on_release_mouse(drgui_context* pContext, drgui_on_release_mouse_proc onReleaseMouse) -{ - if (pContext != NULL) { - pContext->onGlobalReleaseMouse = onReleaseMouse; - } -} - -void drgui_set_global_on_capture_keyboard(drgui_context* pContext, drgui_on_capture_keyboard_proc onCaptureKeyboard) -{ - if (pContext != NULL) { - pContext->onGlobalCaptureKeyboard = onCaptureKeyboard; - } -} - -void drgui_set_global_on_release_keyboard(drgui_context* pContext, drgui_on_capture_keyboard_proc onReleaseKeyboard) -{ - if (pContext != NULL) { - pContext->onGlobalReleaseKeyboard = onReleaseKeyboard; - } -} - -void drgui_set_global_on_change_cursor(drgui_context* pContext, drgui_on_change_cursor_proc onChangeCursor) -{ - if (pContext != NULL) { - pContext->onChangeCursor = onChangeCursor; - } -} - -void drgui_set_on_delete_element(drgui_context* pContext, drgui_on_delete_element_proc onDeleteElement) -{ - if (pContext != NULL) { - pContext->onDeleteElement = onDeleteElement; - } -} - -void drgui_set_on_log(drgui_context* pContext, drgui_on_log onLog) -{ - if (pContext != NULL) { - pContext->onLog = onLog; - } -} - - - -///////////////////////////////////////////////////////////////// -// Elements - -drgui_element* drgui_create_element(drgui_context* pContext, drgui_element* pParent, size_t extraDataSize, const void* pExtraData) -{ - if (pContext != NULL) - { - drgui_element* pElement = (drgui_element*)calloc(1, sizeof(drgui_element) + extraDataSize); - if (pElement != NULL) { - pElement->pContext = pContext; - pElement->pParent = pParent; - pElement->cursor = drgui_cursor_default; - pElement->dirtyRect = drgui_make_inside_out_rect(); - - pElement->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pElement->pExtraData, pExtraData, extraDataSize); - } - - // Add to the the hierarchy. - drgui_append_without_detach_or_redraw(pElement, pElement->pParent); - - - // Have the element positioned at 0,0 relative to the parent by default. - if (pParent != NULL) { - pElement->absolutePosX = pParent->absolutePosX; - pElement->absolutePosY = pParent->absolutePosY; - } - - - return pElement; - } - } - - return NULL; -} - -void drgui_delete_element(drgui_element* pElement) -{ - if (pElement == NULL) { - return; - } - - drgui_context* pContext = pElement->pContext; - if (pContext == NULL) { - return; - } - - if (drgui_is_element_marked_as_dead(pElement)) { - drgui_log(pContext, "WARNING: Attempting to delete an element that is already marked for deletion."); - return; - } - - drgui_mark_element_as_dead(pElement); - - - // Notify the application that the element is being deleted. Do this at the top so the event handler can access things like the hierarchy and - // whatnot in case it needs it. - if (pContext->onDeleteElement) { - pContext->onDeleteElement(pElement); - } - - - // If this was element is marked as the one that was last under the mouse it needs to be unset. - bool needsMouseUpdate = false; - if (pContext->pElementUnderMouse == pElement) - { - pContext->pElementUnderMouse = NULL; - needsMouseUpdate = true; - } - - if (pContext->pLastMouseMoveTopLevelElement == pElement) - { - pContext->pLastMouseMoveTopLevelElement = NULL; - pContext->lastMouseMovePosX = 0; - pContext->lastMouseMovePosY = 0; - needsMouseUpdate = false; // It was a top-level element so the mouse enter/leave state doesn't need an update. - } - - - // If this element has the mouse capture it needs to be released. - if (pContext->pElementWithMouseCapture == pElement) - { - drgui_log(pContext, "WARNING: Deleting an element while it still has the mouse capture."); - drgui_release_mouse(pContext); - } - - // If this element has the keyboard capture it needs to be released. - if (pContext->pElementWithKeyboardCapture == pElement) - { - drgui_log(pContext, "WARNING: Deleting an element while it still has the keyboard capture."); - drgui_release_keyboard(pContext); - } - - // Is this element in the middle of being marked as dirty? - for (size_t iDirtyElement = 0; iDirtyElement < pContext->dirtyElementCount; ++iDirtyElement) { - if (pContext->ppDirtyElements[iDirtyElement] == pElement) { - drgui_log(pContext, "WARNING: Deleting an element while it is being marked as dirty."); - for (size_t iDirtyElement2 = iDirtyElement; iDirtyElement2+1 < pContext->dirtyElementCount; ++iDirtyElement2) { - pContext->ppDirtyElements[iDirtyElement2] = pContext->ppDirtyElements[iDirtyElement2+1]; - } - - pContext->dirtyElementCount -= 1; - break; - } - } - -#if 0 - if (pContext->pDirtyTopLevelElement == pElement) - { - drgui_log(pContext, "WARNING: Deleting an element while it is being marked as dirty."); - pContext->pDirtyTopLevelElement = NULL; - } -#endif - - - - // Deleting this element may have resulted in the mouse entering a new element. Here is where we do a mouse enter/leave update. - if (needsMouseUpdate) - { - pElement->onHitTest = drgui_pass_through_hit_test; // <-- This ensures we don't include this element when searching for the new element under the mouse. - drgui_update_mouse_enter_and_leave_state(pContext, drgui_find_element_under_point(pContext->pLastMouseMoveTopLevelElement, pContext->lastMouseMovePosX, pContext->lastMouseMovePosY)); - } - - - // Here is where we need to detach the element from the hierarchy. When doing this we want to ensure the element is not redrawn when - // it's children are detached. To do this we simply detach the event handler. - pElement->onPaint = NULL; - - // The parent needs to be redraw after detaching. - drgui_element* pParent = pElement->pParent; - drgui_rect relativeRect = drgui_get_relative_rect(pElement); - - - // Orphan the element first. - drgui_detach_without_redraw(pElement); - - // Children need to be deleted before deleting the element itself. - while (pElement->pLastChild != NULL) { - drgui_delete_element(pElement->pLastChild); - } - - - // The parent needs to be redrawn. - if (pParent) { - drgui_dirty(pParent, relativeRect); - } - - - // Finally, we to decided whether or not the element should be deleted for real straight away or not. If the element is being - // deleted within an event handler it should be delayed because the event handlers may try referencing it afterwards. - if (!drgui_is_handling_inbound_event(pContext)) { - drgui_delete_element_for_real(pElement); - } -} - - -size_t drgui_get_extra_data_size(drgui_element* pElement) -{ - if (pElement != NULL) { - return pElement->extraDataSize; - } - - return 0; -} - -void* drgui_get_extra_data(drgui_element* pElement) -{ - if (pElement != NULL) { - return pElement->pExtraData; - } - - return NULL; -} - - -bool drgui_set_type(drgui_element* pElement, const char* type) -{ - if (pElement == NULL) { - return false; - } - - return drgui__strcpy_s(pElement->type, sizeof(pElement->type), (type == NULL) ? "" : type) == 0; -} - -const char* drgui_get_type(drgui_element* pElement) -{ - if (pElement == NULL) { - return NULL; - } - - return pElement->type; -} - -bool drgui_is_of_type(drgui_element* pElement, const char* type) -{ - if (pElement == NULL || type == NULL) { - return false; - } - - return strncmp(pElement->type, type, strlen(type)) == 0; -} - - -void drgui_hide(drgui_element* pElement) -{ - if (pElement != NULL) { - pElement->flags |= IS_ELEMENT_HIDDEN; - drgui_auto_dirty(pElement, drgui_get_local_rect(pElement)); - } -} - -void drgui_show(drgui_element* pElement) -{ - if (pElement != NULL) { - pElement->flags &= ~IS_ELEMENT_HIDDEN; - drgui_auto_dirty(pElement, drgui_get_local_rect(pElement)); - } -} - -bool drgui_is_visible(const drgui_element* pElement) -{ - if (pElement != NULL) { - return (pElement->flags & IS_ELEMENT_HIDDEN) == 0; - } - - return false; -} - -bool drgui_is_visible_recursive(const drgui_element* pElement) -{ - if (drgui_is_visible(pElement)) - { - assert(pElement->pParent != NULL); - - if (pElement->pParent != NULL) { - return drgui_is_visible(pElement->pParent); - } - } - - return false; -} - - -void drgui_disable_clipping(drgui_element* pElement) -{ - if (pElement != NULL) { - pElement->flags |= IS_ELEMENT_CLIPPING_DISABLED; - } -} - -void drgui_enable_clipping(drgui_element* pElement) -{ - if (pElement != NULL) { - pElement->flags &= ~IS_ELEMENT_CLIPPING_DISABLED; - } -} - -bool drgui_is_clipping_enabled(const drgui_element* pElement) -{ - if (pElement != NULL) { - return (pElement->flags & IS_ELEMENT_CLIPPING_DISABLED) == 0; - } - - return true; -} - - - -void drgui_capture_mouse(drgui_element* pElement) -{ - if (pElement == NULL) { - return; - } - - if (pElement->pContext == NULL) { - return; - } - - - if (pElement->pContext->pElementWithMouseCapture != pElement) - { - // Release the previous capture first. - if (pElement->pContext->pElementWithMouseCapture != NULL) { - drgui_release_mouse(pElement->pContext); - } - - assert(pElement->pContext->pElementWithMouseCapture == NULL); - - pElement->pContext->pElementWithMouseCapture = pElement; - - // Two events need to be posted - the global on_capture_mouse event and the local on_capture_mouse event. - drgui_post_outbound_event_capture_mouse(pElement); - - if (pElement == pElement->pContext->pElementWithMouseCapture) { // <-- Only post the global event handler if the element still has the capture. - drgui_post_outbound_event_capture_mouse_global(pElement); - } - } -} - -void drgui_release_mouse(drgui_context* pContext) -{ - if (pContext == NULL) { - return; - } - - - // Events need to be posted before setting the internal pointer. - if (!drgui_is_element_marked_as_dead(pContext->pElementWithMouseCapture)) { // <-- There's a chace the element is releaseing the keyboard due to being deleted. Don't want to post an event in this case. - drgui_post_outbound_event_release_mouse(pContext->pElementWithMouseCapture); - drgui_post_outbound_event_release_mouse_global(pContext->pElementWithMouseCapture); - } - - // We want to set the internal pointer to NULL after posting the events since that is when it has truly released the mouse. - pContext->pElementWithMouseCapture = NULL; - - - // After releasing the mouse the cursor may be sitting on top of a different element - we want to recheck that. - drgui_update_mouse_enter_and_leave_state(pContext, drgui_find_element_under_point(pContext->pLastMouseMoveTopLevelElement, pContext->lastMouseMovePosX, pContext->lastMouseMovePosY)); -} - -void drgui_release_mouse_no_global_notify(drgui_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drgui_on_release_mouse_proc prevProc = pContext->onGlobalReleaseMouse; - pContext->onGlobalReleaseMouse = NULL; - drgui_release_mouse(pContext); - pContext->onGlobalReleaseMouse = prevProc; -} - -drgui_element* drgui_get_element_with_mouse_capture(drgui_context* pContext) -{ - if (pContext == NULL) { - return NULL; - } - - return pContext->pElementWithMouseCapture; -} - -bool drgui_has_mouse_capture(drgui_element* pElement) -{ - if (pElement == NULL) { - return false; - } - - return drgui_get_element_with_mouse_capture(pElement->pContext) == pElement; -} - - -DRGUI_PRIVATE void drgui_release_keyboard_private(drgui_context* pContext, drgui_element* pNewCapturedElement) -{ - assert(pContext != NULL); - - // It is reasonable to expect that an application will want to change keyboard focus from within the release_keyboard - // event handler. The problem with this is that is can cause a infinite dependency chain. We need to handle that case - // by setting a flag that keeps track of whether or not we are in the middle of a release_keyboard event. At the end - // we look at the element that want's the keyboard focuse and explicitly capture it at the end. - - pContext->flags |= IS_RELEASING_KEYBOARD; - { - drgui_element* pPrevCapturedElement = pContext->pElementWithKeyboardCapture; - pContext->pElementWithKeyboardCapture = NULL; - - if (!drgui_is_element_marked_as_dead(pPrevCapturedElement)) { // <-- There's a chace the element is releaseing the keyboard due to being deleted. Don't want to post an event in this case. - drgui_post_outbound_event_release_keyboard(pPrevCapturedElement, pNewCapturedElement); - drgui_post_outbound_event_release_keyboard_global(pPrevCapturedElement, pNewCapturedElement); - } - } - pContext->flags &= ~IS_RELEASING_KEYBOARD; - - // Explicitly capture the keyboard. - drgui_capture_keyboard(pContext->pElementWantingKeyboardCapture); - pContext->pElementWantingKeyboardCapture = NULL; -} - -void drgui_capture_keyboard(drgui_element* pElement) -{ - if (pElement == NULL) { - return; - } - - if (pElement->pContext == NULL) { - return; - } - - - if ((pElement->pContext->flags & IS_RELEASING_KEYBOARD) != 0) { - pElement->pContext->pElementWantingKeyboardCapture = pElement; - return; - } - - - if (pElement->pContext->pElementWithKeyboardCapture != pElement) - { - // Release the previous capture first. - drgui_element* pPrevElementWithKeyboardCapture = pElement->pContext->pElementWithKeyboardCapture; - if (pPrevElementWithKeyboardCapture != NULL) { - drgui_release_keyboard_private(pElement->pContext, pElement); - } - - assert(pElement->pContext->pElementWithKeyboardCapture == NULL); - - pElement->pContext->pElementWithKeyboardCapture = pElement; - pElement->pContext->pElementWantingKeyboardCapture = NULL; - - // Two events need to be posted - the global on_capture event and the local on_capture event. The problem, however, is that the - // local event handler may change the keyboard capture internally, such as if it wants to pass it's focus onto an internal child - // element or whatnot. In this case we don't want to fire the global event handler because it will result in superfluous event - // posting, and could also be posted with an incorrect element. - drgui_post_outbound_event_capture_keyboard(pElement, pPrevElementWithKeyboardCapture); - - if (pElement == pElement->pContext->pElementWithKeyboardCapture) { // <-- Only post the global event handler if the element still has the capture. - drgui_post_outbound_event_capture_keyboard_global(pElement, pPrevElementWithKeyboardCapture); - } - } -} - -void drgui_release_keyboard(drgui_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drgui_release_keyboard_private(pContext, NULL); -} - -void drgui_release_keyboard_no_global_notify(drgui_context* pContext) -{ - if (pContext == NULL) { - return; - } - - drgui_on_release_keyboard_proc prevProc = pContext->onGlobalReleaseKeyboard; - pContext->onGlobalReleaseKeyboard = NULL; - drgui_release_keyboard(pContext); - pContext->onGlobalReleaseKeyboard = prevProc; -} - -drgui_element* drgui_get_element_with_keyboard_capture(drgui_context* pContext) -{ - if (pContext == NULL) { - return NULL; - } - - return pContext->pElementWithKeyboardCapture; -} - -bool drgui_has_keyboard_capture(drgui_element* pElement) -{ - if (pElement == NULL) { - return false; - } - - return drgui_get_element_with_keyboard_capture(pElement->pContext) == pElement; -} - - -void drgui_set_cursor(drgui_element* pElement, drgui_cursor_type cursor) -{ - if (pElement == NULL) { - return; - } - - pElement->cursor = cursor; - - if (drgui_is_element_under_mouse(pElement) && pElement->pContext->currentCursor != cursor) { - drgui__change_cursor(pElement, cursor); - } -} - -drgui_cursor_type drgui_get_cursor(drgui_element* pElement) -{ - if (pElement == NULL) { - return drgui_cursor_none; - } - - return pElement->cursor; -} - - - -//// Events //// - -void drgui_set_on_move(drgui_element * pElement, drgui_on_move_proc callback) -{ - if (pElement != NULL) { - pElement->onMove = callback; - } -} - -void drgui_set_on_size(drgui_element * pElement, drgui_on_size_proc callback) -{ - if (pElement != NULL) { - pElement->onSize = callback; - } -} - -void drgui_set_on_mouse_enter(drgui_element* pElement, drgui_on_mouse_enter_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseEnter = callback; - } -} - -void drgui_set_on_mouse_leave(drgui_element* pElement, drgui_on_mouse_leave_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseLeave = callback; - } -} - -void drgui_set_on_mouse_move(drgui_element* pElement, drgui_on_mouse_move_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseMove = callback; - } -} - -void drgui_set_on_mouse_button_down(drgui_element* pElement, drgui_on_mouse_button_down_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseButtonDown = callback; - } -} - -void drgui_set_on_mouse_button_up(drgui_element* pElement, drgui_on_mouse_button_up_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseButtonUp = callback; - } -} - -void drgui_set_on_mouse_button_dblclick(drgui_element* pElement, drgui_on_mouse_button_dblclick_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseButtonDblClick = callback; - } -} - -void drgui_set_on_mouse_wheel(drgui_element* pElement, drgui_on_mouse_wheel_proc callback) -{ - if (pElement != NULL) { - pElement->onMouseWheel = callback; - } -} - -void drgui_set_on_key_down(drgui_element* pElement, drgui_on_key_down_proc callback) -{ - if (pElement != NULL) { - pElement->onKeyDown = callback; - } -} - -void drgui_set_on_key_up(drgui_element* pElement, drgui_on_key_up_proc callback) -{ - if (pElement != NULL) { - pElement->onKeyUp = callback; - } -} - -void drgui_set_on_printable_key_down(drgui_element* pElement, drgui_on_printable_key_down_proc callback) -{ - if (pElement != NULL) { - pElement->onPrintableKeyDown = callback; - } -} - -void drgui_set_on_paint(drgui_element* pElement, drgui_on_paint_proc callback) -{ - if (pElement != NULL) { - pElement->onPaint = callback; - } -} - -void drgui_set_on_dirty(drgui_element * pElement, drgui_on_dirty_proc callback) -{ - if (pElement != NULL) { - pElement->onDirty = callback; - } -} - -void drgui_set_on_hittest(drgui_element* pElement, drgui_on_hittest_proc callback) -{ - if (pElement != NULL) { - pElement->onHitTest = callback; - } -} - -void drgui_set_on_capture_mouse(drgui_element* pElement, drgui_on_capture_mouse_proc callback) -{ - if (pElement != NULL) { - pElement->onCaptureMouse = callback; - } -} - -void drgui_set_on_release_mouse(drgui_element* pElement, drgui_on_release_mouse_proc callback) -{ - if (pElement != NULL) { - pElement->onReleaseMouse = callback; - } -} - -void drgui_set_on_capture_keyboard(drgui_element* pElement, drgui_on_capture_keyboard_proc callback) -{ - if (pElement != NULL) { - pElement->onCaptureKeyboard = callback; - } -} - -void drgui_set_on_release_keyboard(drgui_element* pElement, drgui_on_release_keyboard_proc callback) -{ - if (pElement != NULL) { - pElement->onReleaseKeyboard = callback; - } -} - - - -bool drgui_is_point_inside_element_bounds(const drgui_element* pElement, float absolutePosX, float absolutePosY) -{ - if (absolutePosX < pElement->absolutePosX || - absolutePosX < pElement->absolutePosY) - { - return false; - } - - if (absolutePosX >= pElement->absolutePosX + pElement->width || - absolutePosY >= pElement->absolutePosY + pElement->height) - { - return false; - } - - return true; -} - -bool drgui_is_point_inside_element(drgui_element* pElement, float absolutePosX, float absolutePosY) -{ - if (drgui_is_point_inside_element_bounds(pElement, absolutePosX, absolutePosY)) - { - // It is valid for onHitTest to be null, in which case we use the default hit test which assumes the element is just a rectangle - // equal to the size of it's bounds. It's equivalent to onHitTest always returning true. - - if (pElement->onHitTest) { - return pElement->onHitTest(pElement, absolutePosX - pElement->absolutePosX, absolutePosY - pElement->absolutePosY); - } - - return true; - } - - return false; -} - - - -typedef struct -{ - drgui_element* pElementUnderPoint; - float absolutePosX; - float absolutePosY; -}drgui_find_element_under_point_data; - -bool drgui_find_element_under_point_iterator(drgui_element* pElement, drgui_rect* pRelativeVisibleRect, void* pUserData) -{ - assert(pElement != NULL); - assert(pRelativeVisibleRect != NULL); - - drgui_find_element_under_point_data* pData = (drgui_find_element_under_point_data*)pUserData; - assert(pData != NULL); - - float relativePosX = pData->absolutePosX; - float relativePosY = pData->absolutePosY; - drgui_make_point_relative(pElement, &relativePosX, &relativePosY); - - if (drgui_rect_contains_point(*pRelativeVisibleRect, relativePosX, relativePosY)) - { - if (pElement->onHitTest) { - if (pElement->onHitTest(pElement, relativePosX, relativePosY)) { - pData->pElementUnderPoint = pElement; - } - } else { - pData->pElementUnderPoint = pElement; - } - } - - - // Always return true to ensure the entire hierarchy is checked. - return true; -} - -drgui_element* drgui_find_element_under_point(drgui_element* pTopLevelElement, float absolutePosX, float absolutePosY) -{ - if (pTopLevelElement == NULL) { - return NULL; - } - - drgui_find_element_under_point_data data; - data.pElementUnderPoint = NULL; - data.absolutePosX = absolutePosX; - data.absolutePosY = absolutePosY; - drgui_iterate_visible_elements(pTopLevelElement, drgui_get_absolute_rect(pTopLevelElement), drgui_find_element_under_point_iterator, &data); - - return data.pElementUnderPoint; -} - -bool drgui_is_element_under_mouse(drgui_element* pElement) -{ - if (pElement == NULL) { - return false; - } - - return drgui_find_element_under_point(pElement->pContext->pLastMouseMoveTopLevelElement, pElement->pContext->lastMouseMovePosX, pElement->pContext->lastMouseMovePosY) == pElement; -} - - - -//// Hierarchy //// - -drgui_element* drgui_get_parent(drgui_element* pChildElement) -{ - if (pChildElement == NULL) { - return NULL; - } - - return pChildElement->pParent; -} - -void drgui_detach(drgui_element* pChildElement) -{ - if (pChildElement == NULL) { - return; - } - - drgui_element* pOldParent = pChildElement->pParent; - - - // We orphan the element using the private API. This will not mark the parent element as dirty so we need to do that afterwards. - drgui_detach_without_redraw(pChildElement); - - // The region of the old parent needs to be redrawn. - if (pOldParent != NULL) { - drgui_auto_dirty(pOldParent, drgui_get_relative_rect(pOldParent)); - } -} - -void drgui_append(drgui_element* pChildElement, drgui_element* pParentElement) -{ - if (pChildElement == NULL) { - return; - } - - // We first need to orphan the element. If the parent element is the new parent is the same as the old one, as in we - // are just moving the child element to the end of the children list, we want to delay the repaint until the end. To - // do this we use drgui_detach_without_redraw() because that will not trigger a redraw. - if (pChildElement->pParent != pParentElement) { - drgui_detach(pChildElement); - } else { - drgui_detach_without_redraw(pChildElement); - } - - - // Now we attach it to the end of the new parent. - if (pParentElement != NULL) { - drgui_append_without_detach(pChildElement, pParentElement); - } -} - -void drgui_prepend(drgui_element* pChildElement, drgui_element* pParentElement) -{ - if (pChildElement == NULL) { - return; - } - - // See comment in drgui_append() for explanation on this. - if (pChildElement->pParent != pParentElement) { - drgui_detach(pChildElement); - } else { - drgui_detach_without_redraw(pChildElement); - } - - - // Now we need to attach the element to the beginning of the parent. - if (pParentElement != NULL) { - drgui_prepend_without_detach(pChildElement, pParentElement); - } -} - -void drgui_append_sibling(drgui_element* pElementToAppend, drgui_element* pElementToAppendTo) -{ - if (pElementToAppend == NULL || pElementToAppendTo == NULL) { - return; - } - - // See comment in drgui_append() for explanation on this. - if (pElementToAppend->pParent != pElementToAppendTo->pParent) { - drgui_detach(pElementToAppend); - } else { - drgui_detach_without_redraw(pElementToAppend); - } - - - // Now we need to attach the element such that it comes just after pElementToAppendTo - drgui_append_sibling_without_detach(pElementToAppend, pElementToAppendTo); -} - -void drgui_prepend_sibling(drgui_element* pElementToPrepend, drgui_element* pElementToPrependTo) -{ - if (pElementToPrepend == NULL || pElementToPrependTo == NULL) { - return; - } - - // See comment in drgui_append() for explanation on this. - if (pElementToPrepend->pParent != pElementToPrependTo->pParent) { - drgui_detach(pElementToPrepend); - } else { - drgui_detach_without_redraw(pElementToPrepend); - } - - - // Now we need to attach the element such that it comes just after pElementToPrependTo - drgui_prepend_sibling_without_detach(pElementToPrepend, pElementToPrependTo); -} - -drgui_element* drgui_find_top_level_element(drgui_element* pElement) -{ - if (pElement == NULL) { - return NULL; - } - - if (pElement->pParent != NULL) { - return drgui_find_top_level_element(pElement->pParent); - } - - return pElement; -} - -bool drgui_is_parent(drgui_element* pParentElement, drgui_element* pChildElement) -{ - if (pParentElement == NULL || pChildElement == NULL) { - return false; - } - - return pParentElement == pChildElement->pParent; -} - -bool drgui_is_child(drgui_element* pChildElement, drgui_element* pParentElement) -{ - return drgui_is_parent(pParentElement, pChildElement); -} - -bool drgui_is_ancestor(drgui_element* pAncestorElement, drgui_element* pChildElement) -{ - if (pAncestorElement == NULL || pChildElement == NULL) { - return false; - } - - drgui_element* pParent = pChildElement->pParent; - while (pParent != NULL) - { - if (pParent == pAncestorElement) { - return true; - } - - pParent = pParent->pParent; - } - - - return false; -} - -bool drgui_is_descendant(drgui_element* pChildElement, drgui_element* pAncestorElement) -{ - return drgui_is_ancestor(pAncestorElement, pChildElement); -} - -bool drgui_is_self_or_ancestor(drgui_element* pAncestorElement, drgui_element* pChildElement) -{ - return pAncestorElement == pChildElement || drgui_is_ancestor(pAncestorElement, pChildElement); -} - -bool drgui_is_self_or_descendant(drgui_element* pChildElement, drgui_element* pAncestorElement) -{ - return pChildElement == pAncestorElement || drgui_is_descendant(pChildElement, pAncestorElement); -} - - - -//// Layout //// - -void drgui_set_absolute_position(drgui_element* pElement, float positionX, float positionY) -{ - if (pElement != NULL) - { - if (pElement->absolutePosX != positionX || pElement->absolutePosY != positionY) - { - float oldRelativePosX = drgui_get_relative_position_x(pElement); - float oldRelativePosY = drgui_get_relative_position_y(pElement); - - drgui_begin_auto_dirty(pElement); - { - drgui_auto_dirty(pElement, drgui_get_local_rect(pElement)); // <-- Previous rectangle. - - float offsetX = positionX - pElement->absolutePosX; - float offsetY = positionY - pElement->absolutePosY; - - pElement->absolutePosX = positionX; - pElement->absolutePosY = positionY; - drgui_auto_dirty(pElement, drgui_get_local_rect(pElement)); // <-- New rectangle. - - - float newRelativePosX = drgui_get_relative_position_x(pElement); - float newRelativePosY = drgui_get_relative_position_y(pElement); - - if (newRelativePosX != oldRelativePosX || newRelativePosY != oldRelativePosY) { - drgui_post_outbound_event_move(pElement, newRelativePosX, newRelativePosY); - } - - - drgui_apply_offset_to_children_recursive(pElement, offsetX, offsetY); - } - drgui_end_auto_dirty(pElement); - } - } -} - -void drgui_get_absolute_position(const drgui_element* pElement, float * positionXOut, float * positionYOut) -{ - if (pElement != NULL) - { - if (positionXOut != NULL) { - *positionXOut = pElement->absolutePosX; - } - - if (positionYOut != NULL) { - *positionYOut = pElement->absolutePosY; - } - } -} - -float drgui_get_absolute_position_x(const drgui_element* pElement) -{ - if (pElement != NULL) { - return pElement->absolutePosX; - } - - return 0.0f; -} - -float drgui_get_absolute_position_y(const drgui_element* pElement) -{ - if (pElement != NULL) { - return pElement->absolutePosY; - } - - return 0.0f; -} - - -void drgui_set_relative_position(drgui_element* pElement, float relativePosX, float relativePosY) -{ - if (pElement != NULL) { - if (pElement->pParent != NULL) { - drgui_set_absolute_position(pElement, pElement->pParent->absolutePosX + relativePosX, pElement->pParent->absolutePosY + relativePosY); - } else { - drgui_set_absolute_position(pElement, relativePosX, relativePosY); - } - } -} - -void drgui_get_relative_position(const drgui_element* pElement, float* positionXOut, float* positionYOut) -{ - if (pElement != NULL) - { - if (pElement->pParent != NULL) - { - if (positionXOut != NULL) { - *positionXOut = pElement->absolutePosX - pElement->pParent->absolutePosX; - } - - if (positionYOut != NULL) { - *positionYOut = pElement->absolutePosY - pElement->pParent->absolutePosY; - } - } - else - { - if (positionXOut != NULL) { - *positionXOut = pElement->absolutePosX; - } - - if (positionYOut != NULL) { - *positionYOut = pElement->absolutePosY; - } - } - } -} - -float drgui_get_relative_position_x(const drgui_element* pElement) -{ - if (pElement != NULL) { - if (pElement->pParent != NULL) { - return pElement->absolutePosX - pElement->pParent->absolutePosX; - } else { - return pElement->absolutePosX; - } - } - - return 0; -} - -float drgui_get_relative_position_y(const drgui_element* pElement) -{ - if (pElement != NULL) { - if (pElement->pParent != NULL) { - return pElement->absolutePosY - pElement->pParent->absolutePosY; - } else { - return pElement->absolutePosY; - } - } - - return 0; -} - - -void drgui_set_size(drgui_element* pElement, float width, float height) -{ - if (pElement != NULL) - { - if (pElement->width != width || pElement->height != height) - { - drgui_begin_auto_dirty(pElement); - { - drgui_auto_dirty(pElement, drgui_get_local_rect(pElement)); // <-- Previous rectangle. - - pElement->width = width; - pElement->height = height; - drgui_auto_dirty(pElement, drgui_get_local_rect(pElement)); // <-- New rectangle. - - drgui_post_outbound_event_size(pElement, width, height); - } - drgui_end_auto_dirty(pElement); - } - } -} - -void drgui_get_size(const drgui_element* pElement, float* widthOut, float* heightOut) -{ - if (pElement != NULL) { - if (widthOut) *widthOut = pElement->width; - if (heightOut) *heightOut = pElement->height; - } else { - if (widthOut) *widthOut = 0; - if (heightOut) *heightOut = 0; - } -} - -float drgui_get_width(const drgui_element * pElement) -{ - if (pElement != NULL) { - return pElement->width; - } - - return 0; -} - -float drgui_get_height(const drgui_element * pElement) -{ - if (pElement != NULL) { - return pElement->height; - } - - return 0; -} - - -drgui_rect drgui_get_absolute_rect(const drgui_element* pElement) -{ - drgui_rect rect; - if (pElement != NULL) - { - rect.left = pElement->absolutePosX; - rect.top = pElement->absolutePosY; - rect.right = rect.left + pElement->width; - rect.bottom = rect.top + pElement->height; - } - else - { - rect.left = 0; - rect.top = 0; - rect.right = 0; - rect.bottom = 0; - } - - return rect; -} - -drgui_rect drgui_get_relative_rect(const drgui_element* pElement) -{ - drgui_rect rect; - if (pElement != NULL) - { - rect.left = drgui_get_relative_position_x(pElement); - rect.top = drgui_get_relative_position_y(pElement); - rect.right = rect.left + pElement->width; - rect.bottom = rect.top + pElement->height; - } - else - { - rect.left = 0; - rect.top = 0; - rect.right = 0; - rect.bottom = 0; - } - - return rect; -} - -drgui_rect drgui_get_local_rect(const drgui_element* pElement) -{ - drgui_rect rect; - rect.left = 0; - rect.top = 0; - - if (pElement != NULL) - { - rect.right = pElement->width; - rect.bottom = pElement->height; - } - else - { - rect.right = 0; - rect.bottom = 0; - } - - return rect; -} - - - -//// Painting //// - -bool drgui_register_painting_callbacks(drgui_context* pContext, void* pPaintingContext, drgui_painting_callbacks callbacks) -{ - if (pContext == NULL) { - return false; - } - - // Fail if the painting callbacks have already been registered. - if (pContext->pPaintingContext != NULL) { - return false; - } - - - pContext->pPaintingContext = pPaintingContext; - pContext->paintingCallbacks = callbacks; - - return true; -} - - -bool drgui_iterate_visible_elements(drgui_element* pParentElement, drgui_rect relativeRect, drgui_visible_iteration_proc callback, void* pUserData) -{ - if (pParentElement == NULL) { - return false; - } - - if (callback == NULL) { - return false; - } - - - if (!drgui_is_visible(pParentElement)) { - return true; - } - - drgui_rect clampedRelativeRect = relativeRect; - if (drgui_clamp_rect_to_element(pParentElement, &clampedRelativeRect)) - { - // We'll only get here if some part of the rectangle was inside the element. - if (!callback(pParentElement, &clampedRelativeRect, pUserData)) { - return false; - } - } - - for (drgui_element* pChild = pParentElement->pFirstChild; pChild != NULL; pChild = pChild->pNextSibling) - { - float childRelativePosX = drgui_get_relative_position_x(pChild); - float childRelativePosY = drgui_get_relative_position_y(pChild); - - drgui_rect childRect; - if (drgui_is_clipping_enabled(pChild)) { - childRect = clampedRelativeRect; - } else { - childRect = relativeRect; - } - - - childRect.left -= childRelativePosX; - childRect.top -= childRelativePosY; - childRect.right -= childRelativePosX; - childRect.bottom -= childRelativePosY; - - if (!drgui_iterate_visible_elements(pChild, childRect, callback, pUserData)) { - return false; - } - } - - - return true; -} - -void drgui_disable_auto_dirty(drgui_context* pContext) -{ - if (pContext != NULL) { - pContext->flags |= IS_AUTO_DIRTY_DISABLED; - } -} - -void drgui_enable_auto_dirty(drgui_context* pContext) -{ - if (pContext != NULL) { - pContext->flags &= ~IS_AUTO_DIRTY_DISABLED; - } -} - -bool drgui_is_auto_dirty_enabled(drgui_context* pContext) -{ - if (pContext != NULL) { - return (pContext->flags & IS_AUTO_DIRTY_DISABLED) == 0; - } - - return false; -} - - -drgui_element* drgui_begin_dirty(drgui_element* pElement) -{ - if (pElement == NULL) { - return NULL; - } - - drgui_context* pContext = pElement->pContext; - assert(pContext != NULL); - - drgui_element* pTopLevelElement = drgui_find_top_level_element(pElement); - assert(pTopLevelElement != NULL); - - // The element needs to be added to the list of dirty elements if it doesn't exist already. - bool isAlreadyDirty = false; - for (size_t iDirtyElementCount = 0; iDirtyElementCount < pContext->dirtyElementCount; ++iDirtyElementCount) { - if (pContext->ppDirtyElements[iDirtyElementCount] == pTopLevelElement) { - isAlreadyDirty = true; - break; - } - } - - if (!isAlreadyDirty) { - if (pContext->dirtyElementCount == pContext->dirtyElementBufferSize) { - size_t newBufferSize = pContext->dirtyElementBufferSize == 0 ? 1 : pContext->dirtyElementBufferSize*2; - drgui_element** ppNewDirtyElements = (drgui_element**)realloc(pContext->ppDirtyElements, newBufferSize * sizeof(*ppNewDirtyElements)); - if (ppNewDirtyElements == NULL) { - return NULL; - } - - pContext->ppDirtyElements = ppNewDirtyElements; - pContext->dirtyElementBufferSize = newBufferSize; - } - - pContext->ppDirtyElements[pContext->dirtyCounter] = pTopLevelElement; - pContext->dirtyElementCount += 1; - } - - - pContext->dirtyCounter += 1; - return pTopLevelElement; -} - -void drgui_end_dirty(drgui_element* pElement) -{ - if (pElement == NULL) { - return; - } - - drgui_context* pContext = pElement->pContext; - assert(pContext != NULL); - - assert(pContext->dirtyElementCount > 0); - assert(pContext->dirtyCounter > 0); - - pContext->dirtyCounter -= 1; - if (pContext->dirtyCounter == 0) - { - for (size_t i = 0; i < pContext->dirtyElementCount; ++i) { - drgui_post_outbound_event_dirty_global(pContext->ppDirtyElements[i], pContext->ppDirtyElements[i]->dirtyRect); - pContext->ppDirtyElements[i]->dirtyRect = drgui_make_inside_out_rect(); - } - - pContext->dirtyElementCount = 0; - } -} - -void drgui_dirty(drgui_element* pElement, drgui_rect relativeRect) -{ - if (pElement == NULL) { - return; - } - - //drgui_context* pContext = pElement->pContext; - //assert(pContext != NULL); - - drgui_element* pTopLevelElement = drgui_begin_dirty(pElement); - if (pTopLevelElement == NULL) { - return; - } - - pTopLevelElement->dirtyRect = drgui_rect_union(pTopLevelElement->dirtyRect, drgui_make_rect_absolute(pElement, &relativeRect)); - drgui_end_dirty(pElement); -} - - -bool drgui_draw_iteration_callback(drgui_element* pElement, drgui_rect* pRelativeRect, void* pUserData) -{ - assert(pElement != NULL); - assert(pRelativeRect != NULL); - - if (pElement->onPaint != NULL) - { - // We want to set the initial clipping rectangle before drawing. - drgui_set_clip(pElement, *pRelativeRect, pUserData); - - // We now call the painting function, but only after setting the clipping rectangle. - pElement->onPaint(pElement, *pRelativeRect, pUserData); - - // The on_paint event handler may have adjusted the clipping rectangle so we need to ensure it's restored. - drgui_set_clip(pElement, *pRelativeRect, pUserData); - } - - return true; -} - -void drgui_draw(drgui_element* pElement, drgui_rect relativeRect, void* pPaintData) -{ - if (pElement == NULL) { - return; - } - - drgui_context* pContext = pElement->pContext; - if (pContext == NULL) { - return; - } - - assert(pContext->paintingCallbacks.drawBegin != NULL); - assert(pContext->paintingCallbacks.drawEnd != NULL); - - pContext->paintingCallbacks.drawBegin(pPaintData); - { - drgui_iterate_visible_elements(pElement, relativeRect, drgui_draw_iteration_callback, pPaintData); - } - pContext->paintingCallbacks.drawEnd(pPaintData); -} - -void drgui_get_clip(drgui_element* pElement, drgui_rect* pRelativeRect, void* pPaintData) -{ - if (pElement == NULL || pElement->pContext == NULL) { - return; - } - - pElement->pContext->paintingCallbacks.getClip(pRelativeRect, pPaintData); - - // The clip returned by the drawing callback will be absolute so we'll need to convert that to relative. - drgui_make_rect_relative(pElement, pRelativeRect); -} - -void drgui_set_clip(drgui_element* pElement, drgui_rect relativeRect, void* pPaintData) -{ - if (pElement == NULL || pElement->pContext == NULL) { - return; - } - - - // Make sure the rectangle is not negative. - if (relativeRect.right < relativeRect.left) { - relativeRect.right = relativeRect.left; - } - - if (relativeRect.bottom < relativeRect.top) { - relativeRect.bottom = relativeRect.top; - } - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.setClip(absoluteRect, pPaintData); -} - -void drgui_draw_rect(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, void* pPaintData) -{ - if (pElement == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.drawRect(absoluteRect, color, pPaintData); -} - -void drgui_draw_rect_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float outlineWidth, void* pPaintData) -{ - if (pElement == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.drawRectOutline(absoluteRect, color, outlineWidth, pPaintData); -} - -void drgui_draw_rect_with_outline(drgui_element * pElement, drgui_rect relativeRect, drgui_color color, float outlineWidth, drgui_color outlineColor, void * pPaintData) -{ - if (pElement == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.drawRectWithOutline(absoluteRect, color, outlineWidth, outlineColor, pPaintData); -} - -void drgui_draw_round_rect(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float radius, void* pPaintData) -{ - if (pElement == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.drawRoundRect(absoluteRect, color, radius, pPaintData); -} - -void drgui_draw_round_rect_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float radius, float outlineWidth, void* pPaintData) -{ - if (pElement == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.drawRoundRectOutline(absoluteRect, color, radius, outlineWidth, pPaintData); -} - -void drgui_draw_round_rect_with_outline(drgui_element* pElement, drgui_rect relativeRect, drgui_color color, float radius, float outlineWidth, drgui_color outlineColor, void* pPaintData) -{ - if (pElement == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_rect absoluteRect = relativeRect; - drgui_make_rect_absolute(pElement, &absoluteRect); - - pElement->pContext->paintingCallbacks.drawRoundRectWithOutline(absoluteRect, color, radius, outlineWidth, outlineColor, pPaintData); -} - -void drgui_draw_text(drgui_element* pElement, drgui_font* pFont, const char* text, int textLengthInBytes, float posX, float posY, drgui_color color, drgui_color backgroundColor, void* pPaintData) -{ - if (pElement == NULL || pFont == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - float absolutePosX = posX; - float absolutePosY = posY; - drgui_make_point_absolute(pElement, &absolutePosX, &absolutePosY); - - pElement->pContext->paintingCallbacks.drawText(pFont->internalFont, text, textLengthInBytes, absolutePosX, absolutePosY, color, backgroundColor, pPaintData); -} - -void drgui_draw_image(drgui_element* pElement, drgui_image* pImage, drgui_draw_image_args* pArgs, void* pPaintData) -{ - if (pElement == NULL || pImage == NULL || pArgs == NULL) { - return; - } - - assert(pElement->pContext != NULL); - - drgui_make_point_absolute(pElement, &pArgs->dstX, &pArgs->dstY); - drgui_make_point_absolute(pElement, &pArgs->dstBoundsX, &pArgs->dstBoundsY); - - if ((pArgs->options & DRGUI_IMAGE_ALIGN_CENTER) != 0) - { - pArgs->dstX = pArgs->dstBoundsX + (pArgs->dstBoundsWidth - pArgs->dstWidth) / 2; - pArgs->dstY = pArgs->dstBoundsY + (pArgs->dstBoundsHeight - pArgs->dstHeight) / 2; - } - - drgui_rect prevClip; - pElement->pContext->paintingCallbacks.getClip(&prevClip, pPaintData); - - bool restoreClip = false; - if ((pArgs->options & DRGUI_IMAGE_CLIP_BOUNDS) != 0) - { - // We only need to clip if part of the destination rectangle falls outside of the bounds. - if (pArgs->dstX < pArgs->dstBoundsX || pArgs->dstX + pArgs->dstWidth > pArgs->dstBoundsX + pArgs->dstBoundsWidth || - pArgs->dstY < pArgs->dstBoundsY || pArgs->dstY + pArgs->dstHeight > pArgs->dstBoundsY + pArgs->dstBoundsHeight) - { - restoreClip = true; - pElement->pContext->paintingCallbacks.setClip(drgui_make_rect(pArgs->dstBoundsX, pArgs->dstBoundsY, pArgs->dstBoundsX + pArgs->dstBoundsWidth, pArgs->dstBoundsY + pArgs->dstBoundsHeight), pPaintData); - } - } - - if ((pArgs->options & DRGUI_IMAGE_DRAW_BOUNDS) != 0) - { - // The bounds is the area sitting around the outside of the destination rectangle. - const float boundsLeft = pArgs->dstBoundsX; - const float boundsTop = pArgs->dstBoundsY; - const float boundsRight = boundsLeft + pArgs->dstBoundsWidth; - const float boundsBottom = boundsTop + pArgs->dstBoundsHeight; - - const float imageLeft = pArgs->dstX; - const float imageTop = pArgs->dstY; - const float imageRight = imageLeft + pArgs->dstWidth; - const float imageBottom = imageTop + pArgs->dstHeight; - - // Left. - if (boundsLeft < imageLeft) { - pElement->pContext->paintingCallbacks.drawRect(drgui_make_rect(boundsLeft, boundsTop, imageLeft, boundsBottom), pArgs->boundsColor, pPaintData); - } - - // Right. - if (boundsRight > imageRight) { - pElement->pContext->paintingCallbacks.drawRect(drgui_make_rect(imageRight, boundsTop, boundsRight, boundsBottom), pArgs->boundsColor, pPaintData); - } - - // Top. - if (boundsTop < imageTop) { - pElement->pContext->paintingCallbacks.drawRect(drgui_make_rect(imageLeft, boundsTop, imageRight, imageTop), pArgs->boundsColor, pPaintData); - } - - // Bottom. - if (boundsBottom > imageBottom) { - pElement->pContext->paintingCallbacks.drawRect(drgui_make_rect(imageLeft, imageBottom, imageRight, boundsBottom), pArgs->boundsColor, pPaintData); - } - } - - pElement->pContext->paintingCallbacks.drawImage(pImage->hResource, pArgs, pPaintData); - - if (restoreClip) { - pElement->pContext->paintingCallbacks.setClip(prevClip, pPaintData); - } -} - - -drgui_font* drgui_create_font(drgui_context* pContext, const char* family, unsigned int size, drgui_font_weight weight, drgui_font_slant slant, float rotation, unsigned int flags) -{ - if (pContext == NULL) { - return NULL; - } - - if (pContext->paintingCallbacks.createFont == NULL) { - return NULL; - } - - - drgui_resource internalFont = pContext->paintingCallbacks.createFont(pContext->pPaintingContext, family, size, weight, slant, rotation, flags); - if (internalFont == NULL) { - return NULL; - } - - drgui_font* pFont = (drgui_font*)malloc(sizeof(drgui_font)); - if (pFont == NULL) { - return NULL; - } - - pFont->pContext = pContext; - pFont->family[0] = '\0'; - pFont->size = size; - pFont->weight = weight; - pFont->slant = slant; - pFont->rotation = rotation; - pFont->flags = flags; - pFont->internalFont = internalFont; - - if (family != NULL) { - drgui__strcpy_s(pFont->family, sizeof(pFont->family), family); - } - - return pFont; -} - -void drgui_delete_font(drgui_font* pFont) -{ - if (pFont == NULL) { - return; - } - - assert(pFont->pContext != NULL); - - // Delete the internal font objects first. - if (pFont->pContext->paintingCallbacks.deleteFont) { - pFont->pContext->paintingCallbacks.deleteFont(pFont->internalFont); - } - - free(pFont); -} - -bool drgui_get_font_metrics(drgui_font* pFont, drgui_font_metrics* pMetricsOut) -{ - if (pFont == NULL || pMetricsOut == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->paintingCallbacks.getFontMetrics == NULL) { - return false; - } - - return pFont->pContext->paintingCallbacks.getFontMetrics(pFont->internalFont, pMetricsOut); -} - -bool drgui_get_glyph_metrics(drgui_font* pFont, unsigned int utf32, drgui_glyph_metrics* pMetricsOut) -{ - if (pFont == NULL || pMetricsOut == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->paintingCallbacks.getGlyphMetrics == NULL) { - return false; - } - - return pFont->pContext->paintingCallbacks.getGlyphMetrics(pFont->internalFont, utf32, pMetricsOut); -} - -bool drgui_measure_string(drgui_font* pFont, const char* text, size_t textLengthInBytes, float* pWidthOut, float* pHeightOut) -{ - if (pFont == NULL) { - return false; - } - - if (text == NULL || textLengthInBytes == 0) - { - drgui_font_metrics metrics; - if (!drgui_get_font_metrics(pFont, &metrics)) { - return false; - } - - if (pWidthOut) { - *pWidthOut = 0; - } - if (pHeightOut) { - *pHeightOut = (float)metrics.lineHeight; - } - - return true; - } - - - - assert(pFont->pContext != NULL); - - if (pFont->pContext->paintingCallbacks.measureString == NULL) { - return false; - } - - return pFont->pContext->paintingCallbacks.measureString(pFont->internalFont, text, textLengthInBytes, pWidthOut, pHeightOut); -} - -bool drgui_get_text_cursor_position_from_point(drgui_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut) -{ - if (pFont == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->paintingCallbacks.getTextCursorPositionFromPoint) { - return pFont->pContext->paintingCallbacks.getTextCursorPositionFromPoint(pFont->internalFont, text, textSizeInBytes, maxWidth, inputPosX, pTextCursorPosXOut, pCharacterIndexOut); - } - - return false; -} - -bool drgui_get_text_cursor_position_from_char(drgui_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut) -{ - if (pFont == NULL) { - return false; - } - - assert(pFont->pContext != NULL); - - if (pFont->pContext->paintingCallbacks.getTextCursorPositionFromChar) { - return pFont->pContext->paintingCallbacks.getTextCursorPositionFromChar(pFont->internalFont, text, characterIndex, pTextCursorPosXOut); - } - - return false; -} - - - -drgui_image* drgui_create_image(drgui_context* pContext, unsigned int width, unsigned int height, drgui_image_format format, unsigned int stride, const void* pData) -{ - if (pContext == NULL) { - return NULL; - } - - if (pContext->paintingCallbacks.createImage == NULL) { - return NULL; - } - - - // If the stride is 0, assume tightly packed. - if (stride == 0) { - stride = width * 4; - } - - - drgui_resource internalImage = pContext->paintingCallbacks.createImage(pContext->pPaintingContext, width, height, format, stride, pData); - if (internalImage == NULL) { - return NULL; - } - - drgui_image* pImage = (drgui_image*)malloc(sizeof(*pImage)); - if (pImage == NULL) { - return NULL; - } - - pImage->pContext = pContext; - pImage->hResource = internalImage; - - - return pImage; -} - -void drgui_delete_image(drgui_image* pImage) -{ - if (pImage == NULL) { - return; - } - - assert(pImage->pContext != NULL); - - // Delete the internal font object. - if (pImage->pContext->paintingCallbacks.deleteImage) { - pImage->pContext->paintingCallbacks.deleteImage(pImage->hResource); - } - - // Free the font object last. - free(pImage); -} - -void drgui_get_image_size(drgui_image* pImage, unsigned int* pWidthOut, unsigned int* pHeightOut) -{ - if (pWidthOut) *pWidthOut = 0; - if (pHeightOut) *pHeightOut = 0; - - if (pImage == NULL) { - return; - } - - assert(pImage->pContext != NULL); - - if (pImage->pContext->paintingCallbacks.getImageSize == NULL) { - return; - } - - pImage->pContext->paintingCallbacks.getImageSize(pImage->hResource, pWidthOut, pHeightOut); -} - -drgui_image_format drgui_get_optimal_image_format(drgui_context* pContext) -{ - if (pContext == NULL || pContext->paintingCallbacks.getOptimalImageFormat == NULL) { - return drgui_image_format_rgba8; - } - - return pContext->paintingCallbacks.getOptimalImageFormat(pContext->pPaintingContext); -} - -void* drgui_map_image_data(drgui_image* pImage, unsigned int accessFlags) -{ - if (pImage == NULL) { - return NULL; - } - - if (pImage->pContext->paintingCallbacks.mapImageData == NULL || pImage->pContext->paintingCallbacks.unmapImageData == NULL) { - return NULL; - } - - return pImage->pContext->paintingCallbacks.mapImageData(pImage->hResource, accessFlags); -} - -void drgui_unmap_image_data(drgui_image* pImage) -{ - if (pImage == NULL) { - return; - } - - if (pImage->pContext->paintingCallbacks.unmapImageData == NULL) { - return; - } - - pImage->pContext->paintingCallbacks.unmapImageData(pImage->hResource); -} - - - -///////////////////////////////////////////////////////////////// -// -// HIGH-LEVEL API -// -///////////////////////////////////////////////////////////////// - -//// Hit Testing and Layout //// - -void drgui_on_size_fit_children_to_parent(drgui_element* pElement, float newWidth, float newHeight) -{ - for (drgui_element* pChild = pElement->pFirstChild; pChild != NULL; pChild = pChild->pNextSibling) { - drgui_set_size(pChild, newWidth, newHeight); - } -} - -bool drgui_pass_through_hit_test(drgui_element* pElement, float mousePosX, float mousePosY) -{ - (void)pElement; - (void)mousePosX; - (void)mousePosY; - - return false; -} - - - -//// Painting //// - -void drgui_draw_border(drgui_element* pElement, float borderWidth, drgui_color color, void* pUserData) -{ - drgui_draw_rect_outline(pElement, drgui_get_local_rect(pElement), color, borderWidth, pUserData); -} - - - -///////////////////////////////////////////////////////////////// -// -// UTILITY API -// -///////////////////////////////////////////////////////////////// - -drgui_color drgui_rgba(drgui_byte r, drgui_byte g, drgui_byte b, drgui_byte a) -{ - drgui_color color; - color.r = r; - color.g = g; - color.b = b; - color.a = a; - - return color; -} - -drgui_color drgui_rgb(drgui_byte r, drgui_byte g, drgui_byte b) -{ - drgui_color color; - color.r = r; - color.g = g; - color.b = b; - color.a = 255; - - return color; -} - -drgui_rect drgui_clamp_rect(drgui_rect rect, drgui_rect other) -{ - drgui_rect result; - result.left = (rect.left >= other.left) ? rect.left : other.left; - result.top = (rect.top >= other.top) ? rect.top : other.top; - result.right = (rect.right <= other.right) ? rect.right : other.right; - result.bottom = (rect.bottom <= other.bottom) ? rect.bottom : other.bottom; - - return result; -} - -bool drgui_clamp_rect_to_element(const drgui_element* pElement, drgui_rect* pRelativeRect) -{ - if (pElement == NULL || pRelativeRect == NULL) { - return false; - } - - - if (pRelativeRect->left < 0) { - pRelativeRect->left = 0; - } - if (pRelativeRect->top < 0) { - pRelativeRect->top = 0; - } - - if (pRelativeRect->right > pElement->width) { - pRelativeRect->right = pElement->width; - } - if (pRelativeRect->bottom > pElement->height) { - pRelativeRect->bottom = pElement->height; - } - - - return (pRelativeRect->right - pRelativeRect->left > 0) && (pRelativeRect->bottom - pRelativeRect->top > 0); -} - -drgui_rect drgui_make_rect_relative(const drgui_element* pElement, drgui_rect* pRect) -{ - if (pElement == NULL || pRect == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - pRect->left -= pElement->absolutePosX; - pRect->top -= pElement->absolutePosY; - pRect->right -= pElement->absolutePosX; - pRect->bottom -= pElement->absolutePosY; - - return *pRect; -} - -drgui_rect drgui_make_rect_absolute(const drgui_element * pElement, drgui_rect * pRect) -{ - if (pElement == NULL || pRect == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - pRect->left += pElement->absolutePosX; - pRect->top += pElement->absolutePosY; - pRect->right += pElement->absolutePosX; - pRect->bottom += pElement->absolutePosY; - - return *pRect; -} - -void drgui_make_point_relative(const drgui_element* pElement, float* positionX, float* positionY) -{ - if (pElement != NULL) - { - if (positionX != NULL) { - *positionX -= pElement->absolutePosX; - } - - if (positionY != NULL) { - *positionY -= pElement->absolutePosY; - } - } -} - -void drgui_make_point_absolute(const drgui_element* pElement, float* positionX, float* positionY) -{ - if (pElement != NULL) - { - if (positionX != NULL) { - *positionX += pElement->absolutePosX; - } - - if (positionY != NULL) { - *positionY += pElement->absolutePosY; - } - } -} - -drgui_rect drgui_make_rect(float left, float top, float right, float bottom) -{ - drgui_rect rect; - rect.left = left; - rect.top = top; - rect.right = right; - rect.bottom = bottom; - - return rect; -} - -drgui_rect drgui_make_inside_out_rect() -{ - drgui_rect rect; - rect.left = FLT_MAX; - rect.top = FLT_MAX; - rect.right = -FLT_MAX; - rect.bottom = -FLT_MAX; - - return rect; -} - -drgui_rect drgui_grow_rect(drgui_rect rect, float amount) -{ - drgui_rect result = rect; - result.left -= amount; - result.top -= amount; - result.right += amount; - result.bottom += amount; - - return result; -} - -drgui_rect drgui_scale_rect(drgui_rect rect, float scaleX, float scaleY) -{ - drgui_rect result = rect; - result.left *= scaleX; - result.top *= scaleY; - result.right *= scaleX; - result.bottom *= scaleY; - - return result; -} - -drgui_rect drgui_offset_rect(drgui_rect rect, float offsetX, float offsetY) -{ - return drgui_make_rect(rect.left + offsetX, rect.top + offsetY, rect.right + offsetX, rect.bottom + offsetY); -} - -drgui_rect drgui_rect_union(drgui_rect rect0, drgui_rect rect1) -{ - drgui_rect result; - result.left = (rect0.left < rect1.left) ? rect0.left : rect1.left; - result.top = (rect0.top < rect1.top) ? rect0.top : rect1.top; - result.right = (rect0.right > rect1.right) ? rect0.right : rect1.right; - result.bottom = (rect0.bottom > rect1.bottom) ? rect0.bottom : rect1.bottom; - - return result; -} - -bool drgui_rect_contains_point(drgui_rect rect, float posX, float posY) -{ - if (posX < rect.left || posY < rect.top) { - return false; - } - - if (posX >= rect.right || posY >= rect.bottom) { - return false; - } - - return true; -} - -bool drgui_rect_equal(drgui_rect rect0, drgui_rect rect1) -{ - return - rect0.left == rect1.left && - rect0.top == rect1.top && - rect0.right == rect1.right && - rect0.bottom == rect1.bottom; -} - -bool drgui_rect_has_volume(drgui_rect rect) -{ - return rect.right > rect.left && rect.bottom > rect.top; -} - - - - -///////////////////////////////////////////////////////////////// -// -// EASY_DRAW-SPECIFIC API -// -///////////////////////////////////////////////////////////////// -#ifndef DRGUI_NO_DR_2D - -void drgui_draw_begin_dr_2d(void* pPaintData); -void drgui_draw_end_dr_2d(void* pPaintData); -void drgui_set_clip_dr_2d(drgui_rect rect, void* pPaintData); -void drgui_get_clip_dr_2d(drgui_rect* pRectOut, void* pPaintData); -void drgui_draw_rect_dr_2d(drgui_rect rect, drgui_color color, void* pPaintData); -void drgui_draw_rect_outline_dr_2d(drgui_rect, drgui_color, float, void*); -void drgui_draw_rect_with_outline_dr_2d(drgui_rect, drgui_color, float, drgui_color, void*); -void drgui_draw_round_rect_dr_2d(drgui_rect, drgui_color, float, void*); -void drgui_draw_round_rect_outline_dr_2d(drgui_rect, drgui_color, float, float, void*); -void drgui_draw_round_rect_with_outline_dr_2d(drgui_rect, drgui_color, float, float, drgui_color, void*); -void drgui_draw_text_dr_2d(drgui_resource, const char*, int, float, float, drgui_color, drgui_color, void*); -void drgui_draw_image_dr_2d(drgui_resource image, drgui_draw_image_args* pArgs, void* pPaintData); - -drgui_resource drgui_create_font_dr_2d(void*, const char*, unsigned int, drgui_font_weight, drgui_font_slant, float, unsigned int flags); -void drgui_delete_font_dr_2d(drgui_resource); -unsigned int drgui_get_font_size_dr_2d(drgui_resource hFont); -bool drgui_get_font_metrics_dr_2d(drgui_resource, drgui_font_metrics*); -bool drgui_get_glyph_metrics_dr_2d(drgui_resource, unsigned int, drgui_glyph_metrics*); -bool drgui_measure_string_dr_2d(drgui_resource, const char*, size_t, float*, float*); -bool drgui_get_text_cursor_position_from_point_dr_2d(drgui_resource font, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut); -bool drgui_get_text_cursor_position_from_char_dr_2d(drgui_resource font, const char* text, size_t characterIndex, float* pTextCursorPosXOut); - -drgui_resource drgui_create_image_dr_2d(void* pPaintingContext, unsigned int width, unsigned int height, drgui_image_format format, unsigned int stride, const void* pImageData); -void drgui_delete_image_dr_2d(drgui_resource image); -void drgui_get_image_size_dr_2d(drgui_resource image, unsigned int* pWidthOut, unsigned int* pHeightOut); -drgui_image_format drgui_get_optimal_image_format_dr_2d(void* pPaintingContext); -void* drgui_map_image_data_dr_2d(drgui_resource image, unsigned int accessFlags); -void drgui_unmap_image_data_dr_2d(drgui_resource image); - -drgui_context* drgui_create_context_dr_2d(dr2d_context* pDrawingContext) -{ - drgui_context* pContext = drgui_create_context(); - if (pContext != NULL) { - drgui_register_dr_2d_callbacks(pContext, pDrawingContext); - } - - return pContext; -} - -void drgui_register_dr_2d_callbacks(drgui_context* pContext, dr2d_context* pDrawingContext) -{ - drgui_painting_callbacks callbacks; - callbacks.drawBegin = drgui_draw_begin_dr_2d; - callbacks.drawEnd = drgui_draw_end_dr_2d; - callbacks.setClip = drgui_set_clip_dr_2d; - callbacks.getClip = drgui_get_clip_dr_2d; - callbacks.drawRect = drgui_draw_rect_dr_2d; - callbacks.drawRectOutline = drgui_draw_rect_outline_dr_2d; - callbacks.drawRectWithOutline = drgui_draw_rect_with_outline_dr_2d; - callbacks.drawRoundRect = drgui_draw_round_rect_dr_2d; - callbacks.drawRoundRectOutline = drgui_draw_round_rect_outline_dr_2d; - callbacks.drawRoundRectWithOutline = drgui_draw_round_rect_with_outline_dr_2d; - callbacks.drawText = drgui_draw_text_dr_2d; - callbacks.drawImage = drgui_draw_image_dr_2d; - - callbacks.createFont = drgui_create_font_dr_2d; - callbacks.deleteFont = drgui_delete_font_dr_2d; - callbacks.getFontSize = drgui_get_font_size_dr_2d; - callbacks.getFontMetrics = drgui_get_font_metrics_dr_2d; - callbacks.getGlyphMetrics = drgui_get_glyph_metrics_dr_2d; - callbacks.measureString = drgui_measure_string_dr_2d; - - callbacks.createImage = drgui_create_image_dr_2d; - callbacks.deleteImage = drgui_delete_image_dr_2d; - callbacks.getImageSize = drgui_get_image_size_dr_2d; - callbacks.getOptimalImageFormat = drgui_get_optimal_image_format_dr_2d; - callbacks.mapImageData = drgui_map_image_data_dr_2d; - callbacks.unmapImageData = drgui_unmap_image_data_dr_2d; - - callbacks.getTextCursorPositionFromPoint = drgui_get_text_cursor_position_from_point_dr_2d; - callbacks.getTextCursorPositionFromChar = drgui_get_text_cursor_position_from_char_dr_2d; - - drgui_register_painting_callbacks(pContext, pDrawingContext, callbacks); -} - - -void drgui_draw_begin_dr_2d(void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_begin_draw(pSurface); -} - -void drgui_draw_end_dr_2d(void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_end_draw(pSurface); -} - -void drgui_set_clip_dr_2d(drgui_rect rect, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_set_clip(pSurface, rect.left, rect.top, rect.right, rect.bottom); -} - -void drgui_get_clip_dr_2d(drgui_rect* pRectOut, void* pPaintData) -{ - assert(pRectOut != NULL); - - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_get_clip(pSurface, &pRectOut->left, &pRectOut->top, &pRectOut->right, &pRectOut->bottom); -} - -void drgui_draw_rect_dr_2d(drgui_rect rect, drgui_color color, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_rect(pSurface, rect.left, rect.top, rect.right, rect.bottom, dr2d_rgba(color.r, color.g, color.b, color.a)); -} - -void drgui_draw_rect_outline_dr_2d(drgui_rect rect, drgui_color color, float outlineWidth, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_rect_outline(pSurface, rect.left, rect.top, rect.right, rect.bottom, dr2d_rgba(color.r, color.g, color.b, color.a), outlineWidth); -} - -void drgui_draw_rect_with_outline_dr_2d(drgui_rect rect, drgui_color color, float outlineWidth, drgui_color outlineColor, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_rect_with_outline(pSurface, rect.left, rect.top, rect.right, rect.bottom, dr2d_rgba(color.r, color.g, color.b, color.a), outlineWidth, dr2d_rgba(outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a)); -} - -void drgui_draw_round_rect_dr_2d(drgui_rect rect, drgui_color color, float radius, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_round_rect(pSurface, rect.left, rect.top, rect.right, rect.bottom, dr2d_rgba(color.r, color.g, color.b, color.a), radius); -} - -void drgui_draw_round_rect_outline_dr_2d(drgui_rect rect, drgui_color color, float radius, float outlineWidth, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_round_rect_outline(pSurface, rect.left, rect.top, rect.right, rect.bottom, dr2d_rgba(color.r, color.g, color.b, color.a), radius, outlineWidth); -} - -void drgui_draw_round_rect_with_outline_dr_2d(drgui_rect rect, drgui_color color, float radius, float outlineWidth, drgui_color outlineColor, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_round_rect_with_outline(pSurface, rect.left, rect.top, rect.right, rect.bottom, dr2d_rgba(color.r, color.g, color.b, color.a), radius, outlineWidth, dr2d_rgba(outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a)); -} - -void drgui_draw_text_dr_2d(drgui_resource font, const char* text, int textSizeInBytes, float posX, float posY, drgui_color color, drgui_color backgroundColor, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_text(pSurface, (dr2d_font*)font, text, textSizeInBytes, posX, posY, dr2d_rgba(color.r, color.g, color.b, color.a), dr2d_rgba(backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a)); -} - -void drgui_draw_image_dr_2d(drgui_resource image, drgui_draw_image_args* pArgs, void* pPaintData) -{ - dr2d_surface* pSurface = (dr2d_surface*)pPaintData; - assert(pSurface != NULL); - - dr2d_draw_image_args args; - args.dstX = pArgs->dstX; - args.dstY = pArgs->dstY; - args.dstWidth = pArgs->dstWidth; - args.dstHeight = pArgs->dstHeight; - args.srcX = pArgs->srcX; - args.srcY = pArgs->srcY; - args.srcWidth = pArgs->srcWidth; - args.srcHeight = pArgs->srcHeight; - args.foregroundTint = dr2d_rgba(pArgs->foregroundTint.r, pArgs->foregroundTint.g, pArgs->foregroundTint.b, pArgs->foregroundTint.a); - args.backgroundColor = dr2d_rgba(pArgs->backgroundColor.r, pArgs->backgroundColor.g, pArgs->backgroundColor.b, pArgs->backgroundColor.a); - args.options = pArgs->options; - dr2d_draw_image(pSurface, (dr2d_image*)image, &args); -} - - -drgui_resource drgui_create_font_dr_2d(void* pPaintingContext, const char* family, unsigned int size, drgui_font_weight weight, drgui_font_slant slant, float rotation, unsigned int flags) -{ - return dr2d_create_font((dr2d_context*)pPaintingContext, family, size, (dr2d_font_weight)weight, (dr2d_font_slant)slant, rotation, flags); -} - -void drgui_delete_font_dr_2d(drgui_resource font) -{ - dr2d_delete_font((dr2d_font*)font); -} - -unsigned int drgui_get_font_size_dr_2d(drgui_resource font) -{ - return dr2d_get_font_size((dr2d_font*)font); -} - -bool drgui_get_font_metrics_dr_2d(drgui_resource font, drgui_font_metrics* pMetricsOut) -{ - assert(pMetricsOut != NULL); - - dr2d_font_metrics metrics; - if (!dr2d_get_font_metrics((dr2d_font*)font, &metrics)) { - return false; - } - - pMetricsOut->ascent = metrics.ascent; - pMetricsOut->descent = metrics.descent; - pMetricsOut->lineHeight = metrics.lineHeight; - pMetricsOut->spaceWidth = metrics.spaceWidth; - - return true; -} - -bool drgui_get_glyph_metrics_dr_2d(drgui_resource font, unsigned int utf32, drgui_glyph_metrics* pMetricsOut) -{ - assert(pMetricsOut != NULL); - - dr2d_glyph_metrics metrics; - if (!dr2d_get_glyph_metrics((dr2d_font*)font, utf32, &metrics)) { - return false; - } - - pMetricsOut->width = metrics.width; - pMetricsOut->height = metrics.height; - pMetricsOut->originX = metrics.originX; - pMetricsOut->originY = metrics.originY; - pMetricsOut->advanceX = metrics.advanceX; - pMetricsOut->advanceY = metrics.advanceY; - - return true; -} - -bool drgui_measure_string_dr_2d(drgui_resource font, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut) -{ - return dr2d_measure_string((dr2d_font*)font, text, textSizeInBytes, pWidthOut, pHeightOut); -} - -bool drgui_get_text_cursor_position_from_point_dr_2d(drgui_resource font, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut) -{ - return dr2d_get_text_cursor_position_from_point((dr2d_font*)font, text, textSizeInBytes, maxWidth, inputPosX, pTextCursorPosXOut, pCharacterIndexOut); -} - -bool drgui_get_text_cursor_position_from_char_dr_2d(drgui_resource font, const char* text, size_t characterIndex, float* pTextCursorPosXOut) -{ - return dr2d_get_text_cursor_position_from_char((dr2d_font*)font, text, characterIndex, pTextCursorPosXOut); -} - - -drgui_resource drgui_create_image_dr_2d(void* pPaintingContext, unsigned int width, unsigned int height, drgui_image_format format, unsigned int stride, const void* pImageData) -{ - dr2d_image_format dr2dFormat; - switch (format) - { - case drgui_image_format_bgra8: dr2dFormat = dr2d_image_format_bgra8; break; - case drgui_image_format_argb8: dr2dFormat = dr2d_image_format_argb8; break; - default: dr2dFormat = dr2d_image_format_rgba8; - } - - return dr2d_create_image((dr2d_context*)pPaintingContext, width, height, dr2dFormat, stride, pImageData); -} - -void drgui_delete_image_dr_2d(drgui_resource image) -{ - dr2d_delete_image((dr2d_image*)image); -} - -void drgui_get_image_size_dr_2d(drgui_resource image, unsigned int* pWidthOut, unsigned int* pHeightOut) -{ - dr2d_get_image_size((dr2d_image*)image, pWidthOut, pHeightOut); -} - -drgui_image_format drgui_get_optimal_image_format_dr_2d(void* pPaintingContext) -{ - return (drgui_image_format)dr2d_get_optimal_image_format((dr2d_context*)pPaintingContext); -} - -void* drgui_map_image_data_dr_2d(drgui_resource image, unsigned int accessFlags) -{ - return dr2d_map_image_data((dr2d_image*)image, accessFlags); -} - -void drgui_unmap_image_data_dr_2d(drgui_resource image) -{ - dr2d_unmap_image_data((dr2d_image*)image); -} - -#endif //DRGUI_NO_DR_2D -#endif //DR_GUI_IMPLEMENTATION - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Text Engine -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -#ifndef DRGUI_NO_TEXT_EDITING -// QUICK NOTES -// -// - Text engines are used to make it easier to manage the layout of a block of text. -// - Text engines support basic editing which requires inbound events to be posted from the higher level application. -// - Text engines are not GUI elements. They are lower level objects that are used by higher level GUI elements. -// - Text engines normalize line endings to \n format. Keep this in mind when retrieving the text of a layout. -// - Text engine use the notion of a container which is used for determining which text runs are visible. - -#ifndef drgui_text_engine_h -#define drgui_text_engine_h - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct drgui_text_engine drgui_text_engine; - -typedef enum -{ - drgui_text_engine_alignment_left, - drgui_text_engine_alignment_top, - drgui_text_engine_alignment_center, - drgui_text_engine_alignment_right, - drgui_text_engine_alignment_bottom, -} drgui_text_engine_alignment; - -typedef struct -{ - /// A pointer to the start of the string. This is NOT null terminated. - const char* text; - - /// The length of the string, in bytes. - size_t textLength; - - - /// The font. - drgui_font* pFont; - - /// The foreground color of the text. - drgui_color textColor; - - /// The backgorund color of the text. - drgui_color backgroundColor; - - - /// The position to draw the text on the x axis. - float posX; - - /// The position to draw the text on the y axis. - float posY; - - /// The width of the run. - float width; - - /// The height of the run. - float height; - - - // PROPERTIES BELOW ARE FOR INTERNAL USE ONLY - - /// Index of the line the run is placed on. For runs that are new line characters, this will represent the number of lines that came before it. For - /// example, if this run represents the new-line character for the first line, this will be 0 and so on. - size_t iLine; - - /// Index in the main text string of the first character of the run. - size_t iChar; - - /// Index in the main text string of the character just past the last character in the run. - size_t iCharEnd; - -} drgui_text_run; - -typedef void (* drgui_text_engine_on_paint_text_proc) (drgui_text_engine* pTL, drgui_text_run* pRun, drgui_element* pElement, void* pPaintData); -typedef void (* drgui_text_engine_on_paint_rect_proc) (drgui_text_engine* pTL, drgui_rect rect, drgui_color color, drgui_element* pElement, void* pPaintData); -typedef void (* drgui_text_engine_on_cursor_move_proc) (drgui_text_engine* pTL); -typedef void (* drgui_text_engine_on_dirty_proc) (drgui_text_engine* pTL, drgui_rect rect); -typedef void (* drgui_text_engine_on_text_changed_proc) (drgui_text_engine* pTL); -typedef void (* drgui_text_engine_on_undo_point_changed_proc)(drgui_text_engine* pTL, unsigned int iUndoPoint); - - -/// Creates a new text engine object. -drgui_text_engine* drgui_create_text_engine(drgui_context* pContext, size_t extraDataSize, void* pExtraData); - -/// Deletes the given text engine. -void drgui_delete_text_engine(drgui_text_engine* pTL); - - -/// Retrieves the size of the extra data associated with the given text engine. -size_t drgui_text_engine_get_extra_data_size(drgui_text_engine* pTL); - -/// Retrieves a pointer to the extra data associated with the given text engine. -void* drgui_text_engine_get_extra_data(drgui_text_engine* pTL); - - -/// Sets the given text engine's text. -void drgui_text_engine_set_text(drgui_text_engine* pTL, const char* text); - -/// Retrieves the given text engine's text. -/// -/// @return The length of the string, not including the null terminator. -/// -/// @remarks -/// Call this function with set to NULL to retieve the required size of . -size_t drgui_text_engine_get_text(drgui_text_engine* pTL, char* textOut, size_t textOutSize); - - -/// Sets the function to call when a region of the text engine needs to be redrawn. -void drgui_text_engine_set_on_dirty(drgui_text_engine* pTL, drgui_text_engine_on_dirty_proc proc); - -/// Sets the function to call when the content of the given text engine has changed. -void drgui_text_engine_set_on_text_changed(drgui_text_engine* pTL, drgui_text_engine_on_text_changed_proc proc); - -/// Sets the function to call when the content of the given text engine's current undo point has moved. -void drgui_text_engine_set_on_undo_point_changed(drgui_text_engine* pTL, drgui_text_engine_on_undo_point_changed_proc proc); - - -/// Sets the size of the container. -void drgui_text_engine_set_container_size(drgui_text_engine* pTL, float containerWidth, float containerHeight); - -/// Retrieves the size of the container. -void drgui_text_engine_get_container_size(drgui_text_engine* pTL, float* pContainerWidthOut, float* pContainerHeightOut); - -/// Retrieves the width of the container. -float drgui_text_engine_get_container_width(drgui_text_engine* pTL); - -/// Retrieves the height of the container. -float drgui_text_engine_get_container_height(drgui_text_engine* pTL); - - -/// Sets the inner offset of the given text engine. -void drgui_text_engine_set_inner_offset(drgui_text_engine* pTL, float innerOffsetX, float innerOffsetY); - -/// Sets the inner offset of the given text engine on the x axis. -void drgui_text_engine_set_inner_offset_x(drgui_text_engine* pTL, float innerOffsetX); - -/// Sets the inner offset of the given text engine on the y axis. -void drgui_text_engine_set_inner_offset_y(drgui_text_engine* pTL, float innerOffsetY); - -/// Retrieves the inner offset of the given text engine. -void drgui_text_engine_get_inner_offset(drgui_text_engine* pTL, float* pInnerOffsetX, float* pInnerOffsetY); - -/// Retrieves the inner offset of the given text engine on the x axis. -float drgui_text_engine_get_inner_offset_x(drgui_text_engine* pTL); - -/// Retrieves the inner offset of the given text engine on the x axis. -float drgui_text_engine_get_inner_offset_y(drgui_text_engine* pTL); - - -/// Sets the default font to use for text runs. -void drgui_text_engine_set_default_font(drgui_text_engine* pTL, drgui_font* pFont); - -/// Retrieves the default font to use for text runs. -drgui_font* drgui_text_engine_get_default_font(drgui_text_engine* pTL); - -/// Sets the default text color of the given text engine. -void drgui_text_engine_set_default_text_color(drgui_text_engine* pTL, drgui_color color); - -/// Retrieves the default text color of the given text engine. -drgui_color drgui_text_engine_get_default_text_color(drgui_text_engine* pTL); - -/// Sets the default background color of the given text engine. -void drgui_text_engine_set_default_bg_color(drgui_text_engine* pTL, drgui_color color); - -/// Retrieves the default background color of the given text engine. -drgui_color drgui_text_engine_get_default_bg_color(drgui_text_engine* pTL); - -/// Sets the background color of selected text. -void drgui_text_engine_set_selection_bg_color(drgui_text_engine* pTL, drgui_color color); - -/// Retrieves the background color of selected text. -drgui_color drgui_text_engine_get_selection_bg_color(drgui_text_engine* pTL); - -/// Sets the background color of the line the cursor is sitting on. -void drgui_text_engine_set_active_line_bg_color(drgui_text_engine* pTL, drgui_color color); - -/// Retrieves the background color of the line the cursor is sitting on. -drgui_color drgui_text_engine_get_active_line_bg_color(drgui_text_engine* pTL); - - -/// Sets the size of a tab in spaces. -void drgui_text_engine_set_tab_size(drgui_text_engine* pTL, unsigned int sizeInSpaces); - -/// Retrieves the size of a tab in spaces. -unsigned int drgui_text_engine_get_tab_size(drgui_text_engine* pTL); - - -/// Sets the horizontal alignment of the given text engine. -void drgui_text_engine_set_horizontal_align(drgui_text_engine* pTL, drgui_text_engine_alignment alignment); - -/// Retrieves the horizontal aligment of the given text engine. -drgui_text_engine_alignment drgui_text_engine_get_horizontal_align(drgui_text_engine* pTL); - -/// Sets the vertical alignment of the given text engine. -void drgui_text_engine_set_vertical_align(drgui_text_engine* pTL, drgui_text_engine_alignment alignment); - -/// Retrieves the vertical aligment of the given text engine. -drgui_text_engine_alignment drgui_text_engine_get_vertical_align(drgui_text_engine* pTL); - - -/// Retrieves the rectangle of the text relative to the bounds, taking alignment into account. -drgui_rect drgui_text_engine_get_text_rect_relative_to_bounds(drgui_text_engine* pTL); - - -/// Sets the width of the text cursor. -void drgui_text_engine_set_cursor_width(drgui_text_engine* pTL, float cursorWidth); - -/// Retrieves the width of the text cursor. -float drgui_text_engine_get_cursor_width(drgui_text_engine* pTL); - -/// Sets the color of the text cursor. -void drgui_text_engine_set_cursor_color(drgui_text_engine* pTL, drgui_color cursorColor); - -/// Retrieves the color of the text cursor. -drgui_color drgui_text_engine_get_cursor_color(drgui_text_engine* pTL); - -/// Sets the blink rate of the cursor in milliseconds. -void drgui_text_engine_set_cursor_blink_rate(drgui_text_engine* pTL, unsigned int blinkRateInMilliseconds); - -/// Retrieves the blink rate of the cursor in milliseconds. -unsigned int drgui_text_engine_get_cursor_blink_rate(drgui_text_engine* pTL); - -/// Shows the cursor. -void drgui_text_engine_show_cursor(drgui_text_engine* pTL); - -/// Hides the cursor. -void drgui_text_engine_hide_cursor(drgui_text_engine* pTL); - -/// Determines whether or not the cursor is visible. -bool drgui_text_engine_is_showing_cursor(drgui_text_engine* pTL); - -/// Retrieves the position of the cursor, relative to the container. -void drgui_text_engine_get_cursor_position(drgui_text_engine* pTL, float* pPosXOut, float* pPosYOut); - -/// Retrieves the rectangle of the cursor, relative to the container. -drgui_rect drgui_text_engine_get_cursor_rect(drgui_text_engine* pTL); - -/// Retrieves the index of the line the cursor is currently sitting on. -size_t drgui_text_engine_get_cursor_line(drgui_text_engine* pTL); - -/// Retrieves the index of the column the cursor is currently sitting on. -size_t drgui_text_engine_get_cursor_column(drgui_text_engine* pTL); - -/// Retrieves the index of the character the cursor is currently sitting on. -size_t drgui_text_engine_get_cursor_character(drgui_text_engine* pTL); - -/// Moves the cursor to the closest character based on the given input position. -void drgui_text_engine_move_cursor_to_point(drgui_text_engine* pTL, float posX, float posY); - -/// Moves the cursor of the given text engine to the left by one character. -bool drgui_text_engine_move_cursor_left(drgui_text_engine* pTL); - -/// Moves the cursor of the given text engine to the right by one character. -bool drgui_text_engine_move_cursor_right(drgui_text_engine* pTL); - -/// Moves the cursor of the given text engine up one line. -bool drgui_text_engine_move_cursor_up(drgui_text_engine* pTL); - -/// Moves the cursor of the given text engine down one line. -bool drgui_text_engine_move_cursor_down(drgui_text_engine* pTL); - -/// Moves the cursor up or down the given number of lines. -bool drgui_text_engine_move_cursor_y(drgui_text_engine* pTL, int amount); - -/// Moves the cursor of the given text engine to the end of the line. -bool drgui_text_engine_move_cursor_to_end_of_line(drgui_text_engine* pTL); - -/// Moves the cursor of the given text engine to the start of the line. -bool drgui_text_engine_move_cursor_to_start_of_line(drgui_text_engine* pTL); - -/// Moves the cursor of the given text engine to the end of the line at the given index. -bool drgui_text_engine_move_cursor_to_end_of_line_by_index(drgui_text_engine* pTL, size_t iLine); - -/// Moves the cursor of the given text engine to the start of the line at the given index. -bool drgui_text_engine_move_cursor_to_start_of_line_by_index(drgui_text_engine* pTL, size_t iLine); - -/// Moves the cursor of the given text engine to the end of the text. -bool drgui_text_engine_move_cursor_to_end_of_text(drgui_text_engine* pTL); - -/// Moves the cursor of the given text engine to the end of the text. -bool drgui_text_engine_move_cursor_to_start_of_text(drgui_text_engine* pTL); - -/// Moves the cursor to the start of the selected text. -void drgui_text_engine_move_cursor_to_start_of_selection(drgui_text_engine* pTL); - -/// Moves the cursor to the end of the selected text. -void drgui_text_engine_move_cursor_to_end_of_selection(drgui_text_engine* pTL); - -/// Moves the cursor to the given character index. -void drgui_text_engine_move_cursor_to_character(drgui_text_engine* pTL, size_t characterIndex); - -/// Determines whether or not the cursor is sitting at the start of the selection. -bool drgui_text_engine_is_cursor_at_start_of_selection(drgui_text_engine* pTL); - -/// Determines whether or not the cursor is sitting at the end fo the selection. -bool drgui_text_engine_is_cursor_at_end_of_selection(drgui_text_engine* pTL); - -/// Swaps the position of the cursor based on the current selection. -void drgui_text_engine_swap_selection_markers(drgui_text_engine* pTL); - -/// Sets the function to call when the cursor in the given text engine is mvoed. -void drgui_text_engine_set_on_cursor_move(drgui_text_engine* pTL, drgui_text_engine_on_cursor_move_proc proc); - -/// Refreshes the cursor and selection marker positions. -void drgui_text_engine_refresh_markers(drgui_text_engine* pTL); - - -/// Inserts a character into the given text engine. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_insert_character(drgui_text_engine* pTL, unsigned int character, size_t insertIndex); - -/// Inserts the given string at the given character index. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_insert_text(drgui_text_engine* pTL, const char* text, size_t insertIndex); - -/// Deletes a range of text in the given text engine. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_delete_text_range(drgui_text_engine* pTL, size_t iFirstCh, size_t iLastChPlus1); - -/// Inserts a character at the position of the cursor. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_insert_character_at_cursor(drgui_text_engine* pTL, unsigned int character); - -/// Inserts a character at the position of the cursor. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_insert_text_at_cursor(drgui_text_engine* pTL, const char* text); - -/// Deletes the character to the left of the cursor. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_delete_character_to_left_of_cursor(drgui_text_engine* pTL); - -/// Deletes the character to the right of the cursor. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_delete_character_to_right_of_cursor(drgui_text_engine* pTL); - -/// Deletes the currently selected text. -/// -/// @return True if the text within the text engine has changed. -bool drgui_text_engine_delete_selected_text(drgui_text_engine* pTL); - - -/// Enter's into selection mode. -/// -/// @remarks -/// An application will typically enter selection mode when the Shift key is pressed, and then leave when the key is released. -/// @par -/// This will increment an internal counter, which is decremented with a corresponding call to drgui_text_engine_leave_selection_mode(). -/// Selection mode will be enabled so long as this counter is greater than 0. Thus, you must ensure you cleanly leave selection -/// mode. -void drgui_text_engine_enter_selection_mode(drgui_text_engine* pTL); - -/// Leaves selection mode. -/// -/// @remarks -/// This decrements the internal counter. Selection mode will not be disabled while this reference counter is greater than 0. Always -/// ensure a leave is correctly matched with an enter. -void drgui_text_engine_leave_selection_mode(drgui_text_engine* pTL); - -/// Determines whether or not the given text engine is in selection mode. -bool drgui_text_engine_is_in_selection_mode(drgui_text_engine* pTL); - -/// Determines whether or not anything is selected in the given text engine. -bool drgui_text_engine_is_anything_selected(drgui_text_engine* pTL); - -/// Deselects everything in the given text engine. -void drgui_text_engine_deselect_all(drgui_text_engine* pTL); - -/// Selects everything in the given text engine. -void drgui_text_engine_select_all(drgui_text_engine* pTL); - -/// Selects the given range of text. -void drgui_text_engine_select(drgui_text_engine* pTL, size_t firstCharacter, size_t lastCharacter); - -/// Retrieves a copy of the selected text. -/// -/// @remarks -/// This returns the length of the selected text. Call this once with set to NULL to calculate the required size of the -/// buffer. -/// @par -/// If the output buffer is not larger enough, the string will be truncated. -size_t drgui_text_engine_get_selected_text(drgui_text_engine* pTL, char* textOut, size_t textOutLength); - -/// Retrieves the index of the first line of the current selection. -size_t drgui_text_engine_get_selection_first_line(drgui_text_engine* pTL); - -/// Retrieves the index of the last line of the current selection. -size_t drgui_text_engine_get_selection_last_line(drgui_text_engine* pTL); - -/// Moves the selection anchor to the end of the given line. -void drgui_text_engine_move_selection_anchor_to_end_of_line(drgui_text_engine* pTL, size_t iLine); - -/// Moves the selection anchor to the start of the given line. -void drgui_text_engine_move_selection_anchor_to_start_of_line(drgui_text_engine* pTL, size_t iLine); - -/// Retrieves the line the selection anchor is sitting on. -size_t drgui_text_engine_get_selection_anchor_line(drgui_text_engine* pTL); - - -/// Prepares the next undo/redo point. -/// -/// @remarks -/// This captures the state that will be applied when the undo/redo point is undone. -bool drgui_text_engine_prepare_undo_point(drgui_text_engine* pTL); - -/// Creates a snapshot of the current state of the text engine and pushes it to the top of the undo/redo stack. -bool drgui_text_engine_commit_undo_point(drgui_text_engine* pTL); - -/// Performs an undo operation. -bool drgui_text_engine_undo(drgui_text_engine* pTL); - -/// Performs a redo operation. -bool drgui_text_engine_redo(drgui_text_engine* pTL); - -/// Retrieves the number of undo points remaining in the stack. -unsigned int drgui_text_engine_get_undo_points_remaining_count(drgui_text_engine* pTL); - -/// Retrieves the number of redo points remaining in the stack. -unsigned int drgui_text_engine_get_redo_points_remaining_count(drgui_text_engine* pTL); - -/// Clears the undo stack. -void drgui_text_engine_clear_undo_stack(drgui_text_engine* pTL); - - - -/// Retrieves the number of lines in the given text engine. -size_t drgui_text_engine_get_line_count(drgui_text_engine* pTL); - -/// Retrieves the number of lines that can fit on the visible portion of the layout, starting from the given line. -/// -/// @remarks -/// Use this for controlling the page size for scrollbars. -size_t drgui_text_engine_get_visible_line_count_starting_at(drgui_text_engine* pTL, size_t iFirstLine); - -/// Retrieves the position of the line at the given index on the y axis. -/// -/// @remarks -/// Use this for calculating the inner offset for scrolling on the y axis. -float drgui_text_engine_get_line_pos_y(drgui_text_engine* pTL, size_t iLine); - -/// Finds the line under the given point on the y axis relative to the container. -size_t drgui_text_engine_get_line_at_pos_y(drgui_text_engine* pTL, float posY); - -/// Retrieves the index of the first character of the line at the given index. -size_t drgui_text_engine_get_line_first_character(drgui_text_engine* pTL, size_t iLine); - -/// Retrieves the index of the last character of the line at the given index. -size_t drgui_text_engine_get_line_last_character(drgui_text_engine* pTL, size_t iLine); - -/// Retrieves teh index of the first and last character of the line at the given index. -void drgui_text_engine_get_line_character_range(drgui_text_engine* pTL, size_t iLine, size_t* pCharStartOut, size_t* pCharEndOut); - - -/// Sets the function to call when a run of text needs to be painted for the given text engine. -void drgui_text_engine_set_on_paint_text(drgui_text_engine* pTL, drgui_text_engine_on_paint_text_proc proc); - -/// Sets the function to call when a quad needs to the be painted for the given text engine. -void drgui_text_engine_set_on_paint_rect(drgui_text_engine* pTL, drgui_text_engine_on_paint_rect_proc proc); - -/// Paints the given text engine by calling the appropriate painting callbacks. -/// -/// @remarks -/// Typically a text engine will be painted to a GUI element. A pointer to an element can be passed to this function -/// which will be passed to the callback functions. This is purely for convenience and nothing is actually drawn to -/// the element outside of the callback functions. -void drgui_text_engine_paint(drgui_text_engine* pTL, drgui_rect rect, drgui_element* pElement, void* pPaintData); - - -/// Steps the given text engine by the given number of milliseconds. -/// -/// @remarks -/// This will trigger the on_dirty callback when the cursor switches it's blink states. -void drgui_text_engine_step(drgui_text_engine* pTL, unsigned int milliseconds); - - -/// Calls the given painting callbacks for the line numbers of the given text engine. -void drgui_text_engine_paint_line_numbers(drgui_text_engine* pTL, float lineNumbersWidth, float lineNumbersHeight, drgui_color textColor, drgui_color backgroundColor, drgui_text_engine_on_paint_text_proc onPaintText, drgui_text_engine_on_paint_rect_proc onPaintRect, drgui_element* pElement, void* pPaintData); - - -/// Finds the given string starting from the cursor and then looping back. -bool drgui_text_engine_find_next(drgui_text_engine* pTL, const char* text, size_t* pSelectionStartOut, size_t* pSelectionEndOut); - -/// Finds the given string starting from the cursor, but does not loop back. -bool drgui_text_engine_find_next_no_loop(drgui_text_engine* pTL, const char* text, size_t* pSelectionStartOut, size_t* pSelectionEndOut); - -#ifdef __cplusplus -} -#endif -#endif //drgui_text_engine_h - - -#ifdef DR_GUI_IMPLEMENTATION -typedef struct -{ - /// The index of the run within the line the marker is positioned on. - size_t iRun; - - /// The index of the character within the run the marker is positioned to the left of. - size_t iChar; - - /// The position on the x axis, relative to the x position of the run. - float relativePosX; - - /// The absolute position on the x axis to place the marker when moving up and down lines. Note that this is not relative - /// to the run, but rather the line. This will be updated when the marker is moved left and right. - float absoluteSickyPosX; - -} drgui_text_marker; - -/// Keeps track of the current state of the text engine. Used for calculating the difference between two states for undo/redo. -typedef struct -{ - /// The text. Can be null in some cases where it isn't used. - char* text; - - /// The index of the character the cursor is positioned at. - size_t cursorPos; - - /// The index of the character the selection anchor is positioned at. - size_t selectionAnchorPos; - - /// Whether or not anything is selected. - bool isAnythingSelected; - -} drgui_text_engine_state; - -typedef struct -{ - /// The position in the main string where the change is located. The length of the relevant string is used to determines how - /// large of a chunk of text needs to be replaced. - size_t diffPos; - - /// The string that was replaced. On undo, this will be inserted into the text engine. Can be empty, in which case this state - /// object was created in response to an insert operation. - char* oldText; - - /// The string that replaces the old text. On redo, this will be inserted into the text engine. This can be empty, in which case - /// this state object was created in response to a delete operation. - char* newText; - - /// The state of the text engine at the time the undo point was prepared, not including the text. The attribute - /// of this object is always null. - drgui_text_engine_state oldState; - - /// The state of the text engine at the time the undo point was committed, not including the text. The attribute - /// of this object is always null. - drgui_text_engine_state newState; - -} drgui_text_engine_undo_state; - -struct drgui_text_engine -{ - /// The main text of the layout. - char* text; - - /// The length of the text. - size_t textLength; - - - /// The function to call when the text engine needs to be redrawn. - drgui_text_engine_on_dirty_proc onDirty; - - /// The function to call when the content of the text engine changes. - drgui_text_engine_on_text_changed_proc onTextChanged; - - /// The function to call when the current undo point has changed. - drgui_text_engine_on_undo_point_changed_proc onUndoPointChanged; - - - /// The width of the container. - float containerWidth; - - /// The height of the container. - float containerHeight; - - /// The inner offset of the container. - float innerOffsetX; - - /// The inner offset of the container. - float innerOffsetY; - - - /// The default font. - drgui_font* pDefaultFont; - - /// The default text color. - drgui_color defaultTextColor; - - /// The default background color. - drgui_color defaultBackgroundColor; - - /// The background color to use for selected text. - drgui_color selectionBackgroundColor; - - /// The background color to use for the line the cursor is currently sitting on. - drgui_color lineBackgroundColor; - - /// The size of a tab in spaces. - unsigned int tabSizeInSpaces; - - /// The horizontal alignment. - drgui_text_engine_alignment horzAlign; - - /// The vertical alignment. - drgui_text_engine_alignment vertAlign; - - /// The width of the text cursor. - float cursorWidth; - - /// The color of the text cursor. - drgui_color cursorColor; - - /// The blink rate in milliseconds of the cursor. - unsigned int cursorBlinkRate; - - /// The amount of time in milliseconds to toggle the cursor's blink state. - unsigned int timeToNextCursorBlink; - - /// Whether or not the cursor is showing based on it's blinking state. - bool isCursorBlinkOn; - - /// Whether or not the cursor is being shown. False by default. - bool isShowingCursor; - - - /// The total width of the text. - float textBoundsWidth; - - /// The total height of the text. - float textBoundsHeight; - - - /// The cursor. - drgui_text_marker cursor; - - /// The selection anchor. - drgui_text_marker selectionAnchor; - - - /// The selection mode counter. When this is greater than 0 we are in selection mode, otherwise we are not. This - /// is incremented by enter_selection_mode() and decremented by leave_selection_mode(). - unsigned int selectionModeCounter; - - /// Whether or not anything is selected. - bool isAnythingSelected; - - - /// The function to call when a text run needs to be painted. - drgui_text_engine_on_paint_text_proc onPaintText; - - /// The function to call when a rectangle needs to be painted. - drgui_text_engine_on_paint_rect_proc onPaintRect; - - /// The function to call when the cursor moves. - drgui_text_engine_on_cursor_move_proc onCursorMove; - - - /// The prepared undo/redo state. This will be filled with some state by PrepareUndoRedoPoint() and again with CreateUndoRedoPoint(). - drgui_text_engine_state preparedState; - - /// The undo/redo stack. - drgui_text_engine_undo_state* pUndoStack; - - /// The number of items in the undo/redo stack. - unsigned int undoStackCount; - - /// The index of the undo/redo state item we are currently sitting on. - unsigned int iUndoState; - - - /// The counter used to determine when an onDirty event needs to be posted. - unsigned int dirtyCounter; - - /// The accumulated dirty rectangle. When dirtyCounter hits 0, this is the rectangle that's posted to the onDirty callback. - drgui_rect accumulatedDirtyRect; - - - /// A pointer to the buffer containing details about every run in the layout. - drgui_text_run* pRuns; - - /// The number of runs in . - size_t runCount; - - /// The size of the buffer in drgui_text_run's. This is used to determine whether or not the buffer - /// needs to be reallocated upon adding a new run. - size_t runBufferSize; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data. - char pExtraData[1]; -}; - -/// Structure containing information about a line. This is used by first_line() and next_line(). -typedef struct -{ - /// The index of the line. - size_t index; - - /// The position of the line on the y axis. - float posY; - - /// The height of the line. - float height; - - /// The index of the first run on the line. - size_t iFirstRun; - - /// The index of the last run on the line. - size_t iLastRun; - -} drgui_text_engine_line; - - -/// Performs a complete refresh of the given text engine. -/// -/// @remarks -/// This will delete every run and re-create them. -DRGUI_PRIVATE void drgui_text_engine__refresh(drgui_text_engine* pTL); - -/// Refreshes the alignment of the given text engine. -DRGUI_PRIVATE void drgui_text_engine__refresh_alignment(drgui_text_engine* pTL); - -/// Appends a text run to the list of runs in the given text engine. -DRGUI_PRIVATE void drgui_text_engine__push_text_run(drgui_text_engine* pTL, drgui_text_run* pRun); - -/// Clears the internal list of text runs. -DRGUI_PRIVATE void drgui_text_engine__clear_text_runs(drgui_text_engine* pTL); - -/// Helper for calculating the offset to apply to each line based on the alignment of the given text engine. -DRGUI_PRIVATE void drgui_text_engine__calculate_line_alignment_offset(drgui_text_engine* pTL, float lineWidth, float* pOffsetXOut, float* pOffsetYOut); - -/// Helper for determine whether or not the given text run is whitespace. -DRGUI_PRIVATE bool drgui_text_engine__is_text_run_whitespace(drgui_text_engine* pTL, drgui_text_run* pRun); - -/// Helper for calculating the width of a tab. -DRGUI_PRIVATE float drgui_text_engine__get_tab_width(drgui_text_engine* pTL); - - -/// Finds the line that's closest to the given point relative to the text. -DRGUI_PRIVATE bool drgui_text_engine__find_closest_line_to_point(drgui_text_engine* pTL, float inputPosYRelativeToText, size_t* pFirstRunIndexOnLineOut, size_t* pLastRunIndexOnLinePlus1Out); - -/// Finds the run that's closest to the given point relative to the text. -DRGUI_PRIVATE bool drgui_text_engine__find_closest_run_to_point(drgui_text_engine* pTL, float inputPosXRelativeToText, float inputPosYRelativeToText, size_t* pRunIndexOut); - -/// Retrieves some basic information about a line, namely the index of the last run on the line, and the line's height. -DRGUI_PRIVATE bool drgui_text_engine__find_line_info(drgui_text_engine* pTL, size_t iFirstRunOnLine, size_t* pLastRunIndexOnLinePlus1Out, float* pLineHeightOut); - -/// Retrieves some basic information about a line by it's index. -DRGUI_PRIVATE bool drgui_text_engine__find_line_info_by_index(drgui_text_engine* pTL, size_t iLine, drgui_rect* pRectOut, size_t* pFirstRunIndexOut, size_t* pLastRunIndexPlus1Out); - -/// Finds the last run on the line that the given run is sitting on. -DRGUI_PRIVATE bool drgui_text_engine__find_last_run_on_line_starting_from_run(drgui_text_engine* pTL, size_t iRun, size_t* pLastRunIndexOnLineOut); - -/// Finds the first run on the line that the given run is sitting on. -DRGUI_PRIVATE bool drgui_text_engine__find_first_run_on_line_starting_from_run(drgui_text_engine* pTL, size_t iRun, size_t* pFirstRunIndexOnLineOut); - -/// Finds the run containing the character at the given index. -DRGUI_PRIVATE bool drgui_text_engine__find_run_at_character(drgui_text_engine* pTL, size_t iChar, size_t* pRunIndexOut); - - -/// Creates a blank text marker. -DRGUI_PRIVATE drgui_text_marker drgui_text_engine__new_marker(); - -/// Moves the given text marker to the given point, relative to the container. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_point_relative_to_container(drgui_text_engine* pTL, drgui_text_marker* pMarker, float inputPosX, float inputPosY); - -/// Retrieves the position of the given text marker relative to the container. -DRGUI_PRIVATE void drgui_text_engine__get_marker_position_relative_to_container(drgui_text_engine* pTL, drgui_text_marker* pMarker, float* pPosXOut, float* pPosYOut); - -/// Moves the marker to the given point, relative to the text rectangle. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_point(drgui_text_engine* pTL, drgui_text_marker* pMarker, float inputPosXRelativeToText, float inputPosYRelativeToText); - -/// Moves the given marker to the left by one character. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_left(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the right by one character. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_right(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker up one line. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_up(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker down one line. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_down(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker down one line. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_y(drgui_text_engine* pTL, drgui_text_marker* pMarker, int amount); - -/// Moves the given marker to the end of the line it's currently sitting on. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_end_of_line(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the start of the line it's currently sitting on. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_start_of_line(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the end of the line at the given index. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_end_of_line_by_index(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iLine); - -/// Moves the given marker to the start of the line at the given index. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_start_of_line_by_index(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iLine); - -/// Moves the given marker to the end of the text. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_end_of_text(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the start of the text. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_start_of_text(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the last character of the given run. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_last_character_of_run(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iRun); - -/// Moves the given marker to the first character of the given run. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_first_character_of_run(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iRun); - -/// Moves the given marker to the last character of the previous run. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_last_character_of_prev_run(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the first character of the next run. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_first_character_of_next_run(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Moves the given marker to the character at the given position. -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_character(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iChar); - - -/// Updates the relative position of the given marker. -/// -/// @remarks -/// This assumes the iRun and iChar properties are valid. -DRGUI_PRIVATE bool drgui_text_engine__update_marker_relative_position(drgui_text_engine* pTL, drgui_text_marker* pMarker); - -/// Updates the sticky position of the given marker. -DRGUI_PRIVATE void drgui_text_engine__update_marker_sticky_position(drgui_text_engine* pTL, drgui_text_marker* pMarker); - - -/// Retrieves the index of the character the given marker is located at. -DRGUI_PRIVATE size_t drgui_text_engine__get_marker_absolute_char_index(drgui_text_engine* pTL, drgui_text_marker* pMarker); - - -/// Helper function for determining whether or not there is any spacing between the selection markers. -DRGUI_PRIVATE bool drgui_text_engine__has_spacing_between_selection_markers(drgui_text_engine* pTL); - -/// Splits the given run into sub-runs based on the current selection rectangle. Returns the sub-run count. -DRGUI_PRIVATE size_t drgui_text_engine__split_text_run_by_selection(drgui_text_engine* pTL, drgui_text_run* pRunToSplit, drgui_text_run pSubRunsOut[3]); - - -/// Retrieves pointers to the selection markers in the correct order. -DRGUI_PRIVATE bool drgui_text_engine__get_selection_markers(drgui_text_engine* pTL, drgui_text_marker** ppSelectionMarker0Out, drgui_text_marker** ppSelectionMarker1Out); - - -/// Retrieves an iterator to the first line in the text engine. -DRGUI_PRIVATE bool drgui_text_engine__first_line(drgui_text_engine* pTL, drgui_text_engine_line* pLine); - -/// Retrieves an iterator to the next line in the text engine. -DRGUI_PRIVATE bool drgui_text_engine__next_line(drgui_text_engine* pTL, drgui_text_engine_line* pLine); - - -/// Removes the undo/redo state stack items after the current undo/redo point. -DRGUI_PRIVATE void drgui_text_engine__trim_undo_stack(drgui_text_engine* pTL); - -/// Initializes the given undo state object by diff-ing the given layout states. -DRGUI_PRIVATE bool drgui_text_engine__diff_states(drgui_text_engine_state* pPrevState, drgui_text_engine_state* pCurrentState, drgui_text_engine_undo_state* pUndoStateOut); - -/// Uninitializes the given undo state object. This basically just free's the internal string. -DRGUI_PRIVATE void drgui_text_engine__uninit_undo_state(drgui_text_engine_undo_state* pUndoState); - -/// Pushes an undo state onto the undo stack. -DRGUI_PRIVATE void drgui_text_engine__push_undo_state(drgui_text_engine* pTL, drgui_text_engine_undo_state* pUndoState); - -/// Applies the given undo state. -DRGUI_PRIVATE void drgui_text_engine__apply_undo_state(drgui_text_engine* pTL, drgui_text_engine_undo_state* pUndoState); - -/// Applies the given undo state as a redo operation. -DRGUI_PRIVATE void drgui_text_engine__apply_redo_state(drgui_text_engine* pTL, drgui_text_engine_undo_state* pUndoState); - - -/// Retrieves a rectangle relative to the given text engine that's equal to the size of the container. -DRGUI_PRIVATE drgui_rect drgui_text_engine__local_rect(drgui_text_engine* pTL); - - -/// Called when the cursor moves. -DRGUI_PRIVATE void drgui_text_engine__on_cursor_move(drgui_text_engine* pTL); - -/// Called when the text engine needs to be redrawn. -DRGUI_PRIVATE void drgui_text_engine__on_dirty(drgui_text_engine* pTL, drgui_rect rect); - -/// Increments the counter. The counter is decremented with drgui_text_engine__end_dirty(). Use this for batching redraws. -DRGUI_PRIVATE void drgui_text_engine__begin_dirty(drgui_text_engine* pTL); - -/// Decrements the dirty counter, and if it hits 0 posts the onDirty callback. -DRGUI_PRIVATE void drgui_text_engine__end_dirty(drgui_text_engine* pTL); - - - - -drgui_text_engine* drgui_create_text_engine(drgui_context* pContext, size_t extraDataSize, void* pExtraData) -{ - if (pContext == NULL) { - return NULL; - } - - drgui_text_engine* pTL = (drgui_text_engine*)malloc(sizeof(drgui_text_engine) + extraDataSize); - if (pTL == NULL) { - return NULL; - } - - pTL->text = NULL; - pTL->textLength = 0; - pTL->onDirty = NULL; - pTL->onTextChanged = NULL; - pTL->onUndoPointChanged = NULL; - pTL->containerWidth = 0; - pTL->containerHeight = 0; - pTL->innerOffsetX = 0; - pTL->innerOffsetY = 0; - pTL->pDefaultFont = NULL; - pTL->defaultTextColor = drgui_rgb(224, 224, 224); - pTL->defaultBackgroundColor = drgui_rgb(48, 48, 48); - pTL->selectionBackgroundColor = drgui_rgb(64, 128, 192); - pTL->lineBackgroundColor = drgui_rgb(40, 40, 40); - pTL->tabSizeInSpaces = 4; - pTL->horzAlign = drgui_text_engine_alignment_left; - pTL->vertAlign = drgui_text_engine_alignment_top; - pTL->cursorWidth = 1; - pTL->cursorColor = drgui_rgb(224, 224, 224); - pTL->cursorBlinkRate = 500; - pTL->timeToNextCursorBlink = pTL->cursorBlinkRate; - pTL->isCursorBlinkOn = true; - pTL->isShowingCursor = false; - pTL->textBoundsWidth = 0; - pTL->textBoundsHeight = 0; - pTL->cursor = drgui_text_engine__new_marker(); - pTL->selectionAnchor = drgui_text_engine__new_marker(); - pTL->selectionModeCounter = 0; - pTL->isAnythingSelected = false; - pTL->onPaintText = NULL; - pTL->onPaintRect = NULL; - pTL->onCursorMove = NULL; - pTL->preparedState.text = NULL; - pTL->pUndoStack = NULL; - pTL->undoStackCount = 0; - pTL->iUndoState = 0; - pTL->dirtyCounter = 0; - pTL->accumulatedDirtyRect = drgui_make_inside_out_rect(); - pTL->pRuns = NULL; - pTL->runCount = 0; - pTL->runBufferSize = 0; - - pTL->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pTL->pExtraData, pExtraData, extraDataSize); - } - - return pTL; -} - -void drgui_delete_text_engine(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - drgui_text_engine_clear_undo_stack(pTL); - - free(pTL->pRuns); - free(pTL->preparedState.text); - free(pTL->text); - free(pTL); -} - - -size_t drgui_text_engine_get_extra_data_size(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->extraDataSize; -} - -void* drgui_text_engine_get_extra_data(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return NULL; - } - - return pTL->pExtraData; -} - - -void drgui_text_engine_set_text(drgui_text_engine* pTL, const char* text) -{ - if (pTL == NULL) { - return; - } - - size_t textLength = strlen(text); - - free(pTL->text); - pTL->text = (char*)malloc(textLength + 1); // +1 for null terminator. - - // We now need to copy over the text, however we need to skip past \r characters in order to normalize line endings - // and keep everything simple. - char* dst = pTL->text; - const char* src = text; - while (*src != '\0') - { - if (*src != '\r') { - *dst++ = *src; - } - - src++; - } - *dst = '\0'; - - pTL->textLength = dst - pTL->text; - - // A change in text means we need to refresh the layout. - drgui_text_engine__refresh(pTL); - - // If the position of the cursor is past the last character we'll need to move it. - if (drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor) >= pTL->textLength) { - drgui_text_engine_move_cursor_to_end_of_text(pTL); - } - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -size_t drgui_text_engine_get_text(drgui_text_engine* pTL, char* textOut, size_t textOutSize) -{ - if (pTL == NULL) { - return 0; - } - - if (textOut == NULL) { - return pTL->textLength; - } - - - if (drgui__strcpy_s(textOut, textOutSize, (pTL->text != NULL) ? pTL->text : "") == 0) { - return pTL->textLength; - } - - return 0; // Error with strcpy_s(). -} - - -void drgui_text_engine_set_on_dirty(drgui_text_engine* pTL, drgui_text_engine_on_dirty_proc proc) -{ - if (pTL == NULL) { - return; - } - - pTL->onDirty = proc; -} - -void drgui_text_engine_set_on_text_changed(drgui_text_engine* pTL, drgui_text_engine_on_text_changed_proc proc) -{ - if (pTL == NULL) { - return; - } - - pTL->onTextChanged = proc; -} - -void drgui_text_engine_set_on_undo_point_changed(drgui_text_engine* pTL, drgui_text_engine_on_undo_point_changed_proc proc) -{ - if (pTL == NULL) { - return; - } - - pTL->onUndoPointChanged = proc; -} - - -void drgui_text_engine_set_container_size(drgui_text_engine* pTL, float containerWidth, float containerHeight) -{ - if (pTL == NULL) { - return; - } - - pTL->containerWidth = containerWidth; - pTL->containerHeight = containerHeight; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -void drgui_text_engine_get_container_size(drgui_text_engine* pTL, float* pContainerWidthOut, float* pContainerHeightOut) -{ - float containerWidth = 0; - float containerHeight = 0; - - if (pTL != NULL) - { - containerWidth = pTL->containerWidth; - containerHeight = pTL->containerHeight; - } - - - if (pContainerWidthOut) { - *pContainerWidthOut = containerWidth; - } - if (pContainerHeightOut) { - *pContainerHeightOut = containerHeight; - } -} - -float drgui_text_engine_get_container_width(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->containerWidth; -} - -float drgui_text_engine_get_container_height(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->containerHeight; -} - - -void drgui_text_engine_set_inner_offset(drgui_text_engine* pTL, float innerOffsetX, float innerOffsetY) -{ - if (pTL == NULL) { - return; - } - - pTL->innerOffsetX = innerOffsetX; - pTL->innerOffsetY = innerOffsetY; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -void drgui_text_engine_set_inner_offset_x(drgui_text_engine* pTL, float innerOffsetX) -{ - if (pTL == NULL) { - return; - } - - pTL->innerOffsetX = innerOffsetX; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -void drgui_text_engine_set_inner_offset_y(drgui_text_engine* pTL, float innerOffsetY) -{ - if (pTL == NULL) { - return; - } - - pTL->innerOffsetY = innerOffsetY; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -void drgui_text_engine_get_inner_offset(drgui_text_engine* pTL, float* pInnerOffsetX, float* pInnerOffsetY) -{ - float innerOffsetX = 0; - float innerOffsetY = 0; - - if (pTL != NULL) - { - innerOffsetX = pTL->innerOffsetX; - innerOffsetY = pTL->innerOffsetY; - } - - - if (pInnerOffsetX) { - *pInnerOffsetX = innerOffsetX; - } - if (pInnerOffsetY) { - *pInnerOffsetY = innerOffsetY; - } -} - -float drgui_text_engine_get_inner_offset_x(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->innerOffsetX; -} - -float drgui_text_engine_get_inner_offset_y(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->innerOffsetY; -} - - -void drgui_text_engine_set_default_font(drgui_text_engine* pTL, drgui_font* pFont) -{ - if (pTL == NULL) { - return; - } - - pTL->pDefaultFont = pFont; - - // A change in font requires a layout refresh. - drgui_text_engine__refresh(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -drgui_font* drgui_text_engine_get_default_font(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return NULL; - } - - return pTL->pDefaultFont; -} - -void drgui_text_engine_set_default_text_color(drgui_text_engine* pTL, drgui_color color) -{ - if (pTL == NULL) { - return; - } - - pTL->defaultTextColor = color; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -drgui_color drgui_text_engine_get_default_text_color(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTL->defaultTextColor; -} - -void drgui_text_engine_set_default_bg_color(drgui_text_engine* pTL, drgui_color color) -{ - if (pTL == NULL) { - return; - } - - pTL->defaultBackgroundColor = color; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -drgui_color drgui_text_engine_get_default_bg_color(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTL->defaultBackgroundColor; -} - -void drgui_text_engine_set_selection_bg_color(drgui_text_engine* pTL, drgui_color color) -{ - if (pTL == NULL) { - return; - } - - pTL->selectionBackgroundColor = color; - - if (drgui_text_engine_is_anything_selected(pTL)) { - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -drgui_color drgui_text_engine_get_selection_bg_color(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTL->selectionBackgroundColor; -} - -void drgui_text_engine_set_active_line_bg_color(drgui_text_engine* pTL, drgui_color color) -{ - if (pTL == NULL) { - return; - } - - pTL->lineBackgroundColor = color; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -drgui_color drgui_text_engine_get_active_line_bg_color(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTL->lineBackgroundColor; -} - - -void drgui_text_engine_set_tab_size(drgui_text_engine* pTL, unsigned int sizeInSpaces) -{ - if (pTL == NULL) { - return; - } - - if (pTL->tabSizeInSpaces != sizeInSpaces) - { - pTL->tabSizeInSpaces = sizeInSpaces; - - drgui_text_engine__refresh(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -unsigned int drgui_text_engine_get_tab_size(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->tabSizeInSpaces; -} - - -void drgui_text_engine_set_horizontal_align(drgui_text_engine* pTL, drgui_text_engine_alignment alignment) -{ - if (pTL == NULL) { - return; - } - - if (pTL->horzAlign != alignment) - { - pTL->horzAlign = alignment; - - drgui_text_engine__refresh_alignment(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -drgui_text_engine_alignment drgui_text_engine_get_horizontal_align(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_text_engine_alignment_left; - } - - return pTL->horzAlign; -} - -void drgui_text_engine_set_vertical_align(drgui_text_engine* pTL, drgui_text_engine_alignment alignment) -{ - if (pTL == NULL) { - return; - } - - if (pTL->vertAlign != alignment) - { - pTL->vertAlign = alignment; - - drgui_text_engine__refresh_alignment(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -drgui_text_engine_alignment drgui_text_engine_get_vertical_align(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_text_engine_alignment_top; - } - - return pTL->vertAlign; -} - - -drgui_rect drgui_text_engine_get_text_rect_relative_to_bounds(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - drgui_rect rect; - rect.left = 0; - rect.top = 0; - - - switch (pTL->horzAlign) - { - case drgui_text_engine_alignment_right: - { - rect.left = pTL->containerWidth - pTL->textBoundsWidth; - break; - } - - case drgui_text_engine_alignment_center: - { - rect.left = (pTL->containerWidth - pTL->textBoundsWidth) / 2; - break; - } - - case drgui_text_engine_alignment_left: - case drgui_text_engine_alignment_top: // Invalid for horizontal align. - case drgui_text_engine_alignment_bottom: // Invalid for horizontal align. - default: - { - break; - } - } - - - switch (pTL->vertAlign) - { - case drgui_text_engine_alignment_bottom: - { - rect.top = pTL->containerHeight - pTL->textBoundsHeight; - break; - } - - case drgui_text_engine_alignment_center: - { - rect.top = (pTL->containerHeight - pTL->textBoundsHeight) / 2; - break; - } - - case drgui_text_engine_alignment_top: - case drgui_text_engine_alignment_left: // Invalid for vertical align. - case drgui_text_engine_alignment_right: // Invalid for vertical align. - default: - { - break; - } - } - - - rect.left += pTL->innerOffsetX; - rect.top += pTL->innerOffsetY; - rect.right = rect.left + pTL->textBoundsWidth; - rect.bottom = rect.top + pTL->textBoundsHeight; - - return rect; -} - - -void drgui_text_engine_set_cursor_width(drgui_text_engine* pTL, float cursorWidth) -{ - if (pTL == NULL) { - return; - } - - drgui_rect oldCursorRect = drgui_text_engine_get_cursor_rect(pTL); - pTL->cursorWidth = cursorWidth; - if (pTL->cursorWidth > 0 && pTL->cursorWidth < 1) { - pTL->cursorWidth = 1; - } - - drgui_text_engine__on_dirty(pTL, drgui_rect_union(oldCursorRect, drgui_text_engine_get_cursor_rect(pTL))); -} - -float drgui_text_engine_get_cursor_width(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->cursorWidth; -} - -void drgui_text_engine_set_cursor_color(drgui_text_engine* pTL, drgui_color cursorColor) -{ - if (pTL == NULL) { - return; - } - - pTL->cursorColor = cursorColor; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine_get_cursor_rect(pTL)); -} - -drgui_color drgui_text_engine_get_cursor_color(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTL->cursorColor; -} - -void drgui_text_engine_set_cursor_blink_rate(drgui_text_engine* pTL, unsigned int blinkRateInMilliseconds) -{ - if (pTL == NULL) { - return; - } - - pTL->cursorBlinkRate = blinkRateInMilliseconds; -} - -unsigned int drgui_text_engine_get_cursor_blink_rate(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->cursorBlinkRate; -} - -void drgui_text_engine_show_cursor(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - if (!pTL->isShowingCursor) - { - pTL->isShowingCursor = true; - - pTL->timeToNextCursorBlink = pTL->cursorBlinkRate; - pTL->isCursorBlinkOn = true; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine_get_cursor_rect(pTL)); - } -} - -void drgui_text_engine_hide_cursor(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - if (pTL->isShowingCursor) - { - pTL->isShowingCursor = false; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine_get_cursor_rect(pTL)); - } -} - -bool drgui_text_engine_is_showing_cursor(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - return pTL->isShowingCursor; -} - -void drgui_text_engine_get_cursor_position(drgui_text_engine* pTL, float* pPosXOut, float* pPosYOut) -{ - if (pTL == NULL) { - return; - } - - drgui_text_engine__get_marker_position_relative_to_container(pTL, &pTL->cursor, pPosXOut, pPosYOut); -} - -drgui_rect drgui_text_engine_get_cursor_rect(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - drgui_rect lineRect = drgui_make_rect(0, 0, 0, 0); - - if (pTL->runCount > 0) - { - drgui_text_engine__find_line_info_by_index(pTL, pTL->pRuns[pTL->cursor.iRun].iLine, &lineRect, NULL, NULL); - } - else if (pTL->pDefaultFont != NULL) - { - drgui_font_metrics defaultFontMetrics; - drgui_get_font_metrics(pTL->pDefaultFont, &defaultFontMetrics); - - lineRect.bottom = (float)defaultFontMetrics.lineHeight; - } - - - - float cursorPosX; - float cursorPosY; - drgui_text_engine_get_cursor_position(pTL, &cursorPosX, &cursorPosY); - - return drgui_make_rect(cursorPosX, cursorPosY, cursorPosX + pTL->cursorWidth, cursorPosY + (lineRect.bottom - lineRect.top)); -} - -size_t drgui_text_engine_get_cursor_line(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - return pTL->pRuns[pTL->cursor.iRun].iLine; -} - -size_t drgui_text_engine_get_cursor_column(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - float posX; - float posY; - drgui_text_engine_get_cursor_position(pTL, &posX, &posY); - - drgui_font_metrics fontMetrics; - drgui_get_font_metrics(pTL->pDefaultFont, &fontMetrics); - - return (unsigned int)((int)posX / fontMetrics.spaceWidth); -} - -size_t drgui_text_engine_get_cursor_character(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor); -} - -void drgui_text_engine_move_cursor_to_point(drgui_text_engine* pTL, float posX, float posY) -{ - if (pTL == NULL) { - return; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - drgui_text_engine__move_marker_to_point_relative_to_container(pTL, &pTL->cursor, posX, posY); - - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -bool drgui_text_engine_move_cursor_left(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_left(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_right(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_right(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_up(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_up(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_down(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_down(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_y(drgui_text_engine* pTL, int amount) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_y(pTL, &pTL->cursor, amount)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_to_end_of_line(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_end_of_line(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_to_start_of_line(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_start_of_line(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_to_end_of_line_by_index(drgui_text_engine* pTL, size_t iLine) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_end_of_line_by_index(pTL, &pTL->cursor, iLine)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_to_start_of_line_by_index(drgui_text_engine* pTL, size_t iLine) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_start_of_line_by_index(pTL, &pTL->cursor, iLine)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_to_end_of_text(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_end_of_text(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_move_cursor_to_start_of_text(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_start_of_text(pTL, &pTL->cursor)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - - return true; - } - - return false; -} - -void drgui_text_engine_move_cursor_to_start_of_selection(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) - { - pTL->cursor = *pSelectionMarker0; - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -void drgui_text_engine_move_cursor_to_end_of_selection(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) - { - pTL->cursor = *pSelectionMarker1; - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -void drgui_text_engine_move_cursor_to_character(drgui_text_engine* pTL, size_t characterIndex) -{ - if (pTL == NULL) { - return; - } - - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - if (drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, characterIndex)) { - if (drgui_text_engine_is_in_selection_mode(pTL)) { - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - } - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - } -} - -bool drgui_text_engine_is_cursor_at_start_of_selection(drgui_text_engine* pTL) -{ - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) { - return &pTL->cursor == pSelectionMarker0; - } - - return false; -} - -bool drgui_text_engine_is_cursor_at_end_of_selection(drgui_text_engine* pTL) -{ - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) { - return &pTL->cursor == pSelectionMarker1; - } - - return false; -} - -void drgui_text_engine_swap_selection_markers(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) - { - size_t iRunOld = pTL->cursor.iRun; - size_t iCharOld = pTL->cursor.iChar; - - drgui_text_marker temp = *pSelectionMarker0; - *pSelectionMarker0 = *pSelectionMarker1; - *pSelectionMarker1 = temp; - - if (iRunOld != pTL->cursor.iRun || iCharOld != pTL->cursor.iChar) { - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - } - } -} - -void drgui_text_engine_set_on_cursor_move(drgui_text_engine* pTL, drgui_text_engine_on_cursor_move_proc proc) -{ - if (pTL == NULL) { - return; - } - - pTL->onCursorMove = proc; -} - -void drgui_text_engine_refresh_markers(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->pRuns == NULL) { - return; - } - - // Cursor. - drgui_text_run* pRun = pTL->pRuns + pTL->cursor.iRun; - drgui_get_text_cursor_position_from_char(pRun->pFont, pTL->text + pRun->iChar, pTL->cursor.iChar, OUT &pTL->cursor.relativePosX); - - pRun = pTL->pRuns + pTL->selectionAnchor.iRun; - drgui_get_text_cursor_position_from_char(pRun->pFont, pTL->text + pRun->iChar, pTL->selectionAnchor.iChar, OUT &pTL->selectionAnchor.relativePosX); -} - -bool drgui_text_engine_insert_character(drgui_text_engine* pTL, unsigned int character, size_t insertIndex) -{ - if (pTL == NULL) { - return false; - } - - // Transform '\r' to '\n'. - if (character == '\r') { - character = '\n'; - } - - - // TODO: Add proper support for UTF-8. - char* pOldText = pTL->text; - char* pNewText = (char*)malloc(pTL->textLength + 1 + 1); // +1 for the new character and +1 for the null terminator. - - if (insertIndex > 0) { - memcpy(pNewText, pOldText, insertIndex); - } - - pNewText[insertIndex] = (char)character; - - if (insertIndex < pTL->textLength) { - memcpy(pNewText + insertIndex + 1, pOldText + insertIndex, pTL->textLength - insertIndex); - } - - pTL->textLength += 1; - pTL->text = pNewText; - pNewText[pTL->textLength] = '\0'; - - free(pOldText); - - - - - // The layout will have changed so it needs to be refreshed. - drgui_text_engine__refresh(pTL); - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - - return true; -} - -bool drgui_text_engine_insert_text(drgui_text_engine* pTL, const char* text, size_t insertIndex) -{ - if (pTL == NULL || text == NULL) { - return false;; - } - - size_t newTextLength = strlen(text); - if (newTextLength == 0) { - return false; - } - - - // TODO: Add proper support for UTF-8. - char* pOldText = pTL->text; - char* pNewText = (char*)malloc(pTL->textLength + newTextLength + 1); // +1 for the new character and +1 for the null terminator. - - if (insertIndex > 0) { - memcpy(pNewText, pOldText, insertIndex); - } - - - // Replace \r\n with \n. - { - char* dst = pNewText + insertIndex; - const char* src = text; - size_t srcLen = newTextLength; - while (*src != '\0' && srcLen > 0) - { - if (*src != '\r') { - *dst++ = *src; - } - - src++; - srcLen -= 1; - } - - newTextLength = dst - (pNewText + insertIndex); - } - - if (insertIndex < pTL->textLength) { - memcpy(pNewText + insertIndex + newTextLength, pOldText + insertIndex, pTL->textLength - insertIndex); - } - - pTL->textLength += newTextLength; - pTL->text = pNewText; - pNewText[pTL->textLength] = '\0'; - - free(pOldText); - - - // The layout will have changed so it needs to be refreshed. - drgui_text_engine__refresh(pTL); - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - - return true; -} - -bool drgui_text_engine_delete_text_range(drgui_text_engine* pTL, size_t iFirstCh, size_t iLastChPlus1) -{ - if (pTL == NULL || iLastChPlus1 == iFirstCh) { - return false; - } - - if (iFirstCh > iLastChPlus1) { - size_t temp = iFirstCh; - iFirstCh = iLastChPlus1; - iLastChPlus1 = temp; - } - - - size_t bytesToRemove = iLastChPlus1 - iFirstCh; - if (bytesToRemove > 0) - { - memmove(pTL->text + iFirstCh, pTL->text + iLastChPlus1, pTL->textLength - iLastChPlus1); - pTL->textLength -= bytesToRemove; - pTL->text[pTL->textLength] = '\0'; - - // The layout will have changed. - drgui_text_engine__refresh(pTL); - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - - return true; - } - - return false; -} - -bool drgui_text_engine_insert_character_at_cursor(drgui_text_engine* pTL, unsigned int character) -{ - if (pTL == NULL) { - return false; - } - - size_t iAbsoluteMarkerChar = 0; - - drgui_text_run* pRun = pTL->pRuns + pTL->cursor.iRun; - if (pTL->runCount > 0 && pRun != NULL) { - iAbsoluteMarkerChar = pRun->iChar + pTL->cursor.iChar; - } - - drgui_text_engine__begin_dirty(pTL); - { - drgui_text_engine_insert_character(pTL, character, iAbsoluteMarkerChar); - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, iAbsoluteMarkerChar + 1); - } - drgui_text_engine__end_dirty(pTL); - - - // The cursor's sticky position needs to be updated whenever the text is edited. - drgui_text_engine__update_marker_sticky_position(pTL, &pTL->cursor); - - - drgui_text_engine__on_cursor_move(pTL); - - return true; -} - -bool drgui_text_engine_insert_text_at_cursor(drgui_text_engine* pTL, const char* text) -{ - if (pTL == NULL || text == NULL) { - return false; - } - - drgui_text_engine__begin_dirty(pTL); - { - size_t cursorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor); - drgui_text_engine_insert_text(pTL, text, cursorPos); - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, cursorPos + strlen(text)); - } - drgui_text_engine__end_dirty(pTL); - - - // The cursor's sticky position needs to be updated whenever the text is edited. - drgui_text_engine__update_marker_sticky_position(pTL, &pTL->cursor); - - drgui_text_engine__on_cursor_move(pTL); - - return true; -} - -bool drgui_text_engine_delete_character_to_left_of_cursor(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - // We just move the cursor to the left, and then delete the character to the right. - if (drgui_text_engine_move_cursor_left(pTL)) { - drgui_text_engine_delete_character_to_right_of_cursor(pTL); - return true; - } - - return false; -} - -bool drgui_text_engine_delete_character_to_right_of_cursor(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->runCount == 0) { - return false; - } - - drgui_text_run* pRun = pTL->pRuns + pTL->cursor.iRun; - size_t iAbsoluteMarkerChar = pRun->iChar + pTL->cursor.iChar; - - if (iAbsoluteMarkerChar < pTL->textLength) - { - // TODO: Add proper support for UTF-8. - memmove(pTL->text + iAbsoluteMarkerChar, pTL->text + iAbsoluteMarkerChar + 1, pTL->textLength - iAbsoluteMarkerChar); - pTL->textLength -= 1; - pTL->text[pTL->textLength] = '\0'; - - - - // The layout will have changed. - drgui_text_engine__refresh(pTL); - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, iAbsoluteMarkerChar); - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); - - return true; - } - - return false; -} - -bool drgui_text_engine_delete_selected_text(drgui_text_engine* pTL) -{ - // Don't do anything if nothing is selected. - if (!drgui_text_engine_is_anything_selected(pTL)) { - return false; - } - - drgui_text_marker* pSelectionMarker0 = &pTL->selectionAnchor; - drgui_text_marker* pSelectionMarker1 = &pTL->cursor; - if (pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar > pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar) - { - drgui_text_marker* temp = pSelectionMarker0; - pSelectionMarker0 = pSelectionMarker1; - pSelectionMarker1 = temp; - } - - size_t iSelectionChar0 = pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar; - size_t iSelectionChar1 = pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar; - - drgui_text_engine__begin_dirty(pTL); - bool wasTextChanged = drgui_text_engine_delete_text_range(pTL, iSelectionChar0, iSelectionChar1); - if (wasTextChanged) - { - // The marker needs to be updated based on the new layout. - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, iSelectionChar0); - - // The cursor's sticky position also needs to be updated. - drgui_text_engine__update_marker_sticky_position(pTL, &pTL->cursor); - - drgui_text_engine__on_cursor_move(pTL); - - - // Reset the selection marker. - pTL->selectionAnchor = pTL->cursor; - pTL->isAnythingSelected = false; - } - - drgui_text_engine__end_dirty(pTL); - return wasTextChanged; -} - - -void drgui_text_engine_enter_selection_mode(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - // If we've just entered selection mode and nothing is currently selected, we want to set the selection anchor to the current cursor position. - if (!drgui_text_engine_is_in_selection_mode(pTL) && !pTL->isAnythingSelected) { - pTL->selectionAnchor = pTL->cursor; - } - - pTL->selectionModeCounter += 1; -} - -void drgui_text_engine_leave_selection_mode(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - if (pTL->selectionModeCounter > 0) { - pTL->selectionModeCounter -= 1; - } -} - -bool drgui_text_engine_is_in_selection_mode(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - return pTL->selectionModeCounter > 0; -} - -bool drgui_text_engine_is_anything_selected(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - return pTL->isAnythingSelected; -} - -void drgui_text_engine_deselect_all(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - pTL->isAnythingSelected = false; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -void drgui_text_engine_select_all(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - drgui_text_engine__move_marker_to_start_of_text(pTL, &pTL->selectionAnchor); - drgui_text_engine__move_marker_to_end_of_text(pTL, &pTL->cursor); - - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -void drgui_text_engine_select(drgui_text_engine* pTL, size_t firstCharacter, size_t lastCharacter) -{ - if (pTL == NULL) { - return; - } - - drgui_text_engine__move_marker_to_character(pTL, &pTL->selectionAnchor, firstCharacter); - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, lastCharacter); - - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); - - drgui_text_engine__on_cursor_move(pTL); - drgui_text_engine__on_dirty(pTL, drgui_text_engine__local_rect(pTL)); -} - -size_t drgui_text_engine_get_selected_text(drgui_text_engine* pTL, char* textOut, size_t textOutSize) -{ - if (pTL == NULL || (textOut != NULL && textOutSize == 0)) { - return 0; - } - - if (!drgui_text_engine_is_anything_selected(pTL)) { - return 0; - } - - - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (!drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) { - return false; - } - - size_t iSelectionChar0 = pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar; - size_t iSelectionChar1 = pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar; - - size_t selectedTextLength = iSelectionChar1 - iSelectionChar0; - - if (textOut != NULL) { - drgui__strncpy_s(textOut, textOutSize, pTL->text + iSelectionChar0, selectedTextLength); - } - - return selectedTextLength; -} - -size_t drgui_text_engine_get_selection_first_line(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (!drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) { - return 0; - } - - return pTL->pRuns[pSelectionMarker0->iRun].iLine; -} - -size_t drgui_text_engine_get_selection_last_line(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (!drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) { - return 0; - } - - return pTL->pRuns[pSelectionMarker1->iRun].iLine; -} - -void drgui_text_engine_move_selection_anchor_to_end_of_line(drgui_text_engine* pTL, size_t iLine) -{ - if (pTL == NULL) { - return; - } - - drgui_text_engine__move_marker_to_end_of_line_by_index(pTL, &pTL->selectionAnchor, iLine); - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); -} - -void drgui_text_engine_move_selection_anchor_to_start_of_line(drgui_text_engine* pTL, size_t iLine) -{ - if (pTL == NULL) { - return; - } - - drgui_text_engine__move_marker_to_start_of_line_by_index(pTL, &pTL->selectionAnchor, iLine); - pTL->isAnythingSelected = drgui_text_engine__has_spacing_between_selection_markers(pTL); -} - -size_t drgui_text_engine_get_selection_anchor_line(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - return pTL->pRuns[pTL->selectionAnchor.iRun].iLine; -} - - - -bool drgui_text_engine_prepare_undo_point(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - // If we have a previously prepared state we'll need to clear it. - if (pTL->preparedState.text != NULL) { - free(pTL->preparedState.text); - } - - pTL->preparedState.text = (char*)malloc(pTL->textLength + 1); - drgui__strcpy_s(pTL->preparedState.text, pTL->textLength + 1, (pTL->text != NULL) ? pTL->text : ""); - - pTL->preparedState.cursorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor); - pTL->preparedState.selectionAnchorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->selectionAnchor); - pTL->preparedState.isAnythingSelected = pTL->isAnythingSelected; - - return true; -} - -bool drgui_text_engine_commit_undo_point(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - // The undo point must have been prepared earlier. - if (pTL->preparedState.text == NULL) { - return false; - } - - - // The undo state is creating by diff-ing the prepared state and the current state. - drgui_text_engine_state currentState; - currentState.text = pTL->text; - currentState.cursorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor); - currentState.selectionAnchorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->selectionAnchor); - currentState.isAnythingSelected = pTL->isAnythingSelected; - - drgui_text_engine_undo_state undoState; - if (!drgui_text_engine__diff_states(&pTL->preparedState, ¤tState, &undoState)) { - return false; - } - - - // At this point we have the undo state ready and we just need to add it the undo stack. Before doing so, however, - // we need to trim the end fo the stack. - drgui_text_engine__trim_undo_stack(pTL); - drgui_text_engine__push_undo_state(pTL, &undoState); - - return true; -} - -bool drgui_text_engine_undo(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->pUndoStack == NULL) { - return false; - } - - if (drgui_text_engine_get_undo_points_remaining_count(pTL) > 0) - { - drgui_text_engine_undo_state* pUndoState = pTL->pUndoStack + (pTL->iUndoState - 1); - assert(pUndoState != NULL); - - drgui_text_engine__apply_undo_state(pTL, pUndoState); - pTL->iUndoState -= 1; - - if (pTL->onUndoPointChanged) { - pTL->onUndoPointChanged(pTL, pTL->iUndoState); - } - - return true; - } - - return false; -} - -bool drgui_text_engine_redo(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->pUndoStack == NULL) { - return false; - } - - if (drgui_text_engine_get_redo_points_remaining_count(pTL) > 0) - { - drgui_text_engine_undo_state* pUndoState = pTL->pUndoStack + pTL->iUndoState; - assert(pUndoState != NULL); - - drgui_text_engine__apply_redo_state(pTL, pUndoState); - pTL->iUndoState += 1; - - if (pTL->onUndoPointChanged) { - pTL->onUndoPointChanged(pTL, pTL->iUndoState); - } - - return true; - } - - return false; -} - -unsigned int drgui_text_engine_get_undo_points_remaining_count(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - return pTL->iUndoState; -} - -unsigned int drgui_text_engine_get_redo_points_remaining_count(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return 0; - } - - if (pTL->undoStackCount > 0) - { - assert(pTL->iUndoState <= pTL->undoStackCount); - return pTL->undoStackCount - pTL->iUndoState; - } - - return 0; -} - -void drgui_text_engine_clear_undo_stack(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->pUndoStack == NULL) { - return; - } - - for (unsigned int i = 0; i < pTL->undoStackCount; ++i) { - drgui_text_engine__uninit_undo_state(pTL->pUndoStack + i); - } - - free(pTL->pUndoStack); - - pTL->pUndoStack = NULL; - pTL->undoStackCount = 0; - - if (pTL->iUndoState > 0) { - pTL->iUndoState = 0; - - if (pTL->onUndoPointChanged) { - pTL->onUndoPointChanged(pTL, pTL->iUndoState); - } - } -} - - - -size_t drgui_text_engine_get_line_count(drgui_text_engine* pTL) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - return pTL->pRuns[pTL->runCount - 1].iLine + 1; -} - -size_t drgui_text_engine_get_visible_line_count_starting_at(drgui_text_engine* pTL, size_t iFirstLine) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - unsigned int count = 0; - float lastLineBottom = 0; - - // First thing we do is find the first line. - unsigned int iLine = 0; - drgui_text_engine_line line; - if (drgui_text_engine__first_line(pTL, &line)) - { - do - { - if (iLine >= iFirstLine) { - break; - } - - iLine += 1; - } while (drgui_text_engine__next_line(pTL, &line)); - - - // At this point we are at the first line and we need to start counting. - do - { - if (line.posY + pTL->innerOffsetY >= pTL->containerHeight) { - break; - } - - count += 1; - lastLineBottom = line.posY + line.height; - - } while (drgui_text_engine__next_line(pTL, &line)); - } - - - // At this point there may be some empty space below the last line, in which case we use the line height of the default font to fill - // out the remaining space. - if (lastLineBottom + pTL->innerOffsetY < pTL->containerHeight) - { - drgui_font_metrics defaultFontMetrics; - if (drgui_get_font_metrics(pTL->pDefaultFont, &defaultFontMetrics)) { - count += (unsigned int)((pTL->containerHeight - (lastLineBottom + pTL->innerOffsetY)) / defaultFontMetrics.lineHeight); - } - } - - - - if (count == 0) { - return 1; - } - - return count; -} - -float drgui_text_engine_get_line_pos_y(drgui_text_engine* pTL, size_t iLine) -{ - drgui_rect lineRect; - if (!drgui_text_engine__find_line_info_by_index(pTL, iLine, &lineRect, NULL, NULL)) { - return 0; - } - - return lineRect.top; -} - -size_t drgui_text_engine_get_line_at_pos_y(drgui_text_engine* pTL, float posY) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - drgui_rect textRect = drgui_text_engine_get_text_rect_relative_to_bounds(pTL); - - size_t iRun; - - float inputPosYRelativeToText = posY - textRect.top; - if (!drgui_text_engine__find_closest_run_to_point(pTL, 0, inputPosYRelativeToText, &iRun)) { - return 0; - } - - return pTL->pRuns[iRun].iLine; -} - -size_t drgui_text_engine_get_line_first_character(drgui_text_engine* pTL, size_t iLine) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - size_t firstRunIndex0; - size_t lastRunIndexPlus1; - if (drgui_text_engine__find_line_info_by_index(pTL, iLine, NULL, &firstRunIndex0, &lastRunIndexPlus1)) { - return pTL->pRuns[firstRunIndex0].iChar; - } - - return 0; -} - -size_t drgui_text_engine_get_line_last_character(drgui_text_engine* pTL, size_t iLine) -{ - if (pTL == NULL || pTL->runCount == 0) { - return 0; - } - - size_t firstRunIndex0; - size_t lastRunIndexPlus1; - if (drgui_text_engine__find_line_info_by_index(pTL, iLine, NULL, &firstRunIndex0, &lastRunIndexPlus1)) { - size_t charEnd = pTL->pRuns[lastRunIndexPlus1 - 1].iCharEnd; - if (charEnd > 0) { - charEnd -= 1; - } - - return charEnd; - } - - return 0; -} - -void drgui_text_engine_get_line_character_range(drgui_text_engine* pTL, size_t iLine, size_t* pCharStartOut, size_t* pCharEndOut) -{ - if (pTL == NULL || pTL->runCount == 0) { - return; - } - - size_t charStart = 0; - size_t charEnd = 0; - - size_t firstRunIndex0; - size_t lastRunIndexPlus1; - if (drgui_text_engine__find_line_info_by_index(pTL, iLine, NULL, &firstRunIndex0, &lastRunIndexPlus1)) { - charStart = pTL->pRuns[firstRunIndex0].iChar; - charEnd = pTL->pRuns[lastRunIndexPlus1 - 1].iCharEnd; - if (charEnd > 0) { - charEnd -= 1; - } - } - - if (pCharStartOut) { - *pCharStartOut = charStart; - } - if (pCharEndOut) { - *pCharEndOut = charEnd; - } -} - - -void drgui_text_engine_set_on_paint_text(drgui_text_engine* pTL, drgui_text_engine_on_paint_text_proc proc) -{ - if (pTL == NULL) { - return; - } - - pTL->onPaintText = proc; -} - -void drgui_text_engine_set_on_paint_rect(drgui_text_engine* pTL, drgui_text_engine_on_paint_rect_proc proc) -{ - if (pTL == NULL) { - return; - } - - pTL->onPaintRect = proc; -} - -void drgui_text_engine_paint(drgui_text_engine* pTL, drgui_rect rect, drgui_element* pElement, void* pPaintData) -{ - if (pTL == NULL || pTL->onPaintText == NULL || pTL->onPaintRect == NULL) { - return; - } - - if (rect.left < 0) { - rect.left = 0; - } - if (rect.top < 0) { - rect.top = 0; - } - if (rect.right > pTL->containerWidth) { - rect.right = pTL->containerWidth; - } - if (rect.bottom > pTL->containerHeight) { - rect.bottom = pTL->containerHeight; - } - - if (rect.right <= rect.left || rect.bottom <= rect.top) { - return; - } - - - // The position of each run will be relative to the text bounds. We want to make it relative to the container bounds. - drgui_rect textRect = drgui_text_engine_get_text_rect_relative_to_bounds(pTL); - - // We draw a rectangle above and below the text rectangle. The main text rectangle will be drawn by iterating over each visible run. - drgui_rect rectTop = drgui_make_rect(0, 0, pTL->containerWidth, textRect.top); - drgui_rect rectBottom = drgui_make_rect(0, textRect.bottom, pTL->containerWidth, pTL->containerHeight); - - if (rectTop.bottom > rect.top) { - pTL->onPaintRect(pTL, rectTop, pTL->defaultBackgroundColor, pElement, pPaintData); - } - - if (rectBottom.top < rect.bottom) { - pTL->onPaintRect(pTL, rectBottom, pTL->defaultBackgroundColor, pElement, pPaintData); - } - - - // We draw line-by-line, starting from the first visible line. - drgui_text_engine_line line; - if (drgui_text_engine__first_line(pTL, &line)) - { - do - { - float lineTop = line.posY + textRect.top; - float lineBottom = lineTop + line.height; - - if (lineTop < rect.bottom) - { - if (lineBottom > rect.top) - { - // The line is visible. We draw in 3 main parts - 1) the blank space to the left of the first run; 2) the runs themselves; 3) the blank - // space to the right of the last run. - - drgui_color bgcolor = pTL->defaultBackgroundColor; - if (line.index == drgui_text_engine_get_cursor_line(pTL)) { - bgcolor = pTL->lineBackgroundColor; - } - - float lineSelectionOverhangLeft = 0; - float lineSelectionOverhangRight = 0; - - if (drgui_text_engine_is_anything_selected(pTL)) - { - drgui_text_marker* pSelectionMarker0 = &pTL->selectionAnchor; - drgui_text_marker* pSelectionMarker1 = &pTL->cursor; - if (pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar > pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar) - { - drgui_text_marker* temp = pSelectionMarker0; - pSelectionMarker0 = pSelectionMarker1; - pSelectionMarker1 = temp; - } - - size_t iSelectionLine0 = pTL->pRuns[pSelectionMarker0->iRun].iLine; - size_t iSelectionLine1 = pTL->pRuns[pSelectionMarker1->iRun].iLine; - - if (line.index >= iSelectionLine0 && line.index < iSelectionLine1) - { - drgui_font_metrics defaultFontMetrics; - drgui_get_font_metrics(pTL->pDefaultFont, &defaultFontMetrics); - - if (pTL->horzAlign == drgui_text_engine_alignment_right) - { - if (line.index > iSelectionLine0) { - lineSelectionOverhangLeft = (float)defaultFontMetrics.spaceWidth; - } - } - else if (pTL->horzAlign == drgui_text_engine_alignment_center) - { - lineSelectionOverhangRight = (float)defaultFontMetrics.spaceWidth; - - if (line.index > iSelectionLine0) { - lineSelectionOverhangLeft = (float)defaultFontMetrics.spaceWidth; - } - } - else - { - lineSelectionOverhangRight = (float)defaultFontMetrics.spaceWidth; - } - } - } - - - drgui_text_run* pFirstRun = pTL->pRuns + line.iFirstRun; - drgui_text_run* pLastRun = pTL->pRuns + line.iLastRun; - - float lineLeft = pFirstRun->posX + textRect.left; - float lineRight = pLastRun->posX + pLastRun->width + textRect.left; - - // 1) The blank space to the left of the first run. - if (lineLeft > 0) - { - if (lineSelectionOverhangLeft > 0) { - pTL->onPaintRect(pTL, drgui_make_rect(lineLeft - lineSelectionOverhangLeft, lineTop, lineLeft, lineBottom), pTL->selectionBackgroundColor, pElement, pPaintData); - } - - pTL->onPaintRect(pTL, drgui_make_rect(0, lineTop, lineLeft - lineSelectionOverhangLeft, lineBottom), bgcolor, pElement, pPaintData); - } - - - // 2) The runs themselves. - for (size_t iRun = line.iFirstRun; iRun <= line.iLastRun; ++iRun) - { - drgui_text_run* pRun = pTL->pRuns + iRun; - - float runLeft = pRun->posX + textRect.left; - float runRight = runLeft + pRun->width; - - if (runRight > 0 && runLeft < pTL->containerWidth) - { - // The run is visible. - if (!drgui_text_engine__is_text_run_whitespace(pTL, pRun) || pTL->text[pRun->iChar] == '\t') - { - drgui_text_run run = pTL->pRuns[iRun]; - run.pFont = pTL->pDefaultFont; - run.textColor = pTL->defaultTextColor; - run.backgroundColor = bgcolor; - run.text = pTL->text + run.iChar; - run.posX = runLeft; - run.posY = lineTop; - - // We paint the run differently depending on whether or not anything is selected. If something is selected - // we need to split the run into a maximum of 3 sub-runs so that the selection rectangle can be drawn correctly. - if (drgui_text_engine_is_anything_selected(pTL)) - { - drgui_text_run subruns[3]; - size_t subrunCount = drgui_text_engine__split_text_run_by_selection(pTL, &run, subruns); - for (size_t iSubRun = 0; iSubRun < subrunCount; ++iSubRun) - { - drgui_text_run* pSubRun = subruns + iSubRun; - - if (!drgui_text_engine__is_text_run_whitespace(pTL, pRun)) { - pTL->onPaintText(pTL, pSubRun, pElement, pPaintData); - } else { - pTL->onPaintRect(pTL, drgui_make_rect(pSubRun->posX, lineTop, pSubRun->posX + pSubRun->width, lineBottom), pSubRun->backgroundColor, pElement, pPaintData); - } - } - } - else - { - // Nothing is selected. - if (!drgui_text_engine__is_text_run_whitespace(pTL, &run)) { - pTL->onPaintText(pTL, &run, pElement, pPaintData); - } else { - pTL->onPaintRect(pTL, drgui_make_rect(run.posX, lineTop, run.posX + run.width, lineBottom), run.backgroundColor, pElement, pPaintData); - } - } - } - } - } - - - // 3) The blank space to the right of the last run. - if (lineRight < pTL->containerWidth) - { - if (lineSelectionOverhangRight > 0) { - pTL->onPaintRect(pTL, drgui_make_rect(lineRight, lineTop, lineRight + lineSelectionOverhangRight, lineBottom), pTL->selectionBackgroundColor, pElement, pPaintData); - } - - pTL->onPaintRect(pTL, drgui_make_rect(lineRight + lineSelectionOverhangRight, lineTop, pTL->containerWidth, lineBottom), bgcolor, pElement, pPaintData); - } - } - } - else - { - // The line is below the rectangle which means no other line will be visible and we can terminate early. - break; - } - - } while (drgui_text_engine__next_line(pTL, &line)); - } - else - { - // There are no lines so we do a simplified branch here. - float lineTop = textRect.top; - float lineBottom = textRect.bottom; - pTL->onPaintRect(pTL, drgui_make_rect(0, lineTop, pTL->containerWidth, lineBottom), pTL->lineBackgroundColor, pElement, pPaintData); - } - - // The cursor. - if (pTL->isShowingCursor && pTL->isCursorBlinkOn) { - pTL->onPaintRect(pTL, drgui_text_engine_get_cursor_rect(pTL), pTL->cursorColor, pElement, pPaintData); - } -} - - -void drgui_text_engine_step(drgui_text_engine* pTL, unsigned int milliseconds) -{ - if (pTL == NULL || milliseconds == 0) { - return; - } - - if (pTL->timeToNextCursorBlink < milliseconds) - { - pTL->isCursorBlinkOn = !pTL->isCursorBlinkOn; - pTL->timeToNextCursorBlink = pTL->cursorBlinkRate; - - drgui_text_engine__on_dirty(pTL, drgui_text_engine_get_cursor_rect(pTL)); - } - else - { - pTL->timeToNextCursorBlink -= milliseconds; - } -} - - - -void drgui_text_engine_paint_line_numbers(drgui_text_engine* pTL, float lineNumbersWidth, float lineNumbersHeight, drgui_color textColor, drgui_color backgroundColor, drgui_text_engine_on_paint_text_proc onPaintText, drgui_text_engine_on_paint_rect_proc onPaintRect, drgui_element* pElement, void* pPaintData) -{ - if (pTL == NULL || onPaintText == NULL || onPaintRect == NULL) { - return; - } - - - // The position of each run will be relative to the text bounds. We want to make it relative to the container bounds. - drgui_rect textRect = drgui_text_engine_get_text_rect_relative_to_bounds(pTL); - - // We draw a rectangle above and below the text rectangle. The main text rectangle will be drawn by iterating over each visible run. - drgui_rect rectTop = drgui_make_rect(0, 0, lineNumbersWidth, textRect.top); - drgui_rect rectBottom = drgui_make_rect(0, textRect.bottom, lineNumbersWidth, lineNumbersHeight); - - if (pTL->onPaintRect) - { - if (rectTop.bottom > 0) { - onPaintRect(pTL, rectTop, backgroundColor, pElement, pPaintData); - } - - if (rectBottom.top < lineNumbersHeight) { - onPaintRect(pTL, rectBottom, backgroundColor, pElement, pPaintData); - } - } - - - // Now we draw each line. - int iLine = 1; - drgui_text_engine_line line; - if (!drgui_text_engine__first_line(pTL, &line)) - { - // We failed to retrieve the first line which is probably due to the text engine being empty. We just fake the first line to - // ensure we get the number 1 to be drawn. - drgui_font_metrics fontMetrics; - drgui_get_font_metrics(pTL->pDefaultFont, &fontMetrics); - - line.height = (float)fontMetrics.lineHeight; - line.posY = 0; - } - - do - { - float lineTop = line.posY + textRect.top; - float lineBottom = lineTop + line.height; - - if (lineTop < lineNumbersHeight) - { - if (lineBottom > 0) - { - char iLineStr[64]; - #ifdef _MSC_VER - _itoa_s(iLine, iLineStr, sizeof(iLineStr), 10); - #else - snprintf(iLineStr, sizeof(iLineStr), "%d", iLine); - #endif - - drgui_font* pFont = pTL->pDefaultFont; - - float textWidth; - float textHeight; - drgui_measure_string(pFont, iLineStr, strlen(iLineStr), &textWidth, &textHeight); - - drgui_text_run run = {0}; - run.pFont = pFont; - run.textColor = textColor; - run.backgroundColor = backgroundColor; - run.text = iLineStr; - run.textLength = strlen(iLineStr); - run.posX = lineNumbersWidth - textWidth; - run.posY = lineTop; - onPaintText(pTL, &run, pElement, pPaintData); - onPaintRect(pTL, drgui_make_rect(0, lineTop, run.posX, lineBottom), run.backgroundColor, pElement, pPaintData); - } - } - else - { - // The line is below the rectangle which means no other line will be visible and we can terminate early. - break; - } - - iLine += 1; - } while (drgui_text_engine__next_line(pTL, &line)); -} - - -bool drgui_text_engine_find_next(drgui_text_engine* pTL, const char* text, size_t* pSelectionStartOut, size_t* pSelectionEndOut) -{ - if (pTL == NULL || pTL->text == NULL || text == NULL || text[0] == '\0') { - return false; - } - - size_t cursorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor); - char* nextOccurance = strstr(pTL->text + cursorPos, text); - if (nextOccurance == NULL) { - nextOccurance = strstr(pTL->text, text); - } - - if (nextOccurance == NULL) { - return false; - } - - if (pSelectionStartOut) { - *pSelectionStartOut = nextOccurance - pTL->text; - } - if (pSelectionEndOut) { - *pSelectionEndOut = (nextOccurance - pTL->text) + strlen(text); - } - - return true; -} - -bool drgui_text_engine_find_next_no_loop(drgui_text_engine* pTL, const char* text, size_t* pSelectionStartOut, size_t* pSelectionEndOut) -{ - if (pTL == NULL || pTL->text == NULL || text == NULL || text[0] == '\0') { - return false; - } - - size_t cursorPos = drgui_text_engine__get_marker_absolute_char_index(pTL, &pTL->cursor); - - char* nextOccurance = strstr(pTL->text + cursorPos, text); - if (nextOccurance == NULL) { - return false; - } - - if (pSelectionStartOut) { - *pSelectionStartOut = nextOccurance - pTL->text; - } - if (pSelectionEndOut) { - *pSelectionEndOut = (nextOccurance - pTL->text) + strlen(text); - } - - return true; -} - - - - -DRGUI_PRIVATE bool drgui_next_run_string(const char* runStart, const char* textEndPastNullTerminator, const char** pRunEndOut) -{ - assert(runStart <= textEndPastNullTerminator); - - if (runStart == NULL || runStart == textEndPastNullTerminator) - { - // String is empty. - return false; - } - - - char firstChar = runStart[0]; - if (firstChar == '\t') - { - // We loop until we hit anything that is not a tab character (tabs will be grouped together into a single run). - do - { - runStart += 1; - *pRunEndOut = runStart; - } while (runStart[0] != '\0' && runStart[0] == '\t'); - } - else if (firstChar == '\n') - { - runStart += 1; - *pRunEndOut = runStart; - } - else if (firstChar == '\0') - { - assert(runStart + 1 == textEndPastNullTerminator); - *pRunEndOut = textEndPastNullTerminator; - } - else - { - do - { - runStart += 1; - *pRunEndOut = runStart; - } while (runStart[0] != '\0' && runStart[0] != '\t' && runStart[0] != '\n'); - } - - return true; -} - -DRGUI_PRIVATE void drgui_text_engine__refresh(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - // We split the runs based on tabs and new-lines. We want to create runs for tabs and new-line characters as well because we want - // to have the entire string covered by runs for the sake of simplicity when it comes to editing. - // - // The first pass positions the runs based on a top-to-bottom, left-to-right alignment. The second pass then repositions the runs - // based on alignment. - - // Runs need to be cleared first. - drgui_text_engine__clear_text_runs(pTL); - - // The text bounds also need to be reset at the top. - pTL->textBoundsWidth = 0; - pTL->textBoundsHeight = 0; - - drgui_font_metrics defaultFontMetrics; - drgui_get_font_metrics(pTL->pDefaultFont, &defaultFontMetrics); - - pTL->textBoundsHeight = (float)defaultFontMetrics.lineHeight; - - const float tabWidth = drgui_text_engine__get_tab_width(pTL); - - size_t iCurrentLine = 0; - float runningPosY = 0; - float runningLineHeight = 0; - - const char* nextRunStart = pTL->text; - const char* nextRunEnd; - while (drgui_next_run_string(nextRunStart, pTL->text + pTL->textLength + 1, OUT &nextRunEnd)) - { - drgui_text_run run; - run.iLine = iCurrentLine; - run.iChar = nextRunStart - pTL->text; - run.iCharEnd = nextRunEnd - pTL->text; - run.textLength = nextRunEnd - nextRunStart; - run.width = 0; - run.height = 0; - run.posX = 0; - run.posY = runningPosY; - run.pFont = pTL->pDefaultFont; - - // X position - // - // The x position depends on the previous run that's on the same line. - if (pTL->runCount > 0) - { - drgui_text_run* pPrevRun = pTL->pRuns + (pTL->runCount - 1); - if (pPrevRun->iLine == iCurrentLine) - { - run.posX = pPrevRun->posX + pPrevRun->width; - } - else - { - // It's the first run on the line. - run.posX = 0; - } - } - - - // Width and height. - assert(nextRunEnd > nextRunStart); - if (nextRunStart[0] == '\t') - { - // Tab. - size_t tabCount = run.iCharEnd - run.iChar; - run.width = (float)(((tabCount*(size_t)tabWidth) - ((size_t)run.posX % (size_t)tabWidth))); - run.height = (float)defaultFontMetrics.lineHeight; - } - else if (nextRunStart[0] == '\n') - { - // New line. - iCurrentLine += 1; - run.width = 0; - run.height = (float)defaultFontMetrics.lineHeight; - } - else if (nextRunStart[0] == '\0') - { - // Null terminator. - run.width = 0; - run.height = (float)defaultFontMetrics.lineHeight; - run.textLength = 0; - } - else - { - // Normal run. - drgui_measure_string(pTL->pDefaultFont, nextRunStart, run.textLength, &run.width, &run.height); - } - - - // The running line height needs to be updated by setting to the maximum size. - runningLineHeight = (run.height > runningLineHeight) ? run.height : runningLineHeight; - - - // Update the text bounds. - if (pTL->textBoundsWidth < run.posX + run.width) { - pTL->textBoundsWidth = run.posX + run.width; - } - pTL->textBoundsHeight = runningPosY + runningLineHeight; - - - // A new line means we need to increment the running y position by the running line height. - if (nextRunStart[0] == '\n') - { - runningPosY += runningLineHeight; - runningLineHeight = 0; - } - - // Add the run to the internal list. - drgui_text_engine__push_text_run(pTL, &run); - - // Go to the next run string. - nextRunStart = nextRunEnd; - } - - // If we were to return now the text would be alignment top/left. If the alignment is not top/left we need to refresh the layout. - if (pTL->horzAlign != drgui_text_engine_alignment_left || pTL->vertAlign != drgui_text_engine_alignment_top) - { - drgui_text_engine__refresh_alignment(pTL); - } -} - -DRGUI_PRIVATE void drgui_text_engine__refresh_alignment(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - float runningPosY = 0; - - unsigned int iCurrentLine = 0; - for (size_t iRun = 0; iRun < pTL->runCount; /* Do Nothing*/) // iRun is incremented from within the loop. - { - float lineWidth = 0; - float lineHeight = 0; - - // This loop does a few things. First, it defines the end point for the loop after this one (jRun). Second, it calculates - // the line width which is needed for center and right alignment. Third it resets the position of each run to their - // unaligned equivalents which will be offsetted in the second loop. - size_t jRun; - for (jRun = iRun; jRun < pTL->runCount && pTL->pRuns[jRun].iLine == iCurrentLine; ++jRun) - { - drgui_text_run* pRun = pTL->pRuns + jRun; - pRun->posX = lineWidth; - pRun->posY = runningPosY; - - lineWidth += pRun->width; - lineHeight = (lineHeight > pRun->height) ? lineHeight : pRun->height; - } - - - // The actual alignment is done here. - float lineOffsetX; - float lineOffsetY; - drgui_text_engine__calculate_line_alignment_offset(pTL, lineWidth, OUT &lineOffsetX, OUT &lineOffsetY); - - for (/* Do Nothing*/; iRun < jRun; ++iRun) - { - drgui_text_run* pRun = pTL->pRuns + iRun; - pRun->posX += lineOffsetX; - pRun->posY += lineOffsetY; - } - - - // Go to the next line. - iCurrentLine += 1; - runningPosY += lineHeight; - } -} - -void drgui_text_engine__calculate_line_alignment_offset(drgui_text_engine* pTL, float lineWidth, float* pOffsetXOut, float* pOffsetYOut) -{ - if (pTL == NULL) { - return; - } - - float offsetX = 0; - float offsetY = 0; - - switch (pTL->horzAlign) - { - case drgui_text_engine_alignment_right: - { - offsetX = pTL->textBoundsWidth - lineWidth; - break; - } - - case drgui_text_engine_alignment_center: - { - offsetX = (pTL->textBoundsWidth - lineWidth) / 2; - break; - } - - case drgui_text_engine_alignment_left: - case drgui_text_engine_alignment_top: // Invalid for horizontal alignment. - case drgui_text_engine_alignment_bottom: // Invalid for horizontal alignment. - default: - { - offsetX = 0; - break; - } - } - - - switch (pTL->vertAlign) - { - case drgui_text_engine_alignment_bottom: - { - offsetY = pTL->textBoundsHeight - pTL->textBoundsHeight; - break; - } - - case drgui_text_engine_alignment_center: - { - offsetY = (pTL->textBoundsHeight - pTL->textBoundsHeight) / 2; - break; - } - - case drgui_text_engine_alignment_top: - case drgui_text_engine_alignment_left: // Invalid for vertical alignment. - case drgui_text_engine_alignment_right: // Invalid for vertical alignment. - default: - { - offsetY = 0; - break; - } - } - - - if (pOffsetXOut) { - *pOffsetXOut = offsetX; - } - if (pOffsetYOut) { - *pOffsetYOut = offsetY; - } -} - - -DRGUI_PRIVATE void drgui_text_engine__push_text_run(drgui_text_engine* pTL, drgui_text_run* pRun) -{ - if (pTL == NULL) { - return; - } - - if (pTL->runBufferSize == pTL->runCount) - { - pTL->runBufferSize = pTL->runBufferSize*2; - if (pTL->runBufferSize == 0) { - pTL->runBufferSize = 1; - } - - pTL->pRuns = (drgui_text_run*)realloc(pTL->pRuns, sizeof(drgui_text_run) * pTL->runBufferSize); - if (pTL->pRuns == NULL) { - pTL->runCount = 0; - pTL->runBufferSize = 0; - return; - } - } - - pTL->pRuns[pTL->runCount] = *pRun; - pTL->runCount += 1; -} - -DRGUI_PRIVATE void drgui_text_engine__clear_text_runs(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - pTL->runCount = 0; -} - -DRGUI_PRIVATE bool drgui_text_engine__is_text_run_whitespace(drgui_text_engine* pTL, drgui_text_run* pRun) -{ - if (pRun == NULL) { - return false; - } - - if (pTL->text[pRun->iChar] != '\t' && pTL->text[pRun->iChar] != '\n') - { - return false; - } - - return true; -} - -DRGUI_PRIVATE float drgui_text_engine__get_tab_width(drgui_text_engine* pTL) -{ - drgui_font_metrics defaultFontMetrics; - drgui_get_font_metrics(pTL->pDefaultFont, &defaultFontMetrics); - - return (float)(defaultFontMetrics.spaceWidth * pTL->tabSizeInSpaces); -} - - -DRGUI_PRIVATE bool drgui_text_engine__find_closest_line_to_point(drgui_text_engine* pTL, float inputPosYRelativeToText, size_t* pFirstRunIndexOnLineOut, size_t* pLastRunIndexOnLinePlus1Out) -{ - size_t iFirstRunOnLine = 0; - size_t iLastRunOnLinePlus1 = 0; - - bool result = true; - if (pTL == NULL || pTL->runCount == 0) - { - result = false; - } - else - { - float runningLineTop = 0; - - float lineHeight; - while (drgui_text_engine__find_line_info(pTL, iFirstRunOnLine, OUT &iLastRunOnLinePlus1, OUT &lineHeight)) - { - const float lineTop = runningLineTop; - const float lineBottom = lineTop + lineHeight; - - if (inputPosYRelativeToText < lineBottom) - { - // It's on this line. - break; - } - else - { - // It's not on this line - go to the next one, unless we're already on the last line. - if (iLastRunOnLinePlus1 == pTL->runCount) { - break; - } - - iFirstRunOnLine = iLastRunOnLinePlus1; - runningLineTop = lineBottom; - } - } - } - - if (pFirstRunIndexOnLineOut) { - *pFirstRunIndexOnLineOut = iFirstRunOnLine; - } - if (pLastRunIndexOnLinePlus1Out) { - *pLastRunIndexOnLinePlus1Out = iLastRunOnLinePlus1; - } - - return result; -} - -DRGUI_PRIVATE bool drgui_text_engine__find_closest_run_to_point(drgui_text_engine* pTL, float inputPosXRelativeToText, float inputPosYRelativeToText, size_t* pRunIndexOut) -{ - if (pTL == NULL) { - return false; - } - - size_t iFirstRunOnLine; - size_t iLastRunOnLinePlus1; - if (drgui_text_engine__find_closest_line_to_point(pTL, inputPosYRelativeToText, OUT &iFirstRunOnLine, OUT &iLastRunOnLinePlus1)) - { - size_t iRunOut = 0; - - const drgui_text_run* pFirstRunOnLine = pTL->pRuns + iFirstRunOnLine; - const drgui_text_run* pLastRunOnLine = pTL->pRuns + (iLastRunOnLinePlus1 - 1); - - if (inputPosXRelativeToText < pFirstRunOnLine->posX) - { - // It's to the left of the first run. - iRunOut = iFirstRunOnLine; - } - else if (inputPosXRelativeToText > pLastRunOnLine->posX + pLastRunOnLine->width) - { - // It's to the right of the last run. - iRunOut = iLastRunOnLinePlus1 - 1; - } - else - { - // It's in the middle of the line. We just iterate over each run on the line and return the first one that contains the point. - for (size_t iRun = iFirstRunOnLine; iRun < iLastRunOnLinePlus1; ++iRun) - { - const drgui_text_run* pRun = pTL->pRuns + iRun; - iRunOut = iRun; - - if (inputPosXRelativeToText >= pRun->posX && inputPosXRelativeToText <= pRun->posX + pRun->width) { - break; - } - } - } - - if (pRunIndexOut) { - *pRunIndexOut = iRunOut; - } - - return true; - } - else - { - // There was an error finding the closest line. - return false; - } -} - -DRGUI_PRIVATE bool drgui_text_engine__find_line_info(drgui_text_engine* pTL, size_t iFirstRunOnLine, size_t* pLastRunIndexOnLinePlus1Out, float* pLineHeightOut) -{ - if (pTL == NULL) { - return false; - } - - if (iFirstRunOnLine < pTL->runCount) - { - const size_t iLine = pTL->pRuns[iFirstRunOnLine].iLine; - float lineHeight = 0; - - size_t iRun; - for (iRun = iFirstRunOnLine; iRun < pTL->runCount && pTL->pRuns[iRun].iLine == iLine; ++iRun) - { - if (lineHeight < pTL->pRuns[iRun].height) { - lineHeight = pTL->pRuns[iRun].height; - } - } - - assert(iRun > iFirstRunOnLine); - - if (pLastRunIndexOnLinePlus1Out) { - *pLastRunIndexOnLinePlus1Out = iRun; - } - if (pLineHeightOut) { - *pLineHeightOut = lineHeight; - } - - return true; - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__find_line_info_by_index(drgui_text_engine* pTL, size_t iLine, drgui_rect* pRectOut, size_t* pFirstRunIndexOut, size_t* pLastRunIndexPlus1Out) -{ - if (pTL == NULL) { - return false; - } - - size_t iFirstRunOnLine = 0; - size_t iLastRunOnLinePlus1 = 0; - - float lineTop = 0; - float lineHeight = 0; - - for (size_t iCurrentLine = 0; iCurrentLine <= iLine; ++iCurrentLine) - { - iFirstRunOnLine = iLastRunOnLinePlus1; - lineTop += lineHeight; - - if (!drgui_text_engine__find_line_info(pTL, iFirstRunOnLine, &iLastRunOnLinePlus1, &lineHeight)) - { - // There was an error retrieving information about the line. - return false; - } - } - - - // At this point we have the first and last runs that make up the line and we can generate our output. - if (iLastRunOnLinePlus1 > iFirstRunOnLine) - { - if (pFirstRunIndexOut) { - *pFirstRunIndexOut = iFirstRunOnLine; - } - if (pLastRunIndexPlus1Out) { - *pLastRunIndexPlus1Out = iLastRunOnLinePlus1; - } - - if (pRectOut != NULL) - { - pRectOut->left = pTL->pRuns[iFirstRunOnLine].posX; - pRectOut->right = pTL->pRuns[iLastRunOnLinePlus1 - 1].posX + pTL->pRuns[iLastRunOnLinePlus1 - 1].width; - pRectOut->top = lineTop; - pRectOut->bottom = pRectOut->top + lineHeight; - } - - return true; - } - else - { - // We couldn't find any runs. - return false; - } -} - -DRGUI_PRIVATE bool drgui_text_engine__find_last_run_on_line_starting_from_run(drgui_text_engine* pTL, size_t iRun, size_t* pLastRunIndexOnLineOut) -{ - if (pTL == NULL || pTL->pRuns == NULL) { - return false; - } - - size_t result = iRun; - - size_t iLine = pTL->pRuns[iRun].iLine; - for (/* Do Nothing*/; iRun < pTL->runCount && pTL->pRuns[iRun].iLine == iLine; ++iRun) - { - result = iRun; - } - - if (pLastRunIndexOnLineOut) { - *pLastRunIndexOnLineOut = result; - } - - return true; -} - -DRGUI_PRIVATE bool drgui_text_engine__find_first_run_on_line_starting_from_run(drgui_text_engine* pTL, size_t iRun, size_t* pFirstRunIndexOnLineOut) -{ - if (pTL == NULL) { - return false; - } - - size_t result = iRun; - - size_t iLine = pTL->pRuns[iRun].iLine; - for (/* Do Nothing*/; iRun > 0 && pTL->pRuns[iRun - 1].iLine == iLine; --iRun) - { - result = iRun - 1; - } - - if (pFirstRunIndexOnLineOut) { - *pFirstRunIndexOnLineOut = result; - } - - return true; -} - -DRGUI_PRIVATE bool drgui_text_engine__find_run_at_character(drgui_text_engine* pTL, size_t iChar, size_t* pRunIndexOut) -{ - if (pTL == NULL || pTL->runCount == 0) { - return false; - } - - size_t result = 0; - if (iChar < pTL->textLength) - { - for (size_t iRun = 0; iRun < pTL->runCount; ++iRun) - { - const drgui_text_run* pRun = pTL->pRuns + iRun; - - if (iChar < pRun->iCharEnd) - { - result = iRun; - break; - } - } - } - else - { - // The character index is too high. Return the last run. - result = pTL->runCount - 1; - } - - if (pRunIndexOut) { - *pRunIndexOut = result; - } - - return true; -} - - -DRGUI_PRIVATE drgui_text_marker drgui_text_engine__new_marker() -{ - drgui_text_marker marker; - marker.iRun = 0; - marker.iChar = 0; - marker.relativePosX = 0; - marker.absoluteSickyPosX = 0; - - return marker; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_point_relative_to_container(drgui_text_engine* pTL, drgui_text_marker* pMarker, float inputPosX, float inputPosY) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - pMarker->iRun = 0; - pMarker->iChar = 0; - pMarker->relativePosX = 0; - pMarker->absoluteSickyPosX = 0; - - drgui_rect textRect = drgui_text_engine_get_text_rect_relative_to_bounds(pTL); - - float inputPosXRelativeToText = inputPosX - textRect.left; - float inputPosYRelativeToText = inputPosY - textRect.top; - if (drgui_text_engine__move_marker_to_point(pTL, pMarker, inputPosXRelativeToText, inputPosYRelativeToText)) - { - drgui_text_engine__update_marker_sticky_position(pTL, pMarker); - return true; - } - - return false; -} - -DRGUI_PRIVATE void drgui_text_engine__get_marker_position_relative_to_container(drgui_text_engine* pTL, drgui_text_marker* pMarker, float* pPosXOut, float* pPosYOut) -{ - if (pTL == NULL || pMarker == NULL) { - return; - } - - float posX = 0; - float posY = 0; - - if (pMarker->iRun < pTL->runCount) - { - posX = pTL->pRuns[pMarker->iRun].posX + pMarker->relativePosX; - posY = pTL->pRuns[pMarker->iRun].posY; - } - - drgui_rect textRect = drgui_text_engine_get_text_rect_relative_to_bounds(pTL); - posX += textRect.left; - posY += textRect.top; - - - if (pPosXOut) { - *pPosXOut = posX; - } - if (pPosYOut) { - *pPosYOut = posY; - } -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_point(drgui_text_engine* pTL, drgui_text_marker* pMarker, float inputPosXRelativeToText, float inputPosYRelativeToText) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - size_t iClosestRunToPoint; - if (drgui_text_engine__find_closest_run_to_point(pTL, inputPosXRelativeToText, inputPosYRelativeToText, OUT &iClosestRunToPoint)) - { - const drgui_text_run* pRun = pTL->pRuns + iClosestRunToPoint; - - pMarker->iRun = iClosestRunToPoint; - - if (inputPosXRelativeToText < pRun->posX) - { - // It's to the left of the run. - pMarker->iChar = 0; - pMarker->relativePosX = 0; - } - else if (inputPosXRelativeToText > pRun->posX + pRun->width) - { - // It's to the right of the run. It may be a new-line run. If so, we need to move the marker to the front of it, not the back. - pMarker->iChar = pRun->textLength; - pMarker->relativePosX = pRun->width; - - if (pTL->text[pRun->iChar] == '\n') { - assert(pMarker->iChar == 1); - pMarker->iChar = 0; - pMarker->relativePosX = 0; - } - } - else - { - // It's somewhere in the middle of the run. We need to handle this a little different for tab runs since they are aligned differently. - if (pTL->text[pRun->iChar] == '\n') - { - // It's a new line character. It needs to be placed at the beginning of it. - pMarker->iChar = 0; - pMarker->relativePosX = 0; - } - else if (pTL->text[pRun->iChar] == '\t') - { - // It's a tab run. - pMarker->iChar = 0; - pMarker->relativePosX = 0; - - const float tabWidth = drgui_text_engine__get_tab_width(pTL); - - float tabLeft = pRun->posX + pMarker->relativePosX; - for (/* Do Nothing*/; pMarker->iChar < pRun->textLength; ++pMarker->iChar) - { - float tabRight = tabWidth * ((pRun->posX + (tabWidth*(pMarker->iChar + 1))) / tabWidth); - if (tabRight > pRun->posX + pRun->width) { - tabRight = pRun->posX + pRun->width; - } - - if (inputPosXRelativeToText >= tabLeft && inputPosXRelativeToText <= tabRight) - { - // The input position is somewhere on top of this character. If it's positioned on the left side of the character, set the output - // value to the character at iChar. Otherwise it should be set to the character at iChar + 1. - float charBoundsRightHalf = tabLeft + ceilf(((tabRight - tabLeft) / 2.0f)); - if (inputPosXRelativeToText <= charBoundsRightHalf) { - pMarker->relativePosX = tabLeft - pRun->posX; - } else { - pMarker->relativePosX = tabRight - pRun->posX; - pMarker->iChar += 1; - } - - break; - } - - tabLeft = tabRight; - } - - // If we're past the last character in the tab run, we want to move to the start of the next run. - if (pMarker->iChar == pRun->textLength) { - drgui_text_engine__move_marker_to_first_character_of_next_run(pTL, pMarker); - } - } - else - { - // It's a standard run. - float inputPosXRelativeToRun = inputPosXRelativeToText - pRun->posX; - if (drgui_get_text_cursor_position_from_point(pRun->pFont, pTL->text + pRun->iChar, pRun->textLength, pRun->width, inputPosXRelativeToRun, OUT &pMarker->relativePosX, OUT &pMarker->iChar)) - { - // If the marker is past the last character of the run it needs to be moved to the start of the next one. - if (pMarker->iChar == pRun->textLength) { - drgui_text_engine__move_marker_to_first_character_of_next_run(pTL, pMarker); - } - } - else - { - // An error occured somehow. - return false; - } - } - } - - return true; - } - else - { - // Couldn't find a run. - return false; - } -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_left(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (pTL->runCount > 0) - { - if (pMarker->iChar > 0) - { - pMarker->iChar -= 1; - - const drgui_text_run* pRun = pTL->pRuns + pMarker->iRun; - if (pTL->text[pRun->iChar] == '\t') - { - const float tabWidth = drgui_text_engine__get_tab_width(pTL); - - if (pMarker->iChar == 0) - { - // Simple case - it's the first tab character which means the relative position is just 0. - pMarker->relativePosX = 0; - } - else - { - pMarker->relativePosX = tabWidth * ((pRun->posX + (tabWidth*(pMarker->iChar + 0))) / tabWidth); - pMarker->relativePosX -= pRun->posX; - } - } - else - { - if (!drgui_get_text_cursor_position_from_char(pRun->pFont, pTL->text + pTL->pRuns[pMarker->iRun].iChar, pMarker->iChar, OUT &pMarker->relativePosX)) { - return false; - } - } - } - else - { - // We're at the beginning of the run which means we need to transfer the cursor to the end of the previous run. - if (!drgui_text_engine__move_marker_to_last_character_of_prev_run(pTL, pMarker)) { - return false; - } - } - - drgui_text_engine__update_marker_sticky_position(pTL, pMarker); - return true; - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_right(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (pTL->runCount > 0) - { - if (pMarker->iChar + 1 < pTL->pRuns[pMarker->iRun].textLength) - { - pMarker->iChar += 1; - - const drgui_text_run* pRun = pTL->pRuns + pMarker->iRun; - if (pTL->text[pRun->iChar] == '\t') - { - const float tabWidth = drgui_text_engine__get_tab_width(pTL); - - pMarker->relativePosX = tabWidth * ((pRun->posX + (tabWidth*(pMarker->iChar + 0))) / tabWidth); - pMarker->relativePosX -= pRun->posX; - } - else - { - if (!drgui_get_text_cursor_position_from_char(pRun->pFont, pTL->text + pTL->pRuns[pMarker->iRun].iChar, pMarker->iChar, OUT &pMarker->relativePosX)) { - return false; - } - } - } - else - { - // We're at the end of the run which means we need to transfer the cursor to the beginning of the next run. - if (!drgui_text_engine__move_marker_to_first_character_of_next_run(pTL, pMarker)) { - return false; - } - } - - drgui_text_engine__update_marker_sticky_position(pTL, pMarker); - return true; - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_up(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL || pTL->runCount == 0) { - return false; - } - - return drgui_text_engine__move_marker_y(pTL, pMarker, -1); -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_down(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL || pTL->runCount == 0) { - return false; - } - - return drgui_text_engine__move_marker_y(pTL, pMarker, 1); -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_y(drgui_text_engine* pTL, drgui_text_marker* pMarker, int amount) -{ - if (pTL == NULL || pMarker == NULL || pTL->runCount == 0) { - return false; - } - - const drgui_text_run* pOldRun = pTL->pRuns + pMarker->iRun; - - int iNewLine = (int)pOldRun->iLine + amount; - if (iNewLine >= (int)drgui_text_engine_get_line_count(pTL)) { - iNewLine = (int)drgui_text_engine_get_line_count(pTL) - 1; - } - if (iNewLine < 0) { - iNewLine = 0; - } - - if ((int)pOldRun->iLine == iNewLine) { - return false; // The lines are the same. - } - - drgui_rect lineRect; - size_t iFirstRunOnLine; - size_t iLastRunOnLinePlus1; - if (drgui_text_engine__find_line_info_by_index(pTL, iNewLine, OUT &lineRect, OUT &iFirstRunOnLine, OUT &iLastRunOnLinePlus1)) - { - float newMarkerPosX = pMarker->absoluteSickyPosX; - float newMarkerPosY = lineRect.top; - drgui_text_engine__move_marker_to_point(pTL, pMarker, newMarkerPosX, newMarkerPosY); - - return true; - } - else - { - // An error occured while finding information about the line above. - return false; - } -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_end_of_line(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - size_t iLastRunOnLine; - if (drgui_text_engine__find_last_run_on_line_starting_from_run(pTL, pMarker->iRun, &iLastRunOnLine)) - { - return drgui_text_engine__move_marker_to_last_character_of_run(pTL, pMarker, iLastRunOnLine); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_start_of_line(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - size_t iFirstRunOnLine; - if (drgui_text_engine__find_first_run_on_line_starting_from_run(pTL, pMarker->iRun, &iFirstRunOnLine)) - { - return drgui_text_engine__move_marker_to_first_character_of_run(pTL, pMarker, iFirstRunOnLine); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_end_of_line_by_index(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iLine) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - size_t iFirstRun; - size_t iLastRunPlus1; - if (drgui_text_engine__find_line_info_by_index(pTL, iLine, NULL, &iFirstRun, &iLastRunPlus1)) - { - return drgui_text_engine__move_marker_to_last_character_of_run(pTL, pMarker, iLastRunPlus1 - 1); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_start_of_line_by_index(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iLine) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - size_t iFirstRun; - size_t iLastRunPlus1; - if (drgui_text_engine__find_line_info_by_index(pTL, iLine, NULL, &iFirstRun, &iLastRunPlus1)) - { - return drgui_text_engine__move_marker_to_first_character_of_run(pTL, pMarker, iFirstRun); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_end_of_text(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (pTL->runCount > 0) { - return drgui_text_engine__move_marker_to_last_character_of_run(pTL, pMarker, pTL->runCount - 1); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_start_of_text(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - return drgui_text_engine__move_marker_to_first_character_of_run(pTL, pMarker, 0); -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_last_character_of_run(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iRun) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (iRun < pTL->runCount) - { - pMarker->iRun = iRun; - pMarker->iChar = pTL->pRuns[pMarker->iRun].textLength; - pMarker->relativePosX = pTL->pRuns[pMarker->iRun].width; - - if (pMarker->iChar > 0) - { - // At this point we are located one character past the last character - we need to move it left. - return drgui_text_engine__move_marker_left(pTL, pMarker); - } - - return true; - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_first_character_of_run(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iRun) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (iRun < pTL->runCount) - { - pMarker->iRun = iRun; - pMarker->iChar = 0; - pMarker->relativePosX = 0; - - drgui_text_engine__update_marker_sticky_position(pTL, pMarker); - - return true; - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_last_character_of_prev_run(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (pMarker->iRun > 0) { - return drgui_text_engine__move_marker_to_last_character_of_run(pTL, pMarker, pMarker->iRun - 1); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_first_character_of_next_run(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return false; - } - - if (pTL->runCount > 0 && pMarker->iRun < pTL->runCount - 1) { - return drgui_text_engine__move_marker_to_first_character_of_run(pTL, pMarker, pMarker->iRun + 1); - } - - return false; -} - -DRGUI_PRIVATE bool drgui_text_engine__move_marker_to_character(drgui_text_engine* pTL, drgui_text_marker* pMarker, size_t iChar) -{ - if (pTL == NULL || pMarker == NULL || pTL->runCount == 0) { - return false; - } - - // Clamp the character to the end of the string. - if (iChar > pTL->textLength) { - iChar = pTL->textLength; - } - - drgui_text_engine__find_run_at_character(pTL, iChar, &pMarker->iRun); - - assert(pMarker->iRun < pTL->runCount); - pMarker->iChar = iChar - pTL->pRuns[pMarker->iRun].iChar; - - - // The relative position depends on whether or not the run is a tab character. - return drgui_text_engine__update_marker_relative_position(pTL, pMarker); -} - - -DRGUI_PRIVATE bool drgui_text_engine__update_marker_relative_position(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL || pTL->runCount == 0) { - return false; - } - - const drgui_text_run* pRun = pTL->pRuns + pMarker->iRun; - if (pTL->text[pRun->iChar] == '\t') - { - const float tabWidth = drgui_text_engine__get_tab_width(pTL); - - if (pMarker->iChar == 0) - { - // Simple case - it's the first tab character which means the relative position is just 0. - pMarker->relativePosX = 0; - } - else - { - pMarker->relativePosX = tabWidth * ((pRun->posX + (tabWidth*(pMarker->iChar + 0))) / tabWidth); - pMarker->relativePosX -= pRun->posX; - } - - return true; - } - else - { - return drgui_get_text_cursor_position_from_char(pRun->pFont, pTL->text + pTL->pRuns[pMarker->iRun].iChar, pMarker->iChar, OUT &pMarker->relativePosX); - } -} - -DRGUI_PRIVATE void drgui_text_engine__update_marker_sticky_position(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL) { - return; - } - - pMarker->absoluteSickyPosX = pTL->pRuns[pMarker->iRun].posX + pMarker->relativePosX; -} - -DRGUI_PRIVATE size_t drgui_text_engine__get_marker_absolute_char_index(drgui_text_engine* pTL, drgui_text_marker* pMarker) -{ - if (pTL == NULL || pMarker == NULL || pTL->runCount == 0) { - return 0; - } - - return pTL->pRuns[pMarker->iRun].iChar + pMarker->iChar; -} - - -DRGUI_PRIVATE bool drgui_text_engine__has_spacing_between_selection_markers(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return false; - } - - return (pTL->cursor.iRun != pTL->selectionAnchor.iRun || pTL->cursor.iChar != pTL->selectionAnchor.iChar); -} - -DRGUI_PRIVATE size_t drgui_text_engine__split_text_run_by_selection(drgui_text_engine* pTL, drgui_text_run* pRunToSplit, drgui_text_run pSubRunsOut[3]) -{ - if (pTL == NULL || pRunToSplit == NULL || pSubRunsOut == NULL) { - return 0; - } - - drgui_text_marker* pSelectionMarker0 = &pTL->selectionAnchor; - drgui_text_marker* pSelectionMarker1 = &pTL->cursor; - if (pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar > pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar) - { - drgui_text_marker* temp = pSelectionMarker0; - pSelectionMarker0 = pSelectionMarker1; - pSelectionMarker1 = temp; - } - - drgui_text_run* pSelectionRun0 = pTL->pRuns + pSelectionMarker0->iRun; - drgui_text_run* pSelectionRun1 = pTL->pRuns + pSelectionMarker1->iRun; - - size_t iSelectionChar0 = pSelectionRun0->iChar + pSelectionMarker0->iChar; - size_t iSelectionChar1 = pSelectionRun1->iChar + pSelectionMarker1->iChar; - - if (drgui_text_engine_is_anything_selected(pTL)) - { - if (pRunToSplit->iChar < iSelectionChar1 && pRunToSplit->iCharEnd > iSelectionChar0) - { - // The run is somewhere inside the selection region. - for (int i = 0; i < 3; ++i) { - pSubRunsOut[i] = *pRunToSplit; - } - - if (pRunToSplit->iChar >= iSelectionChar0) - { - // The first part of the run is selected. - if (pRunToSplit->iCharEnd <= iSelectionChar1) - { - // The entire run is selected. - pSubRunsOut[0].backgroundColor = pTL->selectionBackgroundColor; - return 1; - } - else - { - // The head part of the run is selected, and the tail is deselected. - - // Head. - pSubRunsOut[0].backgroundColor = pTL->selectionBackgroundColor; - pSubRunsOut[0].iCharEnd = iSelectionChar1; - pSubRunsOut[0].width = pSelectionMarker1->relativePosX; - pSubRunsOut[0].text = pTL->text + pSubRunsOut[0].iChar; - pSubRunsOut[0].textLength = pSubRunsOut[0].iCharEnd - pSubRunsOut[0].iChar; - - // Tail. - pSubRunsOut[1].iChar = iSelectionChar1; - pSubRunsOut[1].width = pRunToSplit->width - pSelectionMarker1->relativePosX; - pSubRunsOut[1].posX = pSubRunsOut[0].posX + pSubRunsOut[0].width; - pSubRunsOut[1].text = pTL->text + pSubRunsOut[1].iChar; - pSubRunsOut[1].textLength = pSubRunsOut[1].iCharEnd - pSubRunsOut[1].iChar; - - return 2; - } - } - else - { - // The first part of the run is deselected. There will be at least 2, but possibly 3 sub-runs in this case. - if (pRunToSplit->iCharEnd <= iSelectionChar1) - { - // The head of the run is deselected and the tail is selected. - - // Head. - pSubRunsOut[0].iCharEnd = iSelectionChar0; - pSubRunsOut[0].width = pSelectionMarker0->relativePosX; - pSubRunsOut[0].text = pTL->text + pSubRunsOut[0].iChar; - pSubRunsOut[0].textLength = pSubRunsOut[0].iCharEnd - pSubRunsOut[0].iChar; - - // Tail. - pSubRunsOut[1].backgroundColor = pTL->selectionBackgroundColor; - pSubRunsOut[1].iChar = iSelectionChar0; - pSubRunsOut[1].width = pRunToSplit->width - pSubRunsOut[0].width; - pSubRunsOut[1].posX = pSubRunsOut[0].posX + pSubRunsOut[0].width; - pSubRunsOut[1].text = pTL->text + pSubRunsOut[1].iChar; - pSubRunsOut[1].textLength = pSubRunsOut[1].iCharEnd - pSubRunsOut[1].iChar; - - return 2; - } - else - { - // The head and tail are both deselected, and the middle section is selected. - - // Head. - pSubRunsOut[0].iCharEnd = iSelectionChar0; - pSubRunsOut[0].width = pSelectionMarker0->relativePosX; - pSubRunsOut[0].text = pTL->text + pSubRunsOut[0].iChar; - pSubRunsOut[0].textLength = pSubRunsOut[0].iCharEnd - pSubRunsOut[0].iChar; - - // Mid. - pSubRunsOut[1].iChar = iSelectionChar0; - pSubRunsOut[1].iCharEnd = iSelectionChar1; - pSubRunsOut[1].backgroundColor = pTL->selectionBackgroundColor; - pSubRunsOut[1].width = pSelectionMarker1->relativePosX - pSelectionMarker0->relativePosX; - pSubRunsOut[1].posX = pSubRunsOut[0].posX + pSubRunsOut[0].width; - pSubRunsOut[1].text = pTL->text + pSubRunsOut[1].iChar; - pSubRunsOut[1].textLength = pSubRunsOut[1].iCharEnd - pSubRunsOut[1].iChar; - - // Tail. - pSubRunsOut[2].iChar = iSelectionChar1; - pSubRunsOut[2].width = pRunToSplit->width - pSelectionMarker1->relativePosX; - pSubRunsOut[2].posX = pSubRunsOut[1].posX + pSubRunsOut[1].width; - pSubRunsOut[2].text = pTL->text + pSubRunsOut[2].iChar; - pSubRunsOut[2].textLength = pSubRunsOut[2].iCharEnd - pSubRunsOut[2].iChar; - - return 3; - } - } - } - } - - // If we get here it means the run is not within the selected region. - pSubRunsOut[0] = *pRunToSplit; - return 1; -} - -#if 0 -DRGUI_PRIVATE bool drgui_text_engine__is_run_selected(drgui_text_engine* pTL, unsigned int iRun) -{ - if (drgui_text_engine_is_anything_selected(pTL)) - { - drgui_text_marker* pSelectionMarker0; - drgui_text_marker* pSelectionMarker1; - if (!drgui_text_engine__get_selection_markers(pTL, &pSelectionMarker0, &pSelectionMarker1)) { - return false; - } - - unsigned int iSelectionChar0 = pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar; - unsigned int iSelectionChar1 = pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar; - - return pTL->pRuns[iRun].iChar < iSelectionChar1 && pTL->pRuns[iRun].iCharEnd > iSelectionChar0; - } - - return false; -} -#endif - -DRGUI_PRIVATE bool drgui_text_engine__get_selection_markers(drgui_text_engine* pTL, drgui_text_marker** ppSelectionMarker0Out, drgui_text_marker** ppSelectionMarker1Out) -{ - bool result = false; - - drgui_text_marker* pSelectionMarker0 = NULL; - drgui_text_marker* pSelectionMarker1 = NULL; - if (pTL != NULL && drgui_text_engine_is_anything_selected(pTL)) - { - pSelectionMarker0 = &pTL->selectionAnchor; - pSelectionMarker1 = &pTL->cursor; - if (pTL->pRuns[pSelectionMarker0->iRun].iChar + pSelectionMarker0->iChar > pTL->pRuns[pSelectionMarker1->iRun].iChar + pSelectionMarker1->iChar) - { - drgui_text_marker* temp = pSelectionMarker0; - pSelectionMarker0 = pSelectionMarker1; - pSelectionMarker1 = temp; - } - - result = true; - } - - if (ppSelectionMarker0Out) { - *ppSelectionMarker0Out = pSelectionMarker0; - } - if (ppSelectionMarker1Out) { - *ppSelectionMarker1Out = pSelectionMarker1; - } - - return result; -} - - -DRGUI_PRIVATE bool drgui_text_engine__first_line(drgui_text_engine* pTL, drgui_text_engine_line* pLine) -{ - if (pTL == NULL || pLine == NULL || pTL->runCount == 0) { - return false; - } - - pLine->index = 0; - pLine->posY = 0; - pLine->height = 0; - pLine->iFirstRun = 0; - pLine->iLastRun = 0; - - // We need to find the last run in the line and the height. The height is determined by the run with the largest height. - while (pLine->iLastRun < pTL->runCount) - { - if (pLine->height < pTL->pRuns[pLine->iLastRun].height) { - pLine->height = pTL->pRuns[pLine->iLastRun].height; - } - - pLine->iLastRun += 1; - - if (pTL->pRuns[pLine->iLastRun].iLine != pLine->index) { - break; - } - } - - if (pLine->iLastRun > 0) { - pLine->iLastRun -= 1; - } - - return true; -} - -DRGUI_PRIVATE bool drgui_text_engine__next_line(drgui_text_engine* pTL, drgui_text_engine_line* pLine) -{ - if (pTL == NULL || pLine == NULL || pTL->runCount == 0) { - return false; - } - - // If there's no more runs, there is no next line. - if (pLine->iLastRun == pTL->runCount - 1) { - return false; - } - - pLine->index += 1; - pLine->posY += pLine->height; - pLine->height = 0; - pLine->iFirstRun = pLine->iLastRun + 1; - pLine->iLastRun = pLine->iFirstRun; - - while (pLine->iLastRun < pTL->runCount) - { - if (pLine->height < pTL->pRuns[pLine->iLastRun].height) { - pLine->height = pTL->pRuns[pLine->iLastRun].height; - } - - pLine->iLastRun += 1; - - if (pTL->pRuns[pLine->iLastRun].iLine != pLine->index) { - break; - } - } - - if (pLine->iLastRun > 0) { - pLine->iLastRun -= 1; - } - - return true; -} - -DRGUI_PRIVATE void drgui_text_engine__trim_undo_stack(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - while (pTL->undoStackCount > pTL->iUndoState) - { - unsigned int iLastItem = pTL->undoStackCount - 1; - - drgui_text_engine__uninit_undo_state(pTL->pUndoStack + iLastItem); - pTL->undoStackCount -= 1; - } -} - -DRGUI_PRIVATE bool drgui_text_engine__diff_states(drgui_text_engine_state* pPrevState, drgui_text_engine_state* pCurrentState, drgui_text_engine_undo_state* pUndoStateOut) -{ - if (pPrevState == NULL || pCurrentState == NULL || pUndoStateOut == NULL) { - return false; - } - - if (pPrevState->text == NULL || pCurrentState->text == NULL) { - return false; - } - - const char* prevText = pPrevState->text; - const char* currText = pCurrentState->text; - - const size_t prevLen = strlen(prevText); - const size_t currLen = strlen(currText); - - - // The first step is to find the position of the first differing character. - size_t sameChCountStart; - for (sameChCountStart = 0; sameChCountStart < prevLen && sameChCountStart < currLen; ++sameChCountStart) - { - char prevCh = prevText[sameChCountStart]; - char currCh = currText[sameChCountStart]; - - if (prevCh != currCh) { - break; - } - } - - // The next step is to find the position of the last differing character. - size_t sameChCountEnd; - for (sameChCountEnd = 0; sameChCountEnd < prevLen && sameChCountEnd < currLen; ++sameChCountEnd) - { - // Don't move beyond the first differing character. - if (prevLen - sameChCountEnd <= sameChCountStart || - currLen - sameChCountEnd <= sameChCountStart) - { - break; - } - - char prevCh = prevText[prevLen - sameChCountEnd - 1]; - char currCh = currText[currLen - sameChCountEnd - 1]; - - if (prevCh != currCh) { - break; - } - } - - - // At this point we know which section of the text is different. We now need to initialize the undo state object. - pUndoStateOut->diffPos = sameChCountStart; - pUndoStateOut->newState = *pCurrentState; - pUndoStateOut->newState.text = NULL; - pUndoStateOut->oldState = *pPrevState; - pUndoStateOut->oldState.text = NULL; - - size_t oldTextLen = prevLen - sameChCountStart - sameChCountEnd; - pUndoStateOut->oldText = (char*)malloc(oldTextLen + 1); - drgui__strncpy_s(pUndoStateOut->oldText, oldTextLen + 1, prevText + sameChCountStart, oldTextLen); - - size_t newTextLen = currLen - sameChCountStart - sameChCountEnd; - pUndoStateOut->newText = (char*)malloc(newTextLen + 1); - drgui__strncpy_s(pUndoStateOut->newText, newTextLen + 1, currText + sameChCountStart, newTextLen); - - return true; -} - -DRGUI_PRIVATE void drgui_text_engine__uninit_undo_state(drgui_text_engine_undo_state* pUndoState) -{ - if (pUndoState == NULL) { - return; - } - - free(pUndoState->oldText); - pUndoState->oldText = NULL; - - free(pUndoState->newText); - pUndoState->newText = NULL; -} - -DRGUI_PRIVATE void drgui_text_engine__push_undo_state(drgui_text_engine* pTL, drgui_text_engine_undo_state* pUndoState) -{ - if (pTL == NULL || pUndoState == NULL) { - return; - } - - assert(pTL->iUndoState == pTL->undoStackCount); - - - drgui_text_engine_undo_state* pOldStack = pTL->pUndoStack; - drgui_text_engine_undo_state* pNewStack = (drgui_text_engine_undo_state*)malloc(sizeof(*pNewStack) * (pTL->undoStackCount + 1)); - - if (pTL->undoStackCount > 0) { - memcpy(pNewStack, pOldStack, sizeof(*pNewStack) * (pTL->undoStackCount)); - } - - pNewStack[pTL->undoStackCount] = *pUndoState; - pTL->pUndoStack = pNewStack; - pTL->undoStackCount += 1; - pTL->iUndoState += 1; - - if (pTL->onUndoPointChanged) { - pTL->onUndoPointChanged(pTL, pTL->iUndoState); - } - - free(pOldStack); -} - -DRGUI_PRIVATE void drgui_text_engine__apply_undo_state(drgui_text_engine* pTL, drgui_text_engine_undo_state* pUndoState) -{ - if (pTL == NULL || pUndoState == NULL) { - return; - } - - // When undoing we want to remove the new text and replace it with the old text. - - size_t iFirstCh = pUndoState->diffPos; - size_t iLastChPlus1 = pUndoState->diffPos + strlen(pUndoState->newText); - size_t bytesToRemove = iLastChPlus1 - iFirstCh; - if (bytesToRemove > 0) - { - memmove(pTL->text + iFirstCh, pTL->text + iLastChPlus1, pTL->textLength - iLastChPlus1); - pTL->textLength -= bytesToRemove; - pTL->text[pTL->textLength] = '\0'; - } - - // TODO: This needs improving because it results in multiple onTextChanged and onDirty events being posted. - - // Insert the old text. - drgui_text_engine_insert_text(pTL, pUndoState->oldText, pUndoState->diffPos); - - - // The layout will have changed so it needs to be refreshed. - drgui_text_engine__refresh(pTL); - - - // Markers needs to be updated after refreshing the layout. - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, pUndoState->oldState.cursorPos); - drgui_text_engine__move_marker_to_character(pTL, &pTL->selectionAnchor, pUndoState->oldState.selectionAnchorPos); - - // The cursor's sticky position needs to be updated whenever the text is edited. - drgui_text_engine__update_marker_sticky_position(pTL, &pTL->cursor); - - // Ensure we mark the text as selected if appropriate. - pTL->isAnythingSelected = pUndoState->oldState.isAnythingSelected; - - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_cursor_move(pTL); - - if (pTL->onDirty) { - pTL->onDirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - -DRGUI_PRIVATE void drgui_text_engine__apply_redo_state(drgui_text_engine* pTL, drgui_text_engine_undo_state* pUndoState) -{ - if (pTL == NULL || pUndoState == NULL) { - return; - } - - // An redo is just the opposite of an undo. We want to remove the old text and replace it with the new text. - - size_t iFirstCh = pUndoState->diffPos; - size_t iLastChPlus1 = pUndoState->diffPos + strlen(pUndoState->oldText); - size_t bytesToRemove = iLastChPlus1 - iFirstCh; - if (bytesToRemove > 0) - { - memmove(pTL->text + iFirstCh, pTL->text + iLastChPlus1, pTL->textLength - iLastChPlus1); - pTL->textLength -= bytesToRemove; - pTL->text[pTL->textLength] = '\0'; - } - - // TODO: This needs improving because it results in multiple onTextChanged and onDirty events being posted. - - // Insert the new text. - drgui_text_engine_insert_text(pTL, pUndoState->newText, pUndoState->diffPos); - - - // The layout will have changed so it needs to be refreshed. - drgui_text_engine__refresh(pTL); - - - // Markers needs to be updated after refreshing the layout. - drgui_text_engine__move_marker_to_character(pTL, &pTL->cursor, pUndoState->newState.cursorPos); - drgui_text_engine__move_marker_to_character(pTL, &pTL->selectionAnchor, pUndoState->newState.selectionAnchorPos); - - // The cursor's sticky position needs to be updated whenever the text is edited. - drgui_text_engine__update_marker_sticky_position(pTL, &pTL->cursor); - - // Ensure we mark the text as selected if appropriate. - pTL->isAnythingSelected = pUndoState->newState.isAnythingSelected; - - - if (pTL->onTextChanged) { - pTL->onTextChanged(pTL); - } - - drgui_text_engine__on_cursor_move(pTL); - - if (pTL->onDirty) { - pTL->onDirty(pTL, drgui_text_engine__local_rect(pTL)); - } -} - - -DRGUI_PRIVATE drgui_rect drgui_text_engine__local_rect(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - return drgui_make_rect(0, 0, pTL->containerWidth, pTL->containerHeight); -} - - -DRGUI_PRIVATE void drgui_text_engine__on_cursor_move(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - // When the cursor moves we want to reset the cursor's blink state. - pTL->timeToNextCursorBlink = pTL->cursorBlinkRate; - pTL->isCursorBlinkOn = true; - - if (pTL->onCursorMove) { - pTL->onCursorMove(pTL); - } - - drgui_text_engine__on_dirty(pTL, drgui_text_engine_get_cursor_rect(pTL)); -} - -DRGUI_PRIVATE void drgui_text_engine__on_dirty(drgui_text_engine* pTL, drgui_rect rect) -{ - drgui_text_engine__begin_dirty(pTL); - { - pTL->accumulatedDirtyRect = drgui_rect_union(pTL->accumulatedDirtyRect, rect); - } - drgui_text_engine__end_dirty(pTL); -} - -DRGUI_PRIVATE void drgui_text_engine__begin_dirty(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - pTL->dirtyCounter += 1; -} - -DRGUI_PRIVATE void drgui_text_engine__end_dirty(drgui_text_engine* pTL) -{ - if (pTL == NULL) { - return; - } - - assert(pTL->dirtyCounter > 0); - - pTL->dirtyCounter -= 1; - - if (pTL->dirtyCounter == 0) { - if (pTL->onDirty) { - pTL->onDirty(pTL, pTL->accumulatedDirtyRect); - } - - pTL->accumulatedDirtyRect = drgui_make_inside_out_rect(); - } -} -#endif //DR_GUI_IMPLEMENTATION -#endif - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Scrollbar -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef drgui_scrollbar_h -#define drgui_scrollbar_h - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum -{ - drgui_sb_orientation_none, - drgui_sb_orientation_vertical, - drgui_sb_orientation_horizontal - -} drgui_sb_orientation; - -typedef void (* drgui_sb_on_scroll_proc)(drgui_element* pSBElement, int scrollPos); - - -/// Creates a scrollbar element. -drgui_element* drgui_create_scrollbar(drgui_context* pContext, drgui_element* pParent, drgui_sb_orientation orientation, size_t extraDataSize, const void* pExtraData); - -/// Deletes the given scrollbar element. -void drgui_delete_scrollbar(drgui_element* pSBElement); - - -/// Retrieves the size of the extra data associated with the scrollbar. -size_t drgui_sb_get_extra_data_size(drgui_element* pSBElement); - -/// Retrieves a pointer to the extra data associated with the scrollbar. -void* drgui_sb_get_extra_data(drgui_element* pSBElement); - - -/// Retrieves the orientation of the given scrollbar. -drgui_sb_orientation drgui_sb_get_orientation(drgui_element* pSBElement); - - -/// Sets the given scrollbar's range. -void drgui_sb_set_range(drgui_element* pSBElement, int rangeMin, int rangeMax); - -/// Retrieves the given scrollbar's range. -void drgui_sb_get_range(drgui_element* pSBElement, int* pRangeMinOut, int* pRangeMaxOut); - - -/// Sets the page size of the given scrollbar's page. -void drgui_sb_set_page_size(drgui_element* pSBElement, int pageSize); - -/// Retrieves the page size of the given scrollbar's page. -int drgui_sb_get_page_size(drgui_element* pSBElement); - - -/// Sets the range and page size. -/// -/// @remarks -/// Use this when both the range and page size need to be updated at the same time. -void drgui_sb_set_range_and_page_size(drgui_element* pSBElement, int rangeMin, int rangeMax, int pageSize); - - -/// Explicitly sets the scroll position. -/// -/// @remarks -/// This will move the thumb, but not post the on_scroll event. -/// @par -/// The scroll position will be clamped to the current range, minus the page size. -void drgui_sb_set_scroll_position(drgui_element* pSBElement, int position); - -/// Retrieves the scroll position. -int drgui_sb_get_scroll_position(drgui_element* pSBElement); - - -/// Scrolls by the given amount. -/// -/// @remarks -/// If the resulting scroll position differs from the old one, the on on_scroll event will be posted. -void drgui_sb_scroll(drgui_element* pSBElement, int offset); - -/// Scrolls to the given position. -/// -/// @remarks -/// This differs from drgui_sb_set_scroll_position in that it will post the on_scroll event. -/// @par -/// Note that the actual maximum scrollable position is equal to the maximum range value minus the page size. -void drgui_sb_scroll_to(drgui_element* pSBElement, int newScrollPos); - - -/// Enables auto-hiding of the thumb. -void drgui_sb_enable_thumb_auto_hide(drgui_element* pSBElement); - -/// Disables auto-hiding of the thumb. -void drgui_sb_disable_thumb_auto_hide(drgui_element* pSBElement); - -/// Determines whether or not thumb auto-hiding is enabled. -bool drgui_sb_is_thumb_auto_hide_enabled(drgui_element* pSBElement); - -/// Determines whether or not the thumb is visible. -/// -/// @remarks -/// This is determined by whether or not the thumb is set to auto-hide and the current range and page size. -bool drgui_sb_is_thumb_visible(drgui_element* pSBElement); - - -/// Sets the mouse wheel scale. -/// -/// @remarks -/// Set this to a negative value to reverse the direction. -void drgui_sb_set_mouse_wheel_scele(drgui_element* pSBElement, int scale); - -/// Retrieves the mouse wheel scale. -int drgui_sb_get_mouse_wheel_scale(drgui_element* pSBElement); - - -/// Sets the color of the track. -void drgui_sb_set_track_color(drgui_element* pSBElement, drgui_color color); - -/// Sets the default color of the thumb. -void drgui_sb_set_default_thumb_color(drgui_element* pSBElement, drgui_color color); - -/// Sets the hovered color of the thumb. -void drgui_sb_set_hovered_thumb_color(drgui_element* pSBElement, drgui_color color); - -/// Sets the pressed color of the thumb. -void drgui_sb_set_pressed_thumb_color(drgui_element* pSBElement, drgui_color color); - - -/// Sets the function to call when the given scrollbar is scrolled. -void drgui_sb_set_on_scroll(drgui_element* pSBElement, drgui_sb_on_scroll_proc onScroll); - -/// Retrieves the function call when the given scrollbar is scrolled. -drgui_sb_on_scroll_proc drgui_sb_get_on_scroll(drgui_element* pSBElement); - - -/// Calculates the relative rectangle of the given scrollbar's thumb. -drgui_rect drgui_sb_get_thumb_rect(drgui_element* pSBElement); - - -/// Called when the size event needs to be processed for the given scrollbar. -void drgui_sb_on_size(drgui_element* pSBElement, float newWidth, float newHeight); - -/// Called when the mouse leave event needs to be processed for the given scrollbar. -void drgui_sb_on_mouse_leave(drgui_element* pSBElement); - -/// Called when the mouse move event needs to be processed for the given scrollbar. -void drgui_sb_on_mouse_move(drgui_element* pSBElement, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button down event needs to be processed for the given scrollbar. -void drgui_sb_on_mouse_button_down(drgui_element* pSBElement, int button, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button up event needs to be processed for the given scrollbar. -void drgui_sb_on_mouse_button_up(drgui_element* pSBElement, int button, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse wheel event needs to be processed for the given scrollbar. -void drgui_sb_on_mouse_wheel(drgui_element* pSBElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the paint event needs to be processed. -void drgui_sb_on_paint(drgui_element* pSBElement, drgui_rect relativeClippingRect, void* pPaintData); - - -#ifdef __cplusplus -} -#endif -#endif //drgui_scrollbar_h - - -#ifdef DR_GUI_IMPLEMENTATION - -#define DRGUI_MIN_SCROLLBAR_THUMB_SIZE 16 - -typedef struct -{ - /// The orientation. - drgui_sb_orientation orientation; - - /// The minimum scroll range. - int rangeMin; - - /// The maximum scroll range. - int rangeMax; - - /// The page size. - int pageSize; - - /// The current scroll position. - int scrollPos; - - /// Whether or not to auto-hide the thumb. - bool autoHideThumb; - - /// The mouse wheel scale. - int mouseWheelScale; - - /// The color of the track. - drgui_color trackColor; - - /// The color of the thumb while not hovered or pressed. - drgui_color thumbColor; - - /// The color of the thumb while hovered. - drgui_color thumbColorHovered; - - /// The color of the thumb while pressed. - drgui_color thumbColorPressed; - - /// The function to call when the scroll position changes. - drgui_sb_on_scroll_proc onScroll; - - - /// The current size of the thumb. - float thumbSize; - - /// The current position of the thumb. - float thumbPos; - - /// The amount of padding between the edge of the scrollbar and the thumb. - float thumbPadding; - - /// Whether or not we are hovered over the thumb. - bool thumbHovered; - - /// Whether or not the thumb is pressed. - bool thumbPressed; - - /// The relative position of the mouse on the x axis at the time the thumb was pressed with the mouse. - float thumbClickPosX; - - /// The relative position of the mouse on the y axis at the time the thumb was pressed with the mouse. - float thumbClickPosY; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data. - char pExtraData[1]; - -} drgui_scrollbar; - - -/// Refreshes the given scrollbar's thumb layout and redraws it. -DRGUI_PRIVATE void drgui_sb_refresh_thumb(drgui_element* pSBElement); - -/// Calculates the size of the thumb. This does not change the state of the thumb. -DRGUI_PRIVATE float drgui_sb_calculate_thumb_size(drgui_element* pSBElement); - -/// Calculates the position of the thumb. This does not change the state of the thumb. -DRGUI_PRIVATE float drgui_sb_calculate_thumb_position(drgui_element* pSBElement); - -/// Retrieves the size of the given scrollbar's track. For vertical alignments, it's the height of the element, otherwise it's the width. -DRGUI_PRIVATE float drgui_sb_get_track_size(drgui_element* pSBElement); - -/// Makes the given point that's relative to the given scrollbar relative to it's thumb. -DRGUI_PRIVATE void drgui_sb_make_relative_to_thumb(drgui_element* pSBElement, float* pPosX, float* pPosY); - -/// Calculates the scroll position based on the current position of the thumb. This is used for scrolling while dragging the thumb. -DRGUI_PRIVATE int drgui_sb_calculate_scroll_pos_from_thumb_pos(drgui_element* pScrollba, float thumbPosr); - -/// Simple clamp function. -DRGUI_PRIVATE float drgui_sb_clampf(float n, float lower, float upper) -{ - return n <= lower ? lower : n >= upper ? upper : n; -} - -/// Simple clamp function. -DRGUI_PRIVATE int drgui_sb_clampi(int n, int lower, int upper) -{ - return n <= lower ? lower : n >= upper ? upper : n; -} - -/// Simple max function. -DRGUI_PRIVATE int drgui_sb_maxi(int x, int y) -{ - return (x > y) ? x : y; -} - - -drgui_element* drgui_create_scrollbar(drgui_context* pContext, drgui_element* pParent, drgui_sb_orientation orientation, size_t extraDataSize, const void* pExtraData) -{ - if (pContext == NULL || orientation == drgui_sb_orientation_none) { - return NULL; - } - - drgui_element* pSBElement = drgui_create_element(pContext, pParent, sizeof(drgui_scrollbar) + extraDataSize, NULL); - if (pSBElement == NULL) { - return NULL; - } - - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - assert(pSB != NULL); - - pSB->orientation = orientation; - pSB->rangeMin = 0; - pSB->rangeMax = 0; - pSB->pageSize = 0; - pSB->scrollPos = 0; - pSB->autoHideThumb = true; - pSB->mouseWheelScale = 1; - pSB->trackColor = drgui_rgb(80, 80, 80); - pSB->thumbColor = drgui_rgb(112, 112, 112); - pSB->thumbColorHovered = drgui_rgb(144, 144, 144); - pSB->thumbColorPressed = drgui_rgb(180, 180, 180); - pSB->onScroll = NULL; - - pSB->thumbSize = DRGUI_MIN_SCROLLBAR_THUMB_SIZE; - pSB->thumbPos = 0; - pSB->thumbPadding = 2; - pSB->thumbHovered = false; - pSB->thumbPressed = false; - pSB->thumbClickPosX = 0; - pSB->thumbClickPosY = 0; - - pSB->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pSB->pExtraData, pExtraData, extraDataSize); - } - - - // Default event handlers. - drgui_set_on_size(pSBElement, drgui_sb_on_size); - drgui_set_on_mouse_leave(pSBElement, drgui_sb_on_mouse_leave); - drgui_set_on_mouse_move(pSBElement, drgui_sb_on_mouse_move); - drgui_set_on_mouse_button_down(pSBElement, drgui_sb_on_mouse_button_down); - drgui_set_on_mouse_button_up(pSBElement, drgui_sb_on_mouse_button_up); - drgui_set_on_mouse_wheel(pSBElement, drgui_sb_on_mouse_wheel); - drgui_set_on_paint(pSBElement, drgui_sb_on_paint); - - - return pSBElement; -} - -void drgui_delete_scrollbar(drgui_element* pSBElement) -{ - if (pSBElement == NULL) { - return; - } - - drgui_delete_element(pSBElement); -} - - -size_t drgui_sb_get_extra_data_size(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return 0; - } - - return pSB->extraDataSize; -} - -void* drgui_sb_get_extra_data(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return NULL; - } - - return pSB->pExtraData; -} - - -drgui_sb_orientation drgui_sb_get_orientation(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return drgui_sb_orientation_none; - } - - return pSB->orientation; -} - - -void drgui_sb_set_range(drgui_element* pSBElement, int rangeMin, int rangeMax) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->rangeMin = rangeMin; - pSB->rangeMax = rangeMax; - - - // Make sure the scroll position is still valid. - drgui_sb_scroll_to(pSBElement, drgui_sb_get_scroll_position(pSBElement)); - - // The thumb may have changed, so refresh it. - drgui_sb_refresh_thumb(pSBElement); -} - -void drgui_sb_get_range(drgui_element* pSBElement, int* pRangeMinOut, int* pRangeMaxOut) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - if (pRangeMinOut != NULL) { - *pRangeMinOut = pSB->rangeMin; - } - - if (pRangeMaxOut != NULL) { - *pRangeMaxOut = pSB->rangeMax; - } -} - - -void drgui_sb_set_page_size(drgui_element* pSBElement, int pageSize) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->pageSize = pageSize; - - - // Make sure the scroll position is still valid. - drgui_sb_scroll_to(pSBElement, drgui_sb_get_scroll_position(pSBElement)); - - // The thumb may have changed, so refresh it. - drgui_sb_refresh_thumb(pSBElement); -} - -int drgui_sb_get_page_size(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return 0; - } - - return pSB->pageSize; -} - - -void drgui_sb_set_range_and_page_size(drgui_element* pSBElement, int rangeMin, int rangeMax, int pageSize) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->rangeMin = rangeMin; - pSB->rangeMax = rangeMax; - pSB->pageSize = pageSize; - - - // Make sure the scroll position is still valid. - drgui_sb_scroll_to(pSBElement, drgui_sb_get_scroll_position(pSBElement)); - - // The thumb may have changed, so refresh it. - drgui_sb_refresh_thumb(pSBElement); -} - - -void drgui_sb_set_scroll_position(drgui_element* pSBElement, int position) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - int newScrollPos = drgui_sb_clampi(position, pSB->rangeMin, drgui_sb_maxi(0, pSB->rangeMax - pSB->pageSize + 1)); - if (newScrollPos != pSB->scrollPos) - { - pSB->scrollPos = newScrollPos; - - // The position of the thumb has changed, so refresh it. - drgui_sb_refresh_thumb(pSBElement); - } -} - -int drgui_sb_get_scroll_position(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return 0; - } - - return pSB->scrollPos; -} - - -void drgui_sb_scroll(drgui_element* pSBElement, int offset) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - drgui_sb_scroll_to(pSBElement, pSB->scrollPos + offset); -} - -void drgui_sb_scroll_to(drgui_element* pSBElement, int newScrollPos) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - int oldScrollPos = pSB->scrollPos; - drgui_sb_set_scroll_position(pSBElement, newScrollPos); - - if (oldScrollPos != pSB->scrollPos) - { - if (pSB->onScroll) { - pSB->onScroll(pSBElement, pSB->scrollPos); - } - } -} - - -void drgui_sb_enable_thumb_auto_hide(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - if (pSB->autoHideThumb != true) - { - pSB->autoHideThumb = true; - - // The thumb needs to be refreshed in order to show the correct state. - drgui_sb_refresh_thumb(pSBElement); - } -} - -void drgui_sb_disable_thumb_auto_hide(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - if (pSB->autoHideThumb != false) - { - pSB->autoHideThumb = false; - - // The thumb needs to be refreshed in order to show the correct state. - drgui_sb_refresh_thumb(pSBElement); - } -} - -bool drgui_sb_is_thumb_auto_hide_enabled(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return false; - } - - return pSB->autoHideThumb; -} - -bool drgui_sb_is_thumb_visible(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return false; - } - - // Always visible if auto-hiding is disabled. - if (!pSB->autoHideThumb) { - return true; - } - - return pSB->pageSize < (pSB->rangeMax - pSB->rangeMin + 1) && pSB->pageSize > 0; -} - - -void drgui_sb_set_mouse_wheel_scele(drgui_element* pSBElement, int scale) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->mouseWheelScale = scale; -} - -int drgui_sb_get_mouse_wheel_scale(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return 1; - } - - return pSB->mouseWheelScale; -} - - -void drgui_sb_set_track_color(drgui_element* pSBElement, drgui_color color) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->trackColor = color; -} - -void drgui_sb_set_default_thumb_color(drgui_element* pSBElement, drgui_color color) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->thumbColor = color; -} - -void drgui_sb_set_hovered_thumb_color(drgui_element* pSBElement, drgui_color color) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->thumbColorHovered = color; -} - -void drgui_sb_set_pressed_thumb_color(drgui_element* pSBElement, drgui_color color) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->thumbColorPressed = color; -} - - -void drgui_sb_set_on_scroll(drgui_element* pSBElement, drgui_sb_on_scroll_proc onScroll) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - pSB->onScroll = onScroll; -} - -drgui_sb_on_scroll_proc drgui_sb_get_on_scroll(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return NULL; - } - - return pSB->onScroll; -} - - -drgui_rect drgui_sb_get_thumb_rect(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - drgui_rect rect = {0, 0, 0, 0}; - rect.left = pSB->thumbPadding; - rect.top = pSB->thumbPadding; - - if (pSB->orientation == drgui_sb_orientation_vertical) - { - // Vertical. - rect.left = pSB->thumbPadding; - rect.right = drgui_get_width(pSBElement) - pSB->thumbPadding; - rect.top = pSB->thumbPadding + pSB->thumbPos; - rect.bottom = rect.top + pSB->thumbSize; - } - else - { - // Horizontal. - rect.left = pSB->thumbPadding + pSB->thumbPos; - rect.right = rect.left + pSB->thumbSize; - rect.top = pSB->thumbPadding; - rect.bottom = drgui_get_height(pSBElement) - pSB->thumbPadding; - } - - return rect; -} - - -void drgui_sb_on_size(drgui_element* pSBElement, float newWidth, float newHeight) -{ - (void)newWidth; - (void)newHeight; - - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - drgui_sb_refresh_thumb(pSBElement); -} - -void drgui_sb_on_mouse_leave(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - bool needsRedraw = false; - if (pSB->thumbHovered) - { - needsRedraw = true; - pSB->thumbHovered = false; - } - - if (pSB->thumbPressed) - { - needsRedraw = true; - pSB->thumbPressed = false; - } - - if (needsRedraw) { - drgui_dirty(pSBElement, drgui_sb_get_thumb_rect(pSBElement)); - } -} - -void drgui_sb_on_mouse_move(drgui_element* pSBElement, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - if (pSB->thumbPressed) - { - // The thumb is pressed. Drag it. - float thumbRelativeMousePosX = (float)relativeMousePosX; - float thumbRelativeMousePosY = (float)relativeMousePosY; - drgui_sb_make_relative_to_thumb(pSBElement, &thumbRelativeMousePosX, &thumbRelativeMousePosY); - - float dragOffsetX = thumbRelativeMousePosX - pSB->thumbClickPosX; - float dragOffsetY = thumbRelativeMousePosY - pSB->thumbClickPosY; - - float destTrackPos = pSB->thumbPos; - if (pSB->orientation == drgui_sb_orientation_vertical) { - destTrackPos += dragOffsetY; - } else { - destTrackPos += dragOffsetX; - } - - int destScrollPos = drgui_sb_calculate_scroll_pos_from_thumb_pos(pSBElement, destTrackPos); - if (destScrollPos != pSB->scrollPos) - { - drgui_sb_scroll_to(pSBElement, destScrollPos); - } - } - else - { - // The thumb is not pressed. We just need to check if the hovered state has change and redraw if required. - if (drgui_sb_is_thumb_visible(pSBElement)) - { - bool wasThumbHovered = pSB->thumbHovered; - - drgui_rect thumbRect = drgui_sb_get_thumb_rect(pSBElement); - pSB->thumbHovered = drgui_rect_contains_point(thumbRect, (float)relativeMousePosX, (float)relativeMousePosY); - - if (wasThumbHovered != pSB->thumbHovered) { - drgui_dirty(pSBElement, thumbRect); - } - } - } -} - -void drgui_sb_on_mouse_button_down(drgui_element* pSBElement, int button, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - if (button == DRGUI_MOUSE_BUTTON_LEFT) - { - if (drgui_sb_is_thumb_visible(pSBElement)) - { - drgui_rect thumbRect = drgui_sb_get_thumb_rect(pSBElement); - if (drgui_rect_contains_point(thumbRect, (float)relativeMousePosX, (float)relativeMousePosY)) - { - if (!pSB->thumbPressed) - { - drgui_capture_mouse(pSBElement); - pSB->thumbPressed = true; - - pSB->thumbClickPosX = (float)relativeMousePosX; - pSB->thumbClickPosY = (float)relativeMousePosY; - drgui_sb_make_relative_to_thumb(pSBElement, &pSB->thumbClickPosX, &pSB->thumbClickPosY); - - drgui_dirty(pSBElement, drgui_sb_get_thumb_rect(pSBElement)); - } - } - else - { - // If the click position is above the thumb we want to scroll up by a page. If it's below the thumb, we scroll down by a page. - if (relativeMousePosY < thumbRect.top) { - drgui_sb_scroll(pSBElement, -drgui_sb_get_page_size(pSBElement)); - } else if (relativeMousePosY >= thumbRect.bottom) { - drgui_sb_scroll(pSBElement, drgui_sb_get_page_size(pSBElement)); - } - } - } - } -} - -void drgui_sb_on_mouse_button_up(drgui_element* pSBElement, int button, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - if (button == DRGUI_MOUSE_BUTTON_LEFT) - { - if (pSB->thumbPressed && drgui_get_element_with_mouse_capture(pSBElement->pContext) == pSBElement) - { - drgui_release_mouse(pSBElement->pContext); - pSB->thumbPressed = false; - - drgui_dirty(pSBElement, drgui_sb_get_thumb_rect(pSBElement)); - } - } -} - -void drgui_sb_on_mouse_wheel(drgui_element* pSBElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - drgui_sb_scroll(pSBElement, -delta * drgui_sb_get_mouse_wheel_scale(pSBElement)); -} - -void drgui_sb_on_paint(drgui_element* pSBElement, drgui_rect relativeClippingRect, void* pPaintData) -{ - (void)relativeClippingRect; - - const drgui_scrollbar* pSB = (const drgui_scrollbar*)drgui_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - drgui_rect thumbRect = drgui_sb_get_thumb_rect(pSBElement); - - if (drgui_sb_is_thumb_visible(pSBElement)) - { - // The thumb is visible. - - // Track. We draw this in 4 seperate pieces so we can avoid overdraw with the thumb. - drgui_draw_rect(pSBElement, drgui_make_rect(0, 0, drgui_get_width(pSBElement), thumbRect.top), pSB->trackColor, pPaintData); // Top - drgui_draw_rect(pSBElement, drgui_make_rect(0, thumbRect.bottom, drgui_get_width(pSBElement), drgui_get_height(pSBElement)), pSB->trackColor, pPaintData); // Bottom - drgui_draw_rect(pSBElement, drgui_make_rect(0, thumbRect.top, thumbRect.left, thumbRect.bottom), pSB->trackColor, pPaintData); // Left - drgui_draw_rect(pSBElement, drgui_make_rect(thumbRect.right, thumbRect.top, drgui_get_width(pSBElement), thumbRect.bottom), pSB->trackColor, pPaintData); // Right - - // Thumb. - drgui_color thumbColor; - if (pSB->thumbPressed) { - thumbColor = pSB->thumbColorPressed; - } else if (pSB->thumbHovered) { - thumbColor = pSB->thumbColorHovered; - } else { - thumbColor = pSB->thumbColor; - } - - drgui_draw_rect(pSBElement, thumbRect, thumbColor, pPaintData); - } - else - { - // The thumb is not visible - just draw the track as one quad. - drgui_draw_rect(pSBElement, drgui_get_local_rect(pSBElement), pSB->trackColor, pPaintData); - } -} - - - -DRGUI_PRIVATE void drgui_sb_refresh_thumb(drgui_element* pSBElement) -{ - drgui_scrollbar* pSB = (drgui_scrollbar*)drgui_get_extra_data(pSBElement); - assert(pSB != NULL); - - drgui_rect oldThumbRect = drgui_sb_get_thumb_rect(pSBElement); - - pSB->thumbSize = drgui_sb_calculate_thumb_size(pSBElement); - pSB->thumbPos = drgui_sb_calculate_thumb_position(pSBElement); - - drgui_rect newThumbRect = drgui_sb_get_thumb_rect(pSBElement); - if (!drgui_rect_equal(oldThumbRect, newThumbRect)) - { - drgui_dirty(pSBElement, drgui_rect_union(oldThumbRect, newThumbRect)); - } -} - -DRGUI_PRIVATE float drgui_sb_calculate_thumb_size(drgui_element* pSBElement) -{ - const drgui_scrollbar* pSB = (const drgui_scrollbar*)drgui_get_extra_data(pSBElement); - assert(pSB != NULL); - - float trackSize = drgui_sb_get_track_size(pSBElement); - float range = (float)(pSB->rangeMax - pSB->rangeMin + 1); - - float thumbSize = DRGUI_MIN_SCROLLBAR_THUMB_SIZE; - if (range > 0) - { - thumbSize = roundf((trackSize / range) * pSB->pageSize); - thumbSize = drgui_sb_clampf(thumbSize, DRGUI_MIN_SCROLLBAR_THUMB_SIZE, trackSize); - } - - return thumbSize; -} - -DRGUI_PRIVATE float drgui_sb_calculate_thumb_position(drgui_element* pSBElement) -{ - const drgui_scrollbar* pSB = (const drgui_scrollbar*)drgui_get_extra_data(pSBElement); - assert(pSB != NULL); - - float trackSize = drgui_sb_get_track_size(pSBElement); - float thumbSize = drgui_sb_calculate_thumb_size(pSBElement); - float range = (float)(pSB->rangeMax - pSB->rangeMin + 1); - - float thumbPos = 0; - if (range > pSB->pageSize) - { - thumbPos = roundf((trackSize / range) * pSB->scrollPos); - thumbPos = drgui_sb_clampf(thumbPos, 0, trackSize - thumbSize); - } - - return thumbPos; -} - -DRGUI_PRIVATE float drgui_sb_get_track_size(drgui_element* pSBElement) -{ - const drgui_scrollbar* pSB = (const drgui_scrollbar*)drgui_get_extra_data(pSBElement); - assert(pSB != NULL); - - if (pSB->orientation == drgui_sb_orientation_vertical) { - return drgui_get_height(pSBElement) - (pSB->thumbPadding*2); - } else { - return drgui_get_width(pSBElement) - (pSB->thumbPadding*2); - } -} - -DRGUI_PRIVATE void drgui_sb_make_relative_to_thumb(drgui_element* pSBElement, float* pPosX, float* pPosY) -{ - drgui_rect thumbRect = drgui_sb_get_thumb_rect(pSBElement); - - if (pPosX != NULL) { - *pPosX -= thumbRect.left; - } - - if (pPosY != NULL) { - *pPosY -= thumbRect.top; - } -} - -DRGUI_PRIVATE int drgui_sb_calculate_scroll_pos_from_thumb_pos(drgui_element* pSBElement, float thumbPos) -{ - const drgui_scrollbar* pSB = (const drgui_scrollbar*)drgui_get_extra_data(pSBElement); - assert(pSB != NULL); - - float trackSize = drgui_sb_get_track_size(pSBElement); - float range = (float)(pSB->rangeMax - pSB->rangeMin + 1); - - return (int)roundf(thumbPos / (trackSize / range)); -} -#endif //DR_GUI_IMPLEMENTATION - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Tab Bar -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -// QUICK NOTES -// -// - This control is only the tab bar itself - this does not handle tab pages and content switching and whatnot. - -#ifndef drgui_tab_bar_h -#define drgui_tab_bar_h - -#ifdef __cplusplus -extern "C" { -#endif - -#define DRGUI_MAX_TAB_TEXT_LENGTH 256 - -typedef enum -{ - drgui_tabbar_orientation_top, - drgui_tabbar_orientation_bottom, - drgui_tabbar_orientation_left, - drgui_tabbar_orientation_right -} drgui_tabbar_orientation; - -typedef struct drgui_tab drgui_tab; - -typedef void (* drgui_tabbar_on_measure_tab_proc) (drgui_element* pTBElement, drgui_tab* pTab, float* pWidthOut, float* pHeightOut); -typedef void (* drgui_tabbar_on_paint_tab_proc) (drgui_element* pTBElement, drgui_tab* pTab, drgui_rect relativeClippingRect, float offsetX, float offsetY, float width, float height, void* pPaintData); -typedef void (* drgui_tabbar_on_tab_activated_proc) (drgui_element* pTBElement, drgui_tab* pTab, drgui_tab* pOldActiveTab); -typedef void (* drgui_tabbar_on_tab_deactivated_proc) (drgui_element* pTBElement, drgui_tab* pTab, drgui_tab* pNewActiveTab); -typedef void (* drgui_tabbar_on_tab_close_proc) (drgui_element* pTBElement, drgui_tab* pTab); -typedef void (* drgui_tabbar_on_tab_mouse_button_up_proc)(drgui_element* pTBElement, drgui_tab* pTab, int mouseButton, int mouseRelativePosX, int mouseRelativePosY, int stateFlags); - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tab Bar -// -/////////////////////////////////////////////////////////////////////////////// - -/// Creates a new tab bar control. -drgui_element* drgui_create_tab_bar(drgui_context* pContext, drgui_element* pParent, drgui_tabbar_orientation orientation, size_t extraDataSize, const void* pExtraData); - -/// Deletes the given tab bar control. -void drgui_delete_tab_bar(drgui_element* pTBElement); - - -/// Retrieves the size of the extra data associated with the scrollbar. -size_t drgui_tabbar_get_extra_data_size(drgui_element* pTBElement); - -/// Retrieves a pointer to the extra data associated with the scrollbar. -void* drgui_tabbar_get_extra_data(drgui_element* pTBElement); - -/// Retrieves the orientation of the given scrollbar. -drgui_tabbar_orientation drgui_tabbar_get_orientation(drgui_element* pTBElement); - - -/// Sets the default font to use for tabs. -void drgui_tabbar_set_font(drgui_element* pTBElement, drgui_font* pFont); - -/// Retrieves the default font to use for tabs. -drgui_font* drgui_tabbar_get_font(drgui_element* pTBElement); - -// Sets the color of the text to use on tabs. -void drgui_tabbar_set_text_color(drgui_element* pTBElement, drgui_color color); - -// Retrieves the color of the text to use on tabs. -drgui_color drgui_tabbar_get_text_color(drgui_element* pTBElement); - -// Sets the color of the text to use on active tabs. -void drgui_tabbar_set_text_color_active(drgui_element* pTBElement, drgui_color color); - -// Sets the color of the text to use on hovered tabs. -void drgui_tabbar_set_text_color_hovered(drgui_element* pTBElement, drgui_color color); - -/// Sets the image to use for close buttons. -void drgui_tabbar_set_close_button_image(drgui_element* pTBElement, drgui_image* pImage); - -/// Retrieves the image being used for the close buttons. -drgui_image* drgui_tabbar_get_close_button_image(drgui_element* pTBElement); - -// Sets the default color of the close button. -void drgui_tabbar_set_close_button_color(drgui_element* pTBElement, drgui_color color); - -// Sets the padding to apply the the text of each tab. -void drgui_tabbar_set_tab_padding(drgui_element* pTBElement, float padding); - -// Retrieves the padding to apply to the text of each tab. -float drgui_tabbar_get_tab_padding(drgui_element* pTBElement); - -// Sets the padding to apply the the left of the close button. -void drgui_tabbar_set_close_button_left_padding(drgui_element* pTBElement, float padding); - -// Retrieves the padding to apply to the left of the close button. -float drgui_tabbar_get_close_button_left_padding(drgui_element* pTBElement); - -// Sets the default background color of tabs. This is the color of inactive tabs. -void drgui_tabbar_set_tab_background_color(drgui_element* pTBElement, drgui_color color); - -// Retrieves the default background color of tabs while inactive. -drgui_color drgui_tabbar_get_tab_background_color(drgui_element* pTBElement); - -// Sets the background color of tabs while hovered. -void drgui_tabbar_set_tab_background_color_hovered(drgui_element* pTBElement, drgui_color color); - -// Retrieves the background color of tabs while hovered. -drgui_color drgui_tabbar_get_tab_background_color_hovered(drgui_element* pTBElement); - -// Sets the background color of tabs while activated. -void drgui_tabbar_set_tab_background_color_active(drgui_element* pTBElement, drgui_color color); - -// Retrieves the background color of tabs while activated. -drgui_color drgui_tabbar_get_tab_background_color_actived(drgui_element* pTBElement); - - -/// Sets the function to call when a tab needs to be measured. -void drgui_tabbar_set_on_measure_tab(drgui_element* pTBElement, drgui_tabbar_on_measure_tab_proc proc); - -/// Sets the function to call when a tab needs to be painted. -void drgui_tabbar_set_on_paint_tab(drgui_element* pTBElement, drgui_tabbar_on_paint_tab_proc proc); - -/// Sets the function to call when a tab is activated. -void drgui_tabbar_set_on_tab_activated(drgui_element* pTBElement, drgui_tabbar_on_tab_activated_proc proc); - -/// Sets the function to call when a tab is deactivated. -void drgui_tabbar_set_on_tab_deactivated(drgui_element* pTBElement, drgui_tabbar_on_tab_deactivated_proc proc); - -/// Sets the function to call when a tab is closed with the close button. -void drgui_tabbar_set_on_tab_closed(drgui_element* pTBElement, drgui_tabbar_on_tab_close_proc proc); - -// Sets the function to call when a tab has a mouse button released on it. -void drgui_tabbar_set_on_tab_mouse_button_up(drgui_element* pTBElement, drgui_tabbar_on_tab_mouse_button_up_proc proc); - - -/// Measures the given tab. -void drgui_tabbar_measure_tab(drgui_element* pTBElement, drgui_tab* pTab, float* pWidthOut, float* pHeightOut); - -/// Paints the given tab. -void drgui_tabbar_paint_tab(drgui_element* pTBElement, drgui_tab* pTab, drgui_rect relativeClippingRect, float offsetX, float offsetY, float width, float height, void* pPaintData); - - -/// Sets the width or height of the tab bar to that of it's tabs based on it's orientation. -/// -/// @remarks -/// If the orientation is set to top or bottom, the height will be resized and the width will be left alone. If the orientation -/// is left or right, the width will be resized and the height will be left alone. -/// @par -/// If there is no tab measuring callback set, this will do nothing. -void drgui_tabbar_resize_by_tabs(drgui_element* pTBElement); - -/// Enables auto-resizing based on tabs. -/// -/// @remarks -/// This follows the same resizing rules as per drgui_tabbar_resize_by_tabs(). -/// -/// @see -/// drgui_tabbar_resize_by_tabs() -void drgui_tabbar_enable_auto_size(drgui_element* pTBElement); - -/// Disables auto-resizing based on tabs. -void drgui_tabbar_disable_auto_size(drgui_element* pTBElement); - -/// Determines whether or not auto-sizing is enabled. -bool drgui_tabbar_is_auto_size_enabled(drgui_element* pTBElement); - - -// Retrieves a pointer to the first tab in the given tab bar. -drgui_tab* drgui_tabbar_get_first_tab(drgui_element* pTBElement); - -// Retrieves a pointer to the last tab in the given tab bar. -drgui_tab* drgui_tabbar_get_last_tab(drgui_element* pTBElement); - -// Retrieves a pointer to the next tab in the given tab bar. -drgui_tab* drgui_tabbar_get_next_tab(drgui_element* pTBElement, drgui_tab* pTab); - -// Retrieves a pointer to the previous tab in the given tab bar. -drgui_tab* drgui_tabbar_get_prev_tab(drgui_element* pTBElement, drgui_tab* pTab); - - -/// Activates the given tab. -void drgui_tabbar_activate_tab(drgui_element* pTBElement, drgui_tab* pTab); - -// Activates the tab to the right of the currently active tab, looping back to the start if necessary. -void drgui_tabbar_activate_next_tab(drgui_element* pTBElement); - -// Activates the tab to the left of the currently active tab, looping back to the end if necessary. -void drgui_tabbar_activate_prev_tab(drgui_element* pTBElement); - -/// Retrieves a pointer to the currently active tab. -drgui_tab* drgui_tabbar_get_active_tab(drgui_element* pTBElement); - - -/// Determines whether or not the given tab is in view. -bool drgui_tabbar_is_tab_in_view(drgui_element* pTBElement, drgui_tab* pTab); - - -/// Shows the close buttons on each tab. -void drgui_tabbar_show_close_buttons(drgui_element* pTBElement); - -/// Hides the close buttons on each tab. -void drgui_tabbar_hide_close_buttons(drgui_element* pTBElement); - -/// Enables the on_close event on middle click. -void drgui_tabbar_enable_close_on_middle_click(drgui_element* pTBElement); - -/// Disables the on_close event on middle click. -void drgui_tabbar_disable_close_on_middle_click(drgui_element* pTBElement); - -/// Determines whether or not close-on-middle-click is enabled. -bool drgui_tabbar_is_close_on_middle_click_enabled(drgui_element* pTBElement); - - -/// Called when the mouse leave event needs to be processed for the given tab bar control. -void drgui_tabbar_on_mouse_leave(drgui_element* pTBElement); - -/// Called when the mouse move event needs to be processed for the given tab bar control. -void drgui_tabbar_on_mouse_move(drgui_element* pTBElement, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button down event needs to be processed for the given tab bar control. -void drgui_tabbar_on_mouse_button_down(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button up event needs to be processed for the given tab bar control. -void drgui_tabbar_on_mouse_button_up(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the paint event needs to be processed for the given tab control. -void drgui_tabbar_on_paint(drgui_element* pTBElement, drgui_rect relativeClippingRect, void* pPaintData); - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tab -// -/////////////////////////////////////////////////////////////////////////////// - -/// Creates and appends a tab -drgui_tab* drgui_tabbar_create_and_append_tab(drgui_element* pTBElement, const char* text, size_t extraDataSize, const void* pExtraData); - -/// Creates and prepends a tab. -drgui_tab* drgui_tabbar_create_and_prepend_tab(drgui_element* pTBElement, const char* text, size_t extraDataSize, const void* pExtraData); - -/// Recursively deletes a tree view item. -void drgui_tab_delete(drgui_tab* pTab); - -/// Retrieves the tab bar GUI element that owns the given item. -drgui_element* drgui_tab_get_tab_bar_element(drgui_tab* pTab); - -/// Retrieves the size of the extra data associated with the given tree-view item. -size_t drgui_tab_get_extra_data_size(drgui_tab* pTab); - -/// Retrieves a pointer to the extra data associated with the given tree-view item. -void* drgui_tab_get_extra_data(drgui_tab* pTab); - - -/// Sets the text of the given tab bar item. -void drgui_tab_set_text(drgui_tab* pTab, const char* text); - -/// Retrieves the text of the given tab bar item. -const char* drgui_tab_get_text(drgui_tab* pTab); - - -/// Retrieves a pointer to the next tab in the tab bar. -drgui_tab* drgui_tab_get_next_tab(drgui_tab* pTab); - -/// Retrieves a pointer to the previous tab in the tab bar. -drgui_tab* drgui_tab_get_prev_tab(drgui_tab* pTab); - - -/// Moves the given tab to the front of the tab bar that owns it. -void drgui_tab_move_to_front(drgui_tab* pTab); - -/// Determines whether or not the given tab is in view. -bool drgui_tab_is_in_view(drgui_tab* pTab); - -/// Moves the given tab into view, if it's not already. -/// -/// If the tab is out of view, it will be repositioned to the front of the tab bar. -void drgui_tab_move_into_view(drgui_tab* pTab); - - -#ifdef __cplusplus -} -#endif -#endif //drgui_tab_bar_h - - -#ifdef DR_GUI_IMPLEMENTATION -typedef struct drgui_tab_bar drgui_tab_bar; - -struct drgui_tab_bar -{ - /// The orientation. - drgui_tabbar_orientation orientation; - - - /// A pointer to the first tab. - drgui_tab* pFirstTab; - - /// A pointer to the last tab. - drgui_tab* pLastTab; - - - /// A pointer to the hovered tab. - drgui_tab* pHoveredTab; - - /// A pointer to the active tab. - drgui_tab* pActiveTab; - - /// The tab whose close button is currently pressed, if any. - drgui_tab* pTabWithCloseButtonPressed; - - - /// The default font to use for tab bar items. - drgui_font* pFont; - - /// The default color to use for tab bar item text. - drgui_color tabTextColor; - - /// The default color to use for tab bar item text while active. - drgui_color tabTextColorActivated; - - /// The default color to use for tab bar item text while hovered. - drgui_color tabTextColorHovered; - - /// The default background color of tab bar items. - drgui_color tabBackgroundColor; - - /// The background color of tab bar items while hovered. - drgui_color tabBackgroundColorHovered; - - /// The background color of tab bar items while selected. - drgui_color tabBackbroundColorActivated; - - /// The padding to apply to the text of tabs. - float tabPadding; - - /// The image to use for the close button. - drgui_image* pCloseButtonImage; - - /// The padding to the left of the close button. - float closeButtonPaddingLeft; - - /// The default color of the close button. - drgui_color closeButtonColorDefault; - - /// The color of the close button when the tab is hovered, but not the close button itself. - drgui_color closeButtonColorTabHovered; - - /// The color of the close button when it is hovered. - drgui_color closeButtonColorHovered; - - /// The color of the close button when it is pressed. - drgui_color closeButtonColorPressed; - - - /// Whether or not auto-sizing is enabled. Disabled by default. - bool isAutoSizeEnabled; - - /// Whether or not the close buttons are being shown. - bool isShowingCloseButton; - - /// Whether or not close-on-middle-click is enabled. - bool isCloseOnMiddleClickEnabled; - - /// Whether or not the close button is hovered. - bool isCloseButtonHovered; - - - /// The function to call when a tab needs to be measured. - drgui_tabbar_on_measure_tab_proc onMeasureTab; - - /// The function to call when a tab needs to be painted. - drgui_tabbar_on_paint_tab_proc onPaintTab; - - /// The function to call when a tab is activated. - drgui_tabbar_on_tab_activated_proc onTabActivated; - - /// The function to call when a tab is deactivated. - drgui_tabbar_on_tab_deactivated_proc onTabDeactivated; - - /// The function to call when a tab is closed via the close button. - drgui_tabbar_on_tab_close_proc onTabClose; - - // The function to call when a mouse button is released while over a tab. - drgui_tabbar_on_tab_mouse_button_up_proc onTabMouseButtonUp; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data. - char pExtraData[1]; -}; - -struct drgui_tab -{ - /// The tab bar that owns the tab. - drgui_element* pTBElement; - - /// A pointer to the next tab in the tab bar. - drgui_tab* pNextTab; - - /// A pointer to the previous tab in the tab bar. - drgui_tab* pPrevTab; - - - /// The tab bar's text. - char text[DRGUI_MAX_TAB_TEXT_LENGTH]; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data buffer. - char pExtraData[1]; -}; - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tab -// -/////////////////////////////////////////////////////////////////////////////// - -/// Default implementation of the item measure event. -DRGUI_PRIVATE void drgui_tabbar_on_measure_tab_default(drgui_element* pTBElement, drgui_tab* pTab, float* pWidthOut, float* pHeightOut); - -/// Paints the given menu item. -DRGUI_PRIVATE void drgui_tabbar_on_paint_tab_default(drgui_element* pTBElement, drgui_tab* pTab, drgui_rect relativeClippingRect, float offsetX, float offsetY, float width, float height, void* pPaintData); - -/// Finds the tab sitting under the given point, if any. -DRGUI_PRIVATE drgui_tab* drgui_tabbar_find_tab_under_point(drgui_element* pTBElement, float relativePosX, float relativePosY, bool* pIsOverCloseButtonOut); - -drgui_element* drgui_create_tab_bar(drgui_context* pContext, drgui_element* pParent, drgui_tabbar_orientation orientation, size_t extraDataSize, const void* pExtraData) -{ - if (pContext == NULL) { - return NULL; - } - - drgui_element* pTBElement = drgui_create_element(pContext, pParent, sizeof(drgui_tab_bar) + extraDataSize, NULL); - if (pTBElement == NULL) { - return NULL; - } - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - pTB->orientation = orientation; - pTB->pFirstTab = NULL; - pTB->pLastTab = NULL; - pTB->pHoveredTab = NULL; - pTB->pActiveTab = NULL; - pTB->pTabWithCloseButtonPressed = NULL; - - pTB->pFont = NULL; - pTB->tabTextColor = drgui_rgb(224, 224, 224); - pTB->tabTextColorActivated = drgui_rgb(224, 224, 224); - pTB->tabTextColorHovered = drgui_rgb(224, 224, 224); - pTB->tabBackgroundColor = drgui_rgb(58, 58, 58); - pTB->tabBackgroundColorHovered = drgui_rgb(16, 92, 160); - pTB->tabBackbroundColorActivated = drgui_rgb(32, 128, 192); //drgui_rgb(80, 80, 80); - pTB->tabPadding = 4; - pTB->pCloseButtonImage = NULL; - pTB->closeButtonPaddingLeft = 6; - pTB->closeButtonColorDefault = pTB->tabBackgroundColor; - pTB->closeButtonColorTabHovered = drgui_rgb(192, 192, 192); - pTB->closeButtonColorHovered = drgui_rgb(255, 96, 96); - pTB->closeButtonColorPressed = drgui_rgb(192, 32, 32); - pTB->isAutoSizeEnabled = false; - pTB->isShowingCloseButton = false; - pTB->isCloseOnMiddleClickEnabled = false; - pTB->isCloseButtonHovered = false; - - pTB->onMeasureTab = drgui_tabbar_on_measure_tab_default; - pTB->onPaintTab = drgui_tabbar_on_paint_tab_default; - pTB->onTabActivated = NULL; - pTB->onTabDeactivated = NULL; - pTB->onTabClose = NULL; - - - pTB->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pTB->pExtraData, pExtraData, extraDataSize); - } - - - // Event handlers. - drgui_set_on_mouse_leave(pTBElement, drgui_tabbar_on_mouse_leave); - drgui_set_on_mouse_move(pTBElement, drgui_tabbar_on_mouse_move); - drgui_set_on_mouse_button_down(pTBElement, drgui_tabbar_on_mouse_button_down); - drgui_set_on_mouse_button_up(pTBElement, drgui_tabbar_on_mouse_button_up); - drgui_set_on_paint(pTBElement, drgui_tabbar_on_paint); - - return pTBElement; -} - -void drgui_delete_tab_bar(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - while (pTB->pFirstTab != NULL) { - drgui_tab_delete(pTB->pFirstTab); - } - - - drgui_delete_element(pTBElement); -} - - -size_t drgui_tabbar_get_extra_data_size(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->extraDataSize; -} - -void* drgui_tabbar_get_extra_data(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pExtraData; -} - -drgui_tabbar_orientation drgui_tabbar_get_orientation(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_tabbar_orientation_top; - } - - return pTB->orientation; -} - - -void drgui_tabbar_set_font(drgui_element* pTBElement, drgui_font* pFont) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->pFont = pFont; - - // A change in font may have changed the size of the tabbar. - if (pTB->isAutoSizeEnabled) { - drgui_tabbar_resize_by_tabs(pTBElement); - } - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -drgui_font* drgui_tabbar_get_font(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pFont; -} - - -void drgui_tabbar_set_text_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabTextColor = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -drgui_color drgui_tabbar_get_text_color(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTB->tabTextColor; -} - -void drgui_tabbar_set_text_color_active(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabTextColorActivated = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -void drgui_tabbar_set_text_color_hovered(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabTextColorHovered = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - - -void drgui_tabbar_set_close_button_image(drgui_element* pTBElement, drgui_image* pImage) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->pCloseButtonImage = pImage; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -drgui_image* drgui_tabbar_get_close_button_image(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pCloseButtonImage; -} - -void drgui_tabbar_set_close_button_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->closeButtonColorDefault = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - - -void drgui_tabbar_set_tab_padding(drgui_element* pTBElement, float padding) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabPadding = padding; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -float drgui_tabbar_get_tab_padding(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->tabPadding; -} - -void drgui_tabbar_set_close_button_left_padding(drgui_element* pTBElement, float padding) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->closeButtonPaddingLeft = padding; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -float drgui_tabbar_get_close_button_left_padding(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->closeButtonPaddingLeft; -} - - -void drgui_tabbar_set_tab_background_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabBackgroundColor = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -drgui_color drgui_tabbar_get_tab_background_color(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTB->tabBackgroundColor; -} - -void drgui_tabbar_set_tab_background_color_hovered(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabBackgroundColorHovered = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -drgui_color drgui_tabbar_get_tab_background_color_hovered(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTB->tabBackgroundColorHovered; -} - -void drgui_tabbar_set_tab_background_color_active(drgui_element* pTBElement, drgui_color color) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->tabBackbroundColorActivated = color; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -drgui_color drgui_tabbar_get_tab_background_color_actived(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTB->tabBackbroundColorActivated; -} - - -void drgui_tabbar_set_on_measure_tab(drgui_element* pTBElement, drgui_tabbar_on_measure_tab_proc proc) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onMeasureTab = proc; -} - -void drgui_tabbar_set_on_paint_tab(drgui_element* pTBElement, drgui_tabbar_on_paint_tab_proc proc) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onPaintTab = proc; -} - -void drgui_tabbar_set_on_tab_activated(drgui_element* pTBElement, drgui_tabbar_on_tab_activated_proc proc) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onTabActivated = proc; -} - -void drgui_tabbar_set_on_tab_deactivated(drgui_element* pTBElement, drgui_tabbar_on_tab_deactivated_proc proc) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onTabDeactivated = proc; -} - -void drgui_tabbar_set_on_tab_closed(drgui_element* pTBElement, drgui_tabbar_on_tab_close_proc proc) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onTabClose = proc; -} - -void drgui_tabbar_set_on_tab_mouse_button_up(drgui_element* pTBElement, drgui_tabbar_on_tab_mouse_button_up_proc proc) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onTabMouseButtonUp = proc; -} - - -void drgui_tabbar_measure_tab(drgui_element* pTBElement, drgui_tab* pTab, float* pWidthOut, float* pHeightOut) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->onMeasureTab) { - pTB->onMeasureTab(pTBElement, pTab, pWidthOut, pHeightOut); - } -} - -void drgui_tabbar_paint_tab(drgui_element* pTBElement, drgui_tab* pTab, drgui_rect relativeClippingRect, float offsetX, float offsetY, float width, float height, void* pPaintData) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->onPaintTab) { - pTB->onPaintTab(pTBElement, pTab, relativeClippingRect, offsetX, offsetY, width, height, pPaintData); - } -} - - -void drgui_tabbar_resize_by_tabs(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->onMeasureTab == NULL) { - return; - } - - float maxWidth = 0; - float maxHeight = 0; - if (pTB->pFirstTab == NULL) { - // There are no tabs. Set initial size based on the line height of the font. - drgui_font_metrics fontMetrics; - if (drgui_get_font_metrics(pTB->pFont, &fontMetrics)) { - if (pTB->orientation == drgui_tabbar_orientation_top || pTB->orientation == drgui_tabbar_orientation_bottom) { - maxHeight = fontMetrics.lineHeight + (pTB->tabPadding*2); - } else { - maxWidth = fontMetrics.lineHeight + (pTB->tabPadding*2); - } - } - } else { - for (drgui_tab* pTab = pTB->pFirstTab; pTab != NULL; pTab = pTab->pNextTab) { - float tabWidth = 0; - float tabHeight = 0; - drgui_tabbar_measure_tab(pTBElement, pTab, &tabWidth, &tabHeight); - - maxWidth = (tabWidth > maxWidth) ? tabWidth : maxWidth; - maxHeight = (tabHeight > maxHeight) ? tabHeight : maxHeight; - } - } - - - - - if (pTB->orientation == drgui_tabbar_orientation_top || pTB->orientation == drgui_tabbar_orientation_bottom) { - drgui_set_size(pTBElement, drgui_get_width(pTBElement), maxHeight); - } else { - drgui_set_size(pTBElement, maxWidth, drgui_get_height(pTBElement)); - } -} - -void drgui_tabbar_enable_auto_size(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->isAutoSizeEnabled = true; -} - -void drgui_tabbar_disable_auto_size(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->isAutoSizeEnabled = false; -} - -bool drgui_tabbar_is_auto_size_enabled(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return pTB->isAutoSizeEnabled; -} - - -drgui_tab* drgui_tabbar_get_first_tab(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pFirstTab; -} - -drgui_tab* drgui_tabbar_get_last_tab(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pLastTab; -} - -drgui_tab* drgui_tabbar_get_next_tab(drgui_element* pTBElement, drgui_tab* pTab) -{ - (void)pTBElement; - return drgui_tab_get_next_tab(pTab); -} - -drgui_tab* drgui_tabbar_get_prev_tab(drgui_element* pTBElement, drgui_tab* pTab) -{ - (void)pTBElement; - return drgui_tab_get_prev_tab(pTab); -} - - -void drgui_tabbar_activate_tab(drgui_element* pTBElement, drgui_tab* pTab) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_tab* pOldActiveTab = pTB->pActiveTab; - drgui_tab* pNewActiveTab = pTab; - - if (pOldActiveTab == pNewActiveTab) { - return; // The tab is already active - nothing to do. - } - - - pTB->pActiveTab = pNewActiveTab; - - if (pTB->onTabDeactivated && pOldActiveTab != NULL) { - pTB->onTabDeactivated(pTBElement, pOldActiveTab, pNewActiveTab); - } - - if (pTB->onTabActivated && pNewActiveTab != NULL) { - pTB->onTabActivated(pTBElement, pNewActiveTab, pOldActiveTab); - } - - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -void drgui_tabbar_activate_next_tab(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->pActiveTab == NULL) { - drgui_tabbar_activate_tab(pTBElement, pTB->pFirstTab); - return; - } - - - drgui_tab* pNextTab = pTB->pActiveTab->pNextTab; - if (pNextTab == NULL) { - pNextTab = pTB->pFirstTab; - } - - drgui_tabbar_activate_tab(pTBElement, pNextTab); -} - -void drgui_tabbar_activate_prev_tab(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->pActiveTab == NULL) { - drgui_tabbar_activate_tab(pTBElement, pTB->pLastTab); - return; - } - - - drgui_tab* pPrevTab = pTB->pActiveTab->pPrevTab; - if (pPrevTab == NULL) { - pPrevTab = pTB->pLastTab; - } - - drgui_tabbar_activate_tab(pTBElement, pPrevTab); -} - -drgui_tab* drgui_tabbar_get_active_tab(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pActiveTab; -} - - -bool drgui_tabbar_is_tab_in_view(drgui_element* pTBElement, drgui_tab* pTabIn) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - float tabbarWidth = 0; - float tabbarHeight = 0; - drgui_get_size(pTBElement, &tabbarWidth, &tabbarHeight); - - - // Each tab. - float runningPosX = 0; - float runningPosY = 0; - for (drgui_tab* pTab = pTB->pFirstTab; pTab != NULL; pTab = pTab->pNextTab) - { - float tabWidth = 0; - float tabHeight = 0; - drgui_tabbar_measure_tab(pTBElement, pTab, &tabWidth, &tabHeight); - - if (pTab == pTabIn) { - return runningPosX + tabWidth <= tabbarWidth && runningPosY + tabHeight <= tabbarHeight; - } - - - if (pTB->orientation == drgui_tabbar_orientation_top || pTB->orientation == drgui_tabbar_orientation_bottom) { - runningPosX += tabWidth; - } else { - runningPosY += tabHeight; - } - } - - return false; -} - - -void drgui_tabbar_show_close_buttons(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->isShowingCloseButton = true; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -void drgui_tabbar_hide_close_buttons(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->isShowingCloseButton = false; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - - -void drgui_tabbar_enable_close_on_middle_click(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->isCloseOnMiddleClickEnabled = true; -} - -void drgui_tabbar_disable_close_on_middle_click(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->isCloseOnMiddleClickEnabled = false; -} - -bool drgui_tabbar_is_close_on_middle_click_enabled(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return pTB->isCloseOnMiddleClickEnabled; -} - - -void drgui_tabbar_on_mouse_leave(drgui_element* pTBElement) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->pHoveredTab != NULL) - { - pTB->pHoveredTab = NULL; - pTB->isCloseButtonHovered = false; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } - } -} - -void drgui_tabbar_on_mouse_move(drgui_element* pTBElement, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - bool isCloseButtonHovered = false; - - drgui_tab* pOldHoveredTab = pTB->pHoveredTab; - drgui_tab* pNewHoveredTab = drgui_tabbar_find_tab_under_point(pTBElement, (float)relativeMousePosX, (float)relativeMousePosY, &isCloseButtonHovered); - - if (pOldHoveredTab != pNewHoveredTab || pTB->isCloseButtonHovered != isCloseButtonHovered) - { - pTB->pHoveredTab = pNewHoveredTab; - pTB->isCloseButtonHovered = isCloseButtonHovered; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } - } -} - -void drgui_tabbar_on_mouse_button_down(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT || mouseButton == DRGUI_MOUSE_BUTTON_RIGHT) - { - bool isOverCloseButton = false; - - drgui_tab* pOldActiveTab = pTB->pActiveTab; - drgui_tab* pNewActiveTab = drgui_tabbar_find_tab_under_point(pTBElement, (float)relativeMousePosX, (float)relativeMousePosY, &isOverCloseButton); - - if (pNewActiveTab != NULL && pOldActiveTab != pNewActiveTab && !isOverCloseButton) { - drgui_tabbar_activate_tab(pTBElement, pNewActiveTab); - } - - if (isOverCloseButton && mouseButton == DRGUI_MOUSE_BUTTON_LEFT) { - pTB->pTabWithCloseButtonPressed = pNewActiveTab; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } - } - } - else if (mouseButton == DRGUI_MOUSE_BUTTON_MIDDLE) - { - if (pTB->isCloseOnMiddleClickEnabled) - { - drgui_tab* pHoveredTab = drgui_tabbar_find_tab_under_point(pTBElement, (float)relativeMousePosX, (float)relativeMousePosY, NULL); - if (pHoveredTab != NULL) { - if (pTB->onTabClose) { - pTB->onTabClose(pTBElement, pHoveredTab); - } - } - } - } -} - -void drgui_tabbar_on_mouse_button_up(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - - bool releasedOverCloseButton = false; - drgui_tab* pTabUnderMouse = drgui_tabbar_find_tab_under_point(pTBElement, (float)relativeMousePosX, (float)relativeMousePosY, &releasedOverCloseButton); - - if (pTB->pTabWithCloseButtonPressed != NULL && mouseButton == DRGUI_MOUSE_BUTTON_LEFT) - { - if (releasedOverCloseButton && pTabUnderMouse == pTB->pTabWithCloseButtonPressed) { - if (pTB->onTabClose) { - pTB->onTabClose(pTBElement, pTB->pTabWithCloseButtonPressed); - } - } - - - pTB->pTabWithCloseButtonPressed = NULL; - - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } - } - else - { - if (!releasedOverCloseButton && pTB->onTabMouseButtonUp) { - // TODO: Improve this by passing the mouse position relative to the tab. Currently it is relative to the tab BAR. Can have - // the drgui_tabbar_find_tab_under_point() function return the position relative to the tab. - pTB->onTabMouseButtonUp(pTBElement, pTabUnderMouse, mouseButton, relativeMousePosX, relativeMousePosY, stateFlags); - } - } -} - -void drgui_tabbar_on_paint(drgui_element* pTBElement, drgui_rect relativeClippingRect, void* pPaintData) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - - float tabbarWidth = 0; - float tabbarHeight = 0; - drgui_get_size(pTBElement, &tabbarWidth, &tabbarHeight); - - - // Each tab. - float runningPosX = 0; - float runningPosY = 0; - for (drgui_tab* pTab = pTB->pFirstTab; pTab != NULL; pTab = pTab->pNextTab) - { - float tabWidth = 0; - float tabHeight = 0; - drgui_tabbar_measure_tab(pTBElement, pTab, &tabWidth, &tabHeight); - - // If a part of the tab is out of bounds, stop drawing. - if (runningPosX > tabbarWidth || runningPosY > tabbarHeight) { - break; - } - - - drgui_tabbar_paint_tab(pTBElement, pTab, relativeClippingRect, runningPosX, runningPosY, tabWidth, tabHeight, pPaintData); - - // After painting the tab, there may be a region of the background that was not drawn by the tab painting callback. We'll need to - // draw that here. - if (pTB->orientation == drgui_tabbar_orientation_top || pTB->orientation == drgui_tabbar_orientation_bottom) { - drgui_draw_rect(pTBElement, drgui_make_rect(runningPosX, runningPosY + tabHeight, tabbarWidth, tabbarHeight), pTB->tabBackgroundColor, pPaintData); - } else { - drgui_draw_rect(pTBElement, drgui_make_rect(runningPosX + tabWidth, runningPosY, tabbarWidth, runningPosY + tabHeight), pTB->tabBackgroundColor, pPaintData); - } - - - - if (pTB->orientation == drgui_tabbar_orientation_top || pTB->orientation == drgui_tabbar_orientation_bottom) { - runningPosX += tabWidth; - } else { - runningPosY += tabHeight; - } - } - - - // Background. We just draw a quad around the region that is not covered by items. - drgui_draw_rect(pTBElement, drgui_make_rect(runningPosX, runningPosY, tabbarWidth, tabbarHeight), pTB->tabBackgroundColor, pPaintData); -} - - -DRGUI_PRIVATE void drgui_tabbar_on_measure_tab_default(drgui_element* pTBElement, drgui_tab* pTab, float* pWidthOut, float* pHeightOut) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - float textWidth = 0; - float textHeight = 0; - - if (pTab != NULL) { - drgui_measure_string(pTB->pFont, pTab->text, strlen(pTab->text), &textWidth, &textHeight); - } - - - float closeButtonWidth = 0; - if (pTB->isShowingCloseButton && pTB->pCloseButtonImage != NULL) { - unsigned int closeImageWidth; - drgui_get_image_size(pTB->pCloseButtonImage, &closeImageWidth, NULL); - - closeButtonWidth = closeImageWidth + pTB->closeButtonPaddingLeft; - } - - - if (pWidthOut) { - *pWidthOut = textWidth + closeButtonWidth + pTB->tabPadding*2; - } - if (pHeightOut) { - *pHeightOut = textHeight + pTB->tabPadding*2; - } -} - -DRGUI_PRIVATE void drgui_tabbar_on_paint_tab_default(drgui_element* pTBElement, drgui_tab* pTab, drgui_rect relativeClippingRect, float offsetX, float offsetY, float width, float height, void* pPaintData) -{ - (void)relativeClippingRect; - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - // Background. - drgui_color bgcolor = pTB->tabBackgroundColor; - drgui_color closeButtonColor = pTB->closeButtonColorDefault; - drgui_color textColor = pTB->tabTextColor; - - if (pTB->pHoveredTab == pTab) { - bgcolor = pTB->tabBackgroundColorHovered; - closeButtonColor = pTB->closeButtonColorTabHovered; - textColor = pTB->tabTextColorHovered; - } - if (pTB->pActiveTab == pTab) { - bgcolor = pTB->tabBackbroundColorActivated; - closeButtonColor = pTB->closeButtonColorTabHovered; - textColor = pTB->tabTextColorActivated; - } - - if (pTB->pHoveredTab == pTab && pTB->isCloseButtonHovered) { - closeButtonColor = pTB->closeButtonColorHovered; - - if (pTB->pTabWithCloseButtonPressed == pTB->pHoveredTab) { - closeButtonColor = pTB->closeButtonColorPressed; - } - } - - drgui_draw_rect_outline(pTBElement, drgui_make_rect(offsetX, offsetY, offsetX + width, offsetY + height), bgcolor, pTB->tabPadding, pPaintData); - - - // Text. - float textPosX = offsetX + pTB->tabPadding; - float textPosY = offsetY + pTB->tabPadding; - if (pTab != NULL) { - drgui_draw_text(pTBElement, pTB->pFont, pTab->text, (int)strlen(pTab->text), textPosX, textPosY, textColor, bgcolor, pPaintData); - } - - - // Close button. - if (pTB->isShowingCloseButton && pTB->pCloseButtonImage != NULL) - { - float textWidth = 0; - float textHeight = 0; - if (pTab != NULL) { - drgui_measure_string(pTB->pFont, pTab->text, strlen(pTab->text), &textWidth, &textHeight); - } - - float closeButtonPosX = textPosX + textWidth + pTB->closeButtonPaddingLeft; - float closeButtonPosY = textPosY; - - unsigned int iconWidth; - unsigned int iconHeight; - drgui_get_image_size(pTB->pCloseButtonImage, &iconWidth, &iconHeight); - - drgui_draw_image_args args; - args.dstX = closeButtonPosX; - args.dstY = closeButtonPosY; - args.dstWidth = (float)iconWidth; - args.dstHeight = (float)iconHeight; - args.srcX = 0; - args.srcY = 0; - args.srcWidth = (float)iconWidth; - args.srcHeight = (float)iconHeight; - args.dstBoundsX = args.dstX; - args.dstBoundsY = args.dstY; - args.dstBoundsWidth = (float)iconWidth; - args.dstBoundsHeight = height - (pTB->tabPadding*2); - args.foregroundTint = closeButtonColor; - args.backgroundColor = bgcolor; - args.boundsColor = bgcolor; - args.options = DRGUI_IMAGE_DRAW_BACKGROUND | DRGUI_IMAGE_DRAW_BOUNDS | DRGUI_IMAGE_CLIP_BOUNDS | DRGUI_IMAGE_ALIGN_CENTER; - drgui_draw_image(pTBElement, pTB->pCloseButtonImage, &args, pPaintData); - - - /// Space between the text and the padding. - drgui_draw_rect(pTBElement, drgui_make_rect(textPosX + textWidth, textPosY, closeButtonPosX, textPosY + textHeight), bgcolor, pPaintData); - } -} - -DRGUI_PRIVATE drgui_tab* drgui_tabbar_find_tab_under_point(drgui_element* pTBElement, float relativePosX, float relativePosY, bool* pIsOverCloseButtonOut) -{ - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - unsigned int closeButtonWidth; - unsigned int closeButtonHeight; - drgui_get_image_size(pTB->pCloseButtonImage, &closeButtonWidth, &closeButtonHeight); - - float runningPosX = 0; - float runningPosY = 0; - for (drgui_tab* pTab = pTB->pFirstTab; pTab != NULL; pTab = pTab->pNextTab) - { - float tabWidth = 0; - float tabHeight = 0; - drgui_tabbar_measure_tab(pTBElement, pTab, &tabWidth, &tabHeight); - - if (relativePosX >= runningPosX && relativePosX < runningPosX + tabWidth && relativePosY >= runningPosY && relativePosY < runningPosY + tabHeight) - { - if (pIsOverCloseButtonOut) - { - // The close button is in the center, vertically. - drgui_rect closeButtonRect; - closeButtonRect.left = runningPosX + tabWidth - (pTB->tabPadding + closeButtonWidth); - closeButtonRect.right = closeButtonRect.left + closeButtonWidth; - closeButtonRect.top = runningPosY + (tabHeight - (pTB->tabPadding + closeButtonHeight))/2; - closeButtonRect.bottom = closeButtonRect.top + closeButtonHeight; - - if (pTB->isShowingCloseButton && drgui_rect_contains_point(closeButtonRect, relativePosX, relativePosY)) { - *pIsOverCloseButtonOut = true; - } else { - *pIsOverCloseButtonOut = false; - } - } - - return pTab; - } - - if (pTB->orientation == drgui_tabbar_orientation_top || pTB->orientation == drgui_tabbar_orientation_bottom) { - runningPosX += tabWidth; - } else { - runningPosY += tabHeight; - } - } - - - if (pIsOverCloseButtonOut) { - *pIsOverCloseButtonOut = false; - } - - return NULL; -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tab -// -/////////////////////////////////////////////////////////////////////////////// - -/// Appends the given tab to the given tab bar. -DRGUI_PRIVATE void tab_append(drgui_tab* pTab, drgui_element* pTBElement); - -/// Prepends the given tab to the given tab bar. -DRGUI_PRIVATE void tab_prepend(drgui_tab* pTab, drgui_element* pTBElement); - -/// Detaches the given tab bar from it's tab bar element's hierarchy. -/// -/// @remarks -/// This does not deactivate the tab or what - it only detaches the tab from the hierarchy. -DRGUI_PRIVATE void tab_detach_from_hierarchy(drgui_tab* pTab); - -/// Detaches the given tab bar from it's tab bar element. -DRGUI_PRIVATE void tab_detach(drgui_tab* pTab); - -DRGUI_PRIVATE drgui_tab* tb_create_tab(drgui_element* pTBElement, const char* text, size_t extraDataSize, const void* pExtraData) -{ - if (pTBElement == NULL) { - return NULL; - } - - drgui_tab* pTab = (drgui_tab*)malloc(sizeof(*pTab) + extraDataSize); - if (pTab == NULL) { - return NULL; - } - - pTab->pTBElement = NULL; - pTab->pNextTab = NULL; - pTab->pPrevTab = NULL; - pTab->text[0] = '\0'; - - pTab->extraDataSize = extraDataSize; - if (pExtraData) { - memcpy(pTab->pExtraData, pExtraData, extraDataSize); - } - - if (text != NULL) { - drgui__strncpy_s(pTab->text, sizeof(pTab->text), text, (size_t)-1); // -1 = _TRUNCATE - } - - return pTab; -} - -drgui_tab* drgui_tabbar_create_and_append_tab(drgui_element* pTBElement, const char* text, size_t extraDataSize, const void* pExtraData) -{ - drgui_tab* pTab = (drgui_tab*)tb_create_tab(pTBElement, text, extraDataSize, pExtraData); - if (pTab != NULL) - { - tab_append(pTab, pTBElement); - } - - return pTab; -} - -drgui_tab* drgui_tabbar_create_and_prepend_tab(drgui_element* pTBElement, const char* text, size_t extraDataSize, const void* pExtraData) -{ - drgui_tab* pTab = (drgui_tab*)tb_create_tab(pTBElement, text, extraDataSize, pExtraData); - if (pTab != NULL) - { - tab_prepend(pTab, pTBElement); - } - - return pTab; -} - -void drgui_tab_delete(drgui_tab* pTab) -{ - if (pTab == NULL) { - return; - } - - tab_detach(pTab); - free(pTab); -} - -drgui_element* drgui_tab_get_tab_bar_element(drgui_tab* pTab) -{ - if (pTab == NULL) { - return NULL; - } - - return pTab->pTBElement; -} - -size_t drgui_tab_get_extra_data_size(drgui_tab* pTab) -{ - if (pTab == NULL) { - return 0; - } - - return pTab->extraDataSize; -} - -void* drgui_tab_get_extra_data(drgui_tab* pTab) -{ - if (pTab == NULL) { - return NULL; - } - - return pTab->pExtraData; -} - - -void drgui_tab_set_text(drgui_tab* pTab, const char* text) -{ - if (pTab == NULL) { - return; - } - - if (text != NULL) { - drgui__strncpy_s(pTab->text, sizeof(pTab->text), text, (size_t)-1); // -1 = _TRUNCATE - } else { - pTab->text[0] = '\0'; - } - - // The content of the menu has changed so we'll need to schedule a redraw. - if (drgui_is_auto_dirty_enabled(pTab->pTBElement->pContext)) { - drgui_dirty(pTab->pTBElement, drgui_get_local_rect(pTab->pTBElement)); - } -} - -const char* drgui_tab_get_text(drgui_tab* pTab) -{ - if (pTab == NULL) { - return NULL; - } - - return pTab->text; -} - - -drgui_tab* drgui_tab_get_next_tab(drgui_tab* pTab) -{ - if (pTab == NULL) { - return NULL; - } - - return pTab->pNextTab; -} - -drgui_tab* drgui_tab_get_prev_tab(drgui_tab* pTab) -{ - if (pTab == NULL) { - return NULL; - } - - return pTab->pPrevTab; -} - - -void drgui_tab_move_to_front(drgui_tab* pTab) -{ - if (pTab == NULL) { - return; - } - - drgui_element* pTBElement = pTab->pTBElement; - - tab_detach_from_hierarchy(pTab); - tab_prepend(pTab, pTBElement); -} - -bool drgui_tab_is_in_view(drgui_tab* pTab) -{ - if (pTab == NULL) { - return false; - } - - return drgui_tabbar_is_tab_in_view(pTab->pTBElement, pTab); -} - -void drgui_tab_move_into_view(drgui_tab* pTab) -{ - if (!drgui_tab_is_in_view(pTab)) { - drgui_tab_move_to_front(pTab); - } -} - - - - -DRGUI_PRIVATE void tab_append(drgui_tab* pTab, drgui_element* pTBElement) -{ - if (pTab == NULL || pTBElement == NULL) { - return; - } - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - pTab->pTBElement = pTBElement; - if (pTB->pFirstTab == NULL) - { - assert(pTB->pLastTab == NULL); - - pTB->pFirstTab = pTab; - pTB->pLastTab = pTab; - } - else - { - assert(pTB->pLastTab != NULL); - - pTab->pPrevTab = pTB->pLastTab; - - pTB->pLastTab->pNextTab = pTab; - pTB->pLastTab = pTab; - } - - - if (pTB->isAutoSizeEnabled) { - drgui_tabbar_resize_by_tabs(pTBElement); - } - - // The content of the menu has changed so we'll need to schedule a redraw. - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -DRGUI_PRIVATE void tab_prepend(drgui_tab* pTab, drgui_element* pTBElement) -{ - if (pTab == NULL || pTBElement == NULL) { - return; - } - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - pTab->pTBElement = pTBElement; - if (pTB->pFirstTab == NULL) - { - assert(pTB->pLastTab == NULL); - - pTB->pFirstTab = pTab; - pTB->pLastTab = pTab; - } - else - { - assert(pTB->pLastTab != NULL); - - pTab->pNextTab = pTB->pFirstTab; - - pTB->pFirstTab->pPrevTab = pTab; - pTB->pFirstTab = pTab; - } - - - if (pTB->isAutoSizeEnabled) { - drgui_tabbar_resize_by_tabs(pTBElement); - } - - // The content of the menu has changed so we'll need to schedule a redraw. - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} - -DRGUI_PRIVATE void tab_detach_from_hierarchy(drgui_tab* pTab) -{ - if (pTab == NULL) { - return; - } - - drgui_element* pTBElement = pTab->pTBElement; - if (pTBElement == NULL) { - return; - } - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - - if (pTab->pNextTab != NULL) { - pTab->pNextTab->pPrevTab = pTab->pPrevTab; - } - - if (pTab->pPrevTab != NULL) { - pTab->pPrevTab->pNextTab = pTab->pNextTab; - } - - - if (pTab == pTB->pFirstTab) { - pTB->pFirstTab = pTab->pNextTab; - } - - if (pTab == pTB->pLastTab) { - pTB->pLastTab = pTab->pPrevTab; - } - - - pTab->pNextTab = NULL; - pTab->pPrevTab = NULL; - pTab->pTBElement = NULL; -} - -DRGUI_PRIVATE void tab_detach(drgui_tab* pTab) -{ - if (pTab == NULL) { - return; - } - - drgui_element* pTBElement = pTab->pTBElement; - if (pTBElement == NULL) { - return; - } - - drgui_tab_bar* pTB = (drgui_tab_bar*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - if (pTB->pHoveredTab == pTab) { - pTB->pHoveredTab = NULL; - pTB->isCloseButtonHovered = false; - } - - if (pTB->pActiveTab == pTab) { - pTB->pActiveTab = NULL; - } - - if (pTB->pTabWithCloseButtonPressed == pTab) { - pTB->pTabWithCloseButtonPressed = NULL; - } - - - tab_detach_from_hierarchy(pTab); - - - if (pTB->isAutoSizeEnabled) { - drgui_tabbar_resize_by_tabs(pTBElement); - } - - // The content of the menu has changed so we'll need to schedule a redraw. - if (drgui_is_auto_dirty_enabled(pTBElement->pContext)) { - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); - } -} -#endif //DR_GUI_IMPLEMENTATION - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Text Box -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -#ifndef DRGUI_NO_TEXT_EDITING -// QUICK NOTES -// -// - By default the cursor/caret does not blink automatically. Instead, the application must "step" the text box by -// calling drgui_textbox_step(). - -#ifndef drgui_textbox_h -#define drgui_textbox_h - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (* drgui_textbox_on_cursor_move_proc)(drgui_element* pTBElement); -typedef void (* drgui_textbox_on_undo_point_changed_proc)(drgui_element* pTBElement, unsigned int iUndoPoint); - - -/// Creates a new text box control. -drgui_element* drgui_create_textbox(drgui_context* pContext, drgui_element* pParent, size_t extraDataSize, const void* pExtraData); - -/// Deletest the given text box control. -void drgui_delete_textbox(drgui_element* pTBElement); - - -/// Retrieves the size of the extra data associated with the given text box. -size_t drgui_textbox_get_extra_data_size(drgui_element* pTBElement); - -/// Retrieves a pointer to the extra data associated with the given text box. -void* drgui_textbox_get_extra_data(drgui_element* pTBElement); - - -/// Sets the font to use with the given text box. -void drgui_textbox_set_font(drgui_element* pTBElement, drgui_font* pFont); - -/// Retrieves the font being used with the given text box. -drgui_font* drgui_textbox_get_font(drgui_element* pTBElement); - -/// Sets the color of the text in teh given text box. -void drgui_textbox_set_text_color(drgui_element* pTBElement, drgui_color color); - -/// Sets the background color of the given text box. -void drgui_textbox_set_background_color(drgui_element* pTBElement, drgui_color color); - -/// Sets the background color of selected text. -void drgui_textbox_set_selection_background_color(drgui_element* pTBElement, drgui_color color); - -/// Retrieves the background color of selected text. -drgui_color drgui_textbox_get_selection_background_color(drgui_element* pTBElement); - -/// Sets the background color for the line the caret is currently sitting on. -void drgui_textbox_set_active_line_background_color(drgui_element* pTBElement, drgui_color color); - -/// Sets the width of the text cursor. -void drgui_textbox_set_cursor_width(drgui_element* pTBElement, float cursorWidth); - -/// Retrieves the width of the text cursor. -float drgui_textbox_get_cursor_width(drgui_element* pTBElement); - -/// Sets the color of the cursor of the given text box. -void drgui_textbox_set_cursor_color(drgui_element* pTBElement, drgui_color color); - -/// Sets the border color of the given text box. -void drgui_textbox_set_border_color(drgui_element* pTBElement, drgui_color color); - -/// Sets the border width of the given text box. -void drgui_textbox_set_border_width(drgui_element* pTBElement, float borderWidth); - -/// Sets the amount of padding to apply to given text box. -void drgui_textbox_set_padding(drgui_element* pTBElement, float padding); - -/// Retrieves the amound of vertical padding to apply to the given text box. -float drgui_textbox_get_padding_vert(drgui_element* pTBElement); - -/// Retrieves the amound of horizontal padding to apply to the given text box. -float drgui_textbox_get_padding_horz(drgui_element* pTBElement); - -/// Sets the vertical alignment of the given text box. -void drgui_textbox_set_vertical_align(drgui_element* pTBElement, drgui_text_engine_alignment align); - -/// Sets the horizontal alignment of the given text box. -void drgui_textbox_set_horizontal_align(drgui_element* pTBElement, drgui_text_engine_alignment align); - -// Sets the width of the line numbers. -void drgui_textbox_set_line_numbers_width(drgui_element* pTBElement, float lineNumbersWidth); - -// Retrieves the width of the line numbers. -float drgui_textbox_get_line_numbers_width(drgui_element* pTBElement); - -// Sets the padding to apply between the line numbers and the text. -void drgui_textbox_set_line_numbers_padding(drgui_element* pTBElement, float lineNumbersPadding); - -// Retrieves the padding to apply between the line numbers and the text. -float drgui_textbox_get_line_numbers_padding(drgui_element* pTBElement); - -// Sets the color of the text of the line numbers. -void drgui_textbox_set_line_numbers_color(drgui_element* pTBElement, drgui_color color); - -// Retrieves the color of the text of the line numbers. -drgui_color drgui_textbox_get_line_numbers_color(drgui_element* pTBElement); - -// Sets the color of the background of the line numbers. -void drgui_textbox_set_line_numbers_background_color(drgui_element* pTBElement, drgui_color color); - -// Retrieves the color of the background of the line numbers. -drgui_color drgui_textbox_get_line_numbers_background_color(drgui_element* pTBElement); - - -/// Sets the text of the given text box. -void drgui_textbox_set_text(drgui_element* pTBElement, const char* text); - -/// Retrieves the text of the given text box. -size_t drgui_textbox_get_text(drgui_element* pTBElement, char* pTextOut, size_t textOutSize); - -/// Steps the text box to allow it to blink the cursor. -void drgui_textbox_step(drgui_element* pTBElement, unsigned int milliseconds); - -/// Sets the blink rate of the cursor in milliseconds. -void drgui_textbox_set_cursor_blink_rate(drgui_element* pTBElement, unsigned int blinkRateInMilliseconds); - -/// Moves the caret to the end of the text. -void drgui_textbox_move_cursor_to_end_of_text(drgui_element* pTBElement); - -/// Moves the caret to the beginning of the line at the given index. -void drgui_textbox_move_cursor_to_start_of_line_by_index(drgui_element* pTBElement, size_t iLine); - -/// Determines whether or not anything is selected in the given text box. -bool drgui_textbox_is_anything_selected(drgui_element* pTBElement); - -/// Selects all of the text inside the text box. -void drgui_textbox_select_all(drgui_element* pTBElement); - -/// Deselect everything. -void drgui_textbox_deselect_all(drgui_element* pTBElement); - -/// Retrieves a copy of the selected text. -/// -/// @remarks -/// This returns the length of the selected text. Call this once with set to NULL to calculate the required size of the -/// buffer. -/// @par -/// If the output buffer is not larger enough, the string will be truncated. -size_t drgui_textbox_get_selected_text(drgui_element* pTBElement, char* textOut, size_t textOutLength); - -/// Deletes the character to the right of the cursor. -/// -/// @return True if the text within the text engine has changed. -bool drgui_textbox_delete_character_to_right_of_cursor(drgui_element* pTBElement); - -/// Deletes the currently selected text. -/// -/// @return True if the text within the text engine has changed. -bool drgui_textbox_delete_selected_text(drgui_element* pTBElement); - -/// Inserts a character at the position of the cursor. -/// -/// @return True if the text within the text engine has changed. -bool drgui_textbox_insert_text_at_cursor(drgui_element* pTBElement, const char* text); - -/// Performs an undo operation. -bool drgui_textbox_undo(drgui_element* pTBElement); - -/// Performs a redo operation. -bool drgui_textbox_redo(drgui_element* pTBElement); - -/// Retrieves the number of undo points remaining. -unsigned int drgui_textbox_get_undo_points_remaining_count(drgui_element* pTBElement); - -/// Retrieves the number of redo points remaining. -unsigned int drgui_textbox_get_redo_points_remaining_count(drgui_element* pTBElement); - -/// Clears the undo/redo stack. -void drgui_textbox_clear_undo_stack(drgui_element* pTBElement); - -/// Retrieves the index of the line the cursor is current sitting on. -size_t drgui_textbox_get_cursor_line(drgui_element* pTBElement); - -/// Retrieves the index of the column the cursor is current sitting on. -size_t drgui_textbox_get_cursor_column(drgui_element* pTBElement); - -/// Retrieves the number of lines in the given text box. -size_t drgui_textbox_get_line_count(drgui_element* pTBElement); - - -/// Finds and selects the next occurance of the given string, starting from the cursor and looping back to the start. -bool drgui_textbox_find_and_select_next(drgui_element* pTBElement, const char* text); - -/// Finds the next occurance of the given string and replaces it with another. -bool drgui_textbox_find_and_replace_next(drgui_element* pTBElement, const char* text, const char* replacement); - -/// Finds every occurance of the given string and replaces it with another. -bool drgui_textbox_find_and_replace_all(drgui_element* pTBElement, const char* text, const char* replacement); - - -/// Shows the line numbers. -void drgui_textbox_show_line_numbers(drgui_element* pTBElement); - -/// Hides the line numbers. -void drgui_textbox_hide_line_numbers(drgui_element* pTBElement); - - -/// Disables the vertical scrollbar. -void drgui_textbox_disable_vertical_scrollbar(drgui_element* pTBElement); - -/// Enables the vertical scrollbar. -void drgui_textbox_enable_vertical_scrollbar(drgui_element* pTBElement); - -/// Disables the horizontal scrollbar. -void drgui_textbox_disable_horizontal_scrollbar(drgui_element* pTBElement); - -/// Enables the horizontal scrollbar. -void drgui_textbox_enable_horizontal_scrollbar(drgui_element* pTBElement); - -// Retrieves the vertical scrollbar. -drgui_element* drgui_textbox_get_vertical_scrollbar(drgui_element* pTBElement); - -// Retrieves the horizontal scrollbar. -drgui_element* drgui_textbox_get_horizontal_scrollbar(drgui_element* pTBElement); - -// Sets the size of both the vertical and horizontal scrollbars. -void drgui_textbox_set_scrollbar_size(drgui_element* pTBElement, float size); - - -/// Sets the function to call when the cursor moves. -void drgui_textbox_set_on_cursor_move(drgui_element* pTBElement, drgui_textbox_on_cursor_move_proc proc); - -/// Sets the function to call when the undo point changes. -void drgui_textbox_set_on_undo_point_changed(drgui_element* pTBElement, drgui_textbox_on_undo_point_changed_proc proc); - - - -/// on_size. -void drgui_textbox_on_size(drgui_element* pTBElement, float newWidth, float newHeight); - -/// on_mouse_move. -void drgui_textbox_on_mouse_move(drgui_element* pTBElement, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// on_mouse_button_down. -void drgui_textbox_on_mouse_button_down(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// on_mouse_button_up. -void drgui_textbox_on_mouse_button_up(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// on_mouse_button_dblclick. -void drgui_textbox_on_mouse_button_dblclick(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// on_mouse_wheel -void drgui_textbox_on_mouse_wheel(drgui_element* pTBElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// on_key_down. -void drgui_textbox_on_key_down(drgui_element* pTBElement, drgui_key key, int stateFlags); - -/// on_key_up. -void drgui_textbox_on_key_up(drgui_element* pTBElement, drgui_key key, int stateFlags); - -/// on_printable_key_down. -void drgui_textbox_on_printable_key_down(drgui_element* pTBElement, unsigned int utf32, int stateFlags); - -/// on_paint. -void drgui_textbox_on_paint(drgui_element* pTBElement, drgui_rect relativeRect, void* pPaintData); - -/// on_capture_keyboard -void drgui_textbox_on_capture_keyboard(drgui_element* pTBElement, drgui_element* pPrevCapturedElement); - -/// on_release_keyboard -void drgui_textbox_on_release_keyboard(drgui_element* pTBElement, drgui_element* pNewCapturedElement); - -/// on_capture_mouse -void drgui_textbox_on_capture_mouse(drgui_element* pTBElement); - -/// on_release_mouse -void drgui_textbox_on_release_mouse(drgui_element* pTBElement); - - - -#ifdef __cplusplus -} -#endif -#endif //drgui_textbox_h - - -#ifdef DR_GUI_IMPLEMENTATION -typedef struct -{ - /// The text engine. - drgui_text_engine* pTL; - - /// The vertical scrollbar. - drgui_element* pVertScrollbar; - - /// The horizontal scrollbar. - drgui_element* pHorzScrollbar; - - /// The line numbers element. - drgui_element* pLineNumbers; - - - /// The color of the border. - drgui_color borderColor; - - /// The width of the border. - float borderWidth; - - /// The amount of padding to apply the left and right of the text. - float padding; - - // The width of the line numbers. - float lineNumbersWidth; - - /// The padding to the right of the line numbers. - float lineNumbersPaddingRight; - - // The color of the text of the line numbers. - drgui_color lineNumbersColor; - - // The color of the background of the line numbers. - drgui_color lineNumbersBackgroundColor; - - - /// The desired width of the vertical scrollbar. - float vertScrollbarSize; - - /// The desired height of the horizontal scrollbar. - float horzScrollbarSize; - - /// Whether or not the vertical scrollbar is enabled. - bool isVertScrollbarEnabled; - - /// Whether or not the horizontal scrollbar is enabled. - bool isHorzScrollbarEnabled; - - - /// When selecting lines by clicking and dragging on the line numbers, keeps track of the line to anchor the selection to. - size_t iLineSelectAnchor; - - - /// The function to call when the text cursor/caret moves. - drgui_textbox_on_cursor_move_proc onCursorMove; - - /// The function to call when the undo point changes. - drgui_textbox_on_undo_point_changed_proc onUndoPointChanged; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data. - char pExtraData[1]; - -} drgui_textbox; - - -/// Retrieves the offset to draw the text in the text box. -DRGUI_PRIVATE void drgui_textbox__get_text_offset(drgui_element* pTBElement, float* pOffsetXOut, float* pOffsetYOut); - -/// Calculates the required size of the text engine. -DRGUI_PRIVATE void drgui_textbox__calculate_text_engine_container_size(drgui_element* pTBElement, float* pWidthOut, float* pHeightOut); - -/// Retrieves the rectangle of the text engine's container. -DRGUI_PRIVATE drgui_rect drgui_textbox__get_text_rect(drgui_element* pTBElement); - -/// Refreshes the range, page sizes and layouts of the scrollbars. -DRGUI_PRIVATE void drgui_textbox__refresh_scrollbars(drgui_element* pTBElement); - -/// Refreshes the range and page sizes of the scrollbars. -DRGUI_PRIVATE void drgui_textbox__refresh_scrollbar_ranges(drgui_element* pTBElement); - -/// Refreshes the size and position of the scrollbars. -DRGUI_PRIVATE void drgui_textbox__refresh_scrollbar_layouts(drgui_element* pTBElement); - -/// Retrieves a rectangle representing the space between the edges of the two scrollbars. -DRGUI_PRIVATE drgui_rect drgui_textbox__get_scrollbar_dead_space_rect(drgui_element* pTBElement); - - -/// Called when a mouse button is pressed on the line numbers element. -DRGUI_PRIVATE void drgui_textbox__on_mouse_move_line_numbers(drgui_element* pLineNumbers, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when a mouse button is pressed on the line numbers element. -DRGUI_PRIVATE void drgui_textbox__on_mouse_button_down_line_numbers(drgui_element* pLineNumbers, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when a mouse button is pressed on the line numbers element. -DRGUI_PRIVATE void drgui_textbox__on_mouse_button_up_line_numbers(drgui_element* pLineNumbers, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the line numbers element needs to be drawn. -DRGUI_PRIVATE void drgui_textbox__on_paint_line_numbers(drgui_element* pLineNumbers, drgui_rect relativeRect, void* pPaintData); - -/// Refreshes the line number of the given text editor. -DRGUI_PRIVATE void drgui_textbox__refresh_line_numbers(drgui_element* pTBElement); - - -/// on_paint_rect() -DRGUI_PRIVATE void drgui_textbox__on_text_engine_paint_rect(drgui_text_engine* pLayout, drgui_rect rect, drgui_color color, drgui_element* pTBElement, void* pPaintData); - -/// on_paint_text() -DRGUI_PRIVATE void drgui_textbox__on_text_engine_paint_text(drgui_text_engine* pTL, drgui_text_run* pRun, drgui_element* pTBElement, void* pPaintData); - -/// on_dirty() -DRGUI_PRIVATE void drgui_textbox__on_text_engine_dirty(drgui_text_engine* pTL, drgui_rect rect); - -/// on_cursor_move() -DRGUI_PRIVATE void drgui_textbox__on_text_engine_cursor_move(drgui_text_engine* pTL); - -/// on_text_changed() -DRGUI_PRIVATE void drgui_textbox__on_text_engine_text_changed(drgui_text_engine* pTL); - -/// on_undo_point_changed() -DRGUI_PRIVATE void drgui_textbox__on_text_engine_undo_point_changed(drgui_text_engine* pTL, unsigned int iUndoPoint); - - -DRGUI_PRIVATE void drgui_textbox__on_vscroll(drgui_element* pSBElement, int scrollPos) -{ - drgui_element* pTBElement = *(drgui_element**)drgui_sb_get_extra_data(pSBElement); - assert(pTBElement != NULL); - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - drgui_text_engine_set_inner_offset_y(pTB->pTL, -drgui_text_engine_get_line_pos_y(pTB->pTL, scrollPos)); - - // The line numbers need to be redrawn. - drgui_dirty(pTB->pLineNumbers, drgui_get_local_rect(pTB->pLineNumbers)); -} - -DRGUI_PRIVATE void drgui_textbox__on_hscroll(drgui_element* pSBElement, int scrollPos) -{ - drgui_element* pTBElement = *(drgui_element**)drgui_sb_get_extra_data(pSBElement); - assert(pTBElement != NULL); - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - drgui_text_engine_set_inner_offset_x(pTB->pTL, (float)-scrollPos); -} - - - -drgui_element* drgui_create_textbox(drgui_context* pContext, drgui_element* pParent, size_t extraDataSize, const void* pExtraData) -{ - if (pContext == NULL) { - return NULL; - } - - drgui_element* pTBElement = drgui_create_element(pContext, pParent, sizeof(drgui_textbox) + extraDataSize, NULL); - if (pTBElement == NULL) { - return NULL; - } - - drgui_set_cursor(pTBElement, drgui_cursor_text); - drgui_set_on_size(pTBElement, drgui_textbox_on_size); - drgui_set_on_mouse_move(pTBElement, drgui_textbox_on_mouse_move); - drgui_set_on_mouse_button_down(pTBElement, drgui_textbox_on_mouse_button_down); - drgui_set_on_mouse_button_up(pTBElement, drgui_textbox_on_mouse_button_up); - drgui_set_on_mouse_button_dblclick(pTBElement, drgui_textbox_on_mouse_button_dblclick); - drgui_set_on_mouse_wheel(pTBElement, drgui_textbox_on_mouse_wheel); - drgui_set_on_key_down(pTBElement, drgui_textbox_on_key_down); - drgui_set_on_printable_key_down(pTBElement, drgui_textbox_on_printable_key_down); - drgui_set_on_paint(pTBElement, drgui_textbox_on_paint); - drgui_set_on_capture_keyboard(pTBElement, drgui_textbox_on_capture_keyboard); - drgui_set_on_release_keyboard(pTBElement, drgui_textbox_on_release_keyboard); - drgui_set_on_capture_mouse(pTBElement, drgui_textbox_on_capture_mouse); - drgui_set_on_release_mouse(pTBElement, drgui_textbox_on_release_mouse); - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - pTB->pVertScrollbar = drgui_create_scrollbar(pContext, pTBElement, drgui_sb_orientation_vertical, sizeof(pTBElement), &pTBElement); - drgui_sb_set_on_scroll(pTB->pVertScrollbar, drgui_textbox__on_vscroll); - drgui_sb_set_mouse_wheel_scele(pTB->pVertScrollbar, 3); - - pTB->pHorzScrollbar = drgui_create_scrollbar(pContext, pTBElement, drgui_sb_orientation_horizontal, sizeof(pTBElement), &pTBElement); - drgui_sb_set_on_scroll(pTB->pHorzScrollbar, drgui_textbox__on_hscroll); - - pTB->pLineNumbers = drgui_create_element(pContext, pTBElement, sizeof(pTBElement), &pTBElement); - drgui_hide(pTB->pLineNumbers); - drgui_set_on_mouse_move(pTB->pLineNumbers, drgui_textbox__on_mouse_move_line_numbers); - drgui_set_on_mouse_button_down(pTB->pLineNumbers, drgui_textbox__on_mouse_button_down_line_numbers); - drgui_set_on_mouse_button_up(pTB->pLineNumbers, drgui_textbox__on_mouse_button_up_line_numbers); - drgui_set_on_paint(pTB->pLineNumbers, drgui_textbox__on_paint_line_numbers); - - pTB->pTL = drgui_create_text_engine(pContext, sizeof(pTBElement), &pTBElement); - if (pTB->pTL == NULL) { - drgui_delete_element(pTBElement); - return NULL; - } - - drgui_text_engine_set_on_paint_rect(pTB->pTL, drgui_textbox__on_text_engine_paint_rect); - drgui_text_engine_set_on_paint_text(pTB->pTL, drgui_textbox__on_text_engine_paint_text); - drgui_text_engine_set_on_dirty(pTB->pTL, drgui_textbox__on_text_engine_dirty); - drgui_text_engine_set_on_cursor_move(pTB->pTL, drgui_textbox__on_text_engine_cursor_move); - drgui_text_engine_set_on_text_changed(pTB->pTL, drgui_textbox__on_text_engine_text_changed); - drgui_text_engine_set_on_undo_point_changed(pTB->pTL, drgui_textbox__on_text_engine_undo_point_changed); - drgui_text_engine_set_default_text_color(pTB->pTL, drgui_rgb(0, 0, 0)); - drgui_text_engine_set_cursor_color(pTB->pTL, drgui_rgb(0, 0, 0)); - drgui_text_engine_set_default_bg_color(pTB->pTL, drgui_rgb(255, 255, 255)); - drgui_text_engine_set_active_line_bg_color(pTB->pTL, drgui_rgb(255, 255, 255)); - drgui_text_engine_set_vertical_align(pTB->pTL, drgui_text_engine_alignment_center); - - pTB->borderColor = drgui_rgb(0, 0, 0); - pTB->borderWidth = 1; - pTB->padding = 2; - pTB->lineNumbersWidth = 64; - pTB->lineNumbersPaddingRight = 16; - pTB->lineNumbersColor = drgui_rgb(80, 160, 192); - pTB->lineNumbersBackgroundColor = drgui_text_engine_get_default_bg_color(pTB->pTL); - pTB->vertScrollbarSize = 16; - pTB->horzScrollbarSize = 16; - pTB->isVertScrollbarEnabled = true; - pTB->isHorzScrollbarEnabled = true; - pTB->iLineSelectAnchor = 0; - pTB->onCursorMove = NULL; - pTB->onUndoPointChanged = NULL; - - pTB->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pTB->pExtraData, pExtraData, extraDataSize); - } - - return pTBElement; -} - -void drgui_delete_textbox(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->pTL) { - drgui_delete_text_engine(pTB->pTL); - pTB->pTL = NULL; - } - - if (pTB->pLineNumbers) { - drgui_delete_element(pTB->pLineNumbers); - pTB->pLineNumbers = NULL; - } - - if (pTB->pHorzScrollbar) { - drgui_delete_element(pTB->pHorzScrollbar); - pTB->pHorzScrollbar = NULL; - } - - if (pTB->pVertScrollbar) { - drgui_delete_element(pTB->pVertScrollbar); - pTB->pVertScrollbar = NULL; - } - - drgui_delete_element(pTBElement); -} - -size_t drgui_textbox_get_extra_data_size(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->extraDataSize; -} - -void* drgui_textbox_get_extra_data(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pExtraData; -} - - -void drgui_textbox_set_font(drgui_element* pTBElement, drgui_font* pFont) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_begin_dirty(pTBElement); - { - drgui_text_engine_set_default_font(pTB->pTL, pFont); - - // The font used for line numbers are tied to the main font at the moment. - drgui_textbox__refresh_line_numbers(pTBElement); - - // Emulate a scroll to ensure the scroll position is pinned to a line. - drgui_textbox__on_vscroll(pTB->pVertScrollbar, drgui_sb_get_scroll_position(pTB->pVertScrollbar)); - drgui_textbox__refresh_scrollbars(pTBElement); - - // The caret position needs to be refreshes. We'll cheat here a little bit and just do a full refresh of the text engine. - //drgui_text_engine__refresh(pTB->pTL); - drgui_text_engine_refresh_markers(pTB->pTL); - } - drgui_end_dirty(pTBElement); -} - -drgui_font* drgui_textbox_get_font(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return drgui_text_engine_get_default_font(pTB->pTL); -} - -void drgui_textbox_set_text_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_default_text_color(pTB->pTL, color); -} - -void drgui_textbox_set_background_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_default_bg_color(pTB->pTL, color); -} - -void drgui_textbox_set_selection_background_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_selection_bg_color(pTB->pTL, color); -} - -drgui_color drgui_textbox_get_selection_background_color(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return drgui_text_engine_get_selection_bg_color(pTB->pTL); -} - -void drgui_textbox_set_active_line_background_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_active_line_bg_color(pTB->pTL, color); -} - -void drgui_textbox_set_cursor_width(drgui_element* pTBElement, float cursorWidth) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_cursor_width(pTB->pTL, cursorWidth); -} - -float drgui_textbox_get_cursor_width(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return drgui_text_engine_get_cursor_width(pTB->pTL); -} - -void drgui_textbox_set_cursor_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_cursor_color(pTB->pTL, color); -} - -void drgui_textbox_set_border_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->borderColor = color; -} - -void drgui_textbox_set_border_width(drgui_element* pTBElement, float borderWidth) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->borderWidth = borderWidth; -} - -void drgui_textbox_set_padding(drgui_element* pTBElement, float padding) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->padding = padding; -} - -float drgui_textbox_get_padding_vert(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->padding; -} - -float drgui_textbox_get_padding_horz(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->padding; -} - -void drgui_textbox_set_vertical_align(drgui_element* pTBElement, drgui_text_engine_alignment align) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_vertical_align(pTB->pTL, align); -} - -void drgui_textbox_set_horizontal_align(drgui_element* pTBElement, drgui_text_engine_alignment align) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_horizontal_align(pTB->pTL, align); -} - -void drgui_textbox_set_line_numbers_width(drgui_element* pTBElement, float lineNumbersWidth) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->lineNumbersWidth = lineNumbersWidth; -} - -float drgui_textbox_get_line_numbers_width(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->lineNumbersWidth; -} - -void drgui_textbox_set_line_numbers_padding(drgui_element* pTBElement, float lineNumbersPadding) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->lineNumbersPaddingRight = lineNumbersPadding; -} - -float drgui_textbox_get_line_numbers_padding(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return pTB->lineNumbersPaddingRight; -} - -void drgui_textbox_set_line_numbers_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->lineNumbersColor = color; - drgui_textbox__refresh_line_numbers(pTBElement); -} - -drgui_color drgui_textbox_get_line_numbers_color(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTB->lineNumbersColor; -} - -void drgui_textbox_set_line_numbers_background_color(drgui_element* pTBElement, drgui_color color) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->lineNumbersBackgroundColor = color; - drgui_textbox__refresh_line_numbers(pTBElement); -} - -drgui_color drgui_textbox_get_line_numbers_background_color(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTB->lineNumbersBackgroundColor; -} - - - -void drgui_textbox_set_text(drgui_element* pTBElement, const char* text) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - drgui_text_engine_set_text(pTB->pTL, text); - } - drgui_text_engine_commit_undo_point(pTB->pTL); -} - -size_t drgui_textbox_get_text(drgui_element* pTBElement, char* pTextOut, size_t textOutSize) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return drgui_text_engine_get_text(pTB->pTL, pTextOut, textOutSize); -} - -void drgui_textbox_step(drgui_element* pTBElement, unsigned int milliseconds) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_step(pTB->pTL, milliseconds); -} - -void drgui_textbox_set_cursor_blink_rate(drgui_element* pTBElement, unsigned int blinkRateInMilliseconds) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_set_cursor_blink_rate(pTB->pTL, blinkRateInMilliseconds); -} - -void drgui_textbox_move_cursor_to_end_of_text(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_move_cursor_to_end_of_text(pTB->pTL); -} - -void drgui_textbox_move_cursor_to_start_of_line_by_index(drgui_element* pTBElement, size_t iLine) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_move_cursor_to_start_of_line_by_index(pTB->pTL, iLine); -} - - -bool drgui_textbox_is_anything_selected(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return drgui_text_engine_is_anything_selected(pTB->pTL); -} - -void drgui_textbox_select_all(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_select_all(pTB->pTL); -} - -void drgui_textbox_deselect_all(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_deselect_all(pTB->pTL); -} - -size_t drgui_textbox_get_selected_text(drgui_element* pTBElement, char* textOut, size_t textOutLength) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return drgui_text_engine_get_selected_text(pTB->pTL, textOut, textOutLength); -} - -bool drgui_textbox_delete_character_to_right_of_cursor(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - wasTextChanged = drgui_text_engine_delete_character_to_right_of_cursor(pTB->pTL); - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - - return wasTextChanged; -} - -bool drgui_textbox_delete_selected_text(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - wasTextChanged = drgui_text_engine_delete_selected_text(pTB->pTL); - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - - return wasTextChanged; -} - -bool drgui_textbox_insert_text_at_cursor(drgui_element* pTBElement, const char* text) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false;; - } - - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - wasTextChanged = drgui_text_engine_insert_text_at_cursor(pTB->pTL, text); - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - - return wasTextChanged; -} - -bool drgui_textbox_undo(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return drgui_text_engine_undo(pTB->pTL); -} - -bool drgui_textbox_redo(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return drgui_text_engine_redo(pTB->pTL); -} - -unsigned int drgui_textbox_get_undo_points_remaining_count(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return drgui_text_engine_get_undo_points_remaining_count(pTB->pTL); -} - -unsigned int drgui_textbox_get_redo_points_remaining_count(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return false; - } - - return drgui_text_engine_get_redo_points_remaining_count(pTB->pTL); -} - -void drgui_textbox_clear_undo_stack(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_clear_undo_stack(pTB->pTL); -} - - -size_t drgui_textbox_get_cursor_line(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return drgui_text_engine_get_cursor_line(pTB->pTL); -} - -size_t drgui_textbox_get_cursor_column(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return drgui_text_engine_get_cursor_column(pTB->pTL); -} - -size_t drgui_textbox_get_line_count(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - return drgui_text_engine_get_line_count(pTB->pTL); -} - - -bool drgui_textbox_find_and_select_next(drgui_element* pTBElement, const char* text) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - size_t selectionStart; - size_t selectionEnd; - if (drgui_text_engine_find_next(pTB->pTL, text, &selectionStart, &selectionEnd)) - { - drgui_text_engine_select(pTB->pTL, selectionStart, selectionEnd); - drgui_text_engine_move_cursor_to_end_of_selection(pTB->pTL); - - return true; - } - - return false; -} - -bool drgui_textbox_find_and_replace_next(drgui_element* pTBElement, const char* text, const char* replacement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - size_t selectionStart; - size_t selectionEnd; - if (drgui_text_engine_find_next(pTB->pTL, text, &selectionStart, &selectionEnd)) - { - drgui_text_engine_select(pTB->pTL, selectionStart, selectionEnd); - drgui_text_engine_move_cursor_to_end_of_selection(pTB->pTL); - - wasTextChanged = drgui_text_engine_delete_selected_text(pTB->pTL) || wasTextChanged; - wasTextChanged = drgui_text_engine_insert_text_at_cursor(pTB->pTL, replacement) || wasTextChanged; - } - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - - return wasTextChanged; -} - -bool drgui_textbox_find_and_replace_all(drgui_element* pTBElement, const char* text, const char* replacement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return 0; - } - - size_t originalCursorLine = drgui_text_engine_get_cursor_line(pTB->pTL); - size_t originalCursorPos = drgui_text_engine_get_cursor_character(pTB->pTL) - drgui_text_engine_get_line_first_character(pTB->pTL, originalCursorLine); - int originalScrollPosX = drgui_sb_get_scroll_position(pTB->pHorzScrollbar); - int originalScrollPosY = drgui_sb_get_scroll_position(pTB->pVertScrollbar); - - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - // It's important that we don't replace the replacement text. To handle this, we just move the cursor to the top of the text and find - // and replace every occurance without looping. - drgui_text_engine_move_cursor_to_start_of_text(pTB->pTL); - - size_t selectionStart; - size_t selectionEnd; - while (drgui_text_engine_find_next_no_loop(pTB->pTL, text, &selectionStart, &selectionEnd)) - { - drgui_text_engine_select(pTB->pTL, selectionStart, selectionEnd); - drgui_text_engine_move_cursor_to_end_of_selection(pTB->pTL); - - wasTextChanged = drgui_text_engine_delete_selected_text(pTB->pTL) || wasTextChanged; - wasTextChanged = drgui_text_engine_insert_text_at_cursor(pTB->pTL, replacement) || wasTextChanged; - } - - // The cursor may have moved so we'll need to restore it. - size_t lineCharStart; - size_t lineCharEnd; - drgui_text_engine_get_line_character_range(pTB->pTL, originalCursorLine, &lineCharStart, &lineCharEnd); - - size_t newCursorPos = lineCharStart + originalCursorPos; - if (newCursorPos > lineCharEnd) { - newCursorPos = lineCharEnd; - } - drgui_text_engine_move_cursor_to_character(pTB->pTL, newCursorPos); - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - - - // The scroll positions may have moved so we'll need to restore them. - drgui_sb_scroll_to(pTB->pHorzScrollbar, originalScrollPosX); - drgui_sb_scroll_to(pTB->pVertScrollbar, originalScrollPosY); - - return wasTextChanged; -} - - -void drgui_textbox_show_line_numbers(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_show(pTB->pLineNumbers); - drgui_textbox__refresh_line_numbers(pTBElement); -} - -void drgui_textbox_hide_line_numbers(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_hide(pTB->pLineNumbers); - drgui_textbox__refresh_line_numbers(pTBElement); -} - - -void drgui_textbox_disable_vertical_scrollbar(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->isVertScrollbarEnabled) { - pTB->isVertScrollbarEnabled = false; - drgui_textbox__refresh_scrollbars(pTBElement); - } -} - -void drgui_textbox_enable_vertical_scrollbar(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (!pTB->isVertScrollbarEnabled) { - pTB->isVertScrollbarEnabled = true; - drgui_textbox__refresh_scrollbars(pTBElement); - } -} - -void drgui_textbox_disable_horizontal_scrollbar(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->isHorzScrollbarEnabled) { - pTB->isHorzScrollbarEnabled = false; - drgui_textbox__refresh_scrollbars(pTBElement); - } -} - -void drgui_textbox_enable_horizontal_scrollbar(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (!pTB->isHorzScrollbarEnabled) { - pTB->isHorzScrollbarEnabled = true; - drgui_textbox__refresh_scrollbars(pTBElement); - } -} - -drgui_element* drgui_textbox_get_vertical_scrollbar(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pVertScrollbar; -} - -drgui_element* drgui_textbox_get_horizontal_scrollbar(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return NULL; - } - - return pTB->pHorzScrollbar; -} - -void drgui_textbox_set_scrollbar_size(drgui_element* pTBElement, float size) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->horzScrollbarSize = size; - pTB->vertScrollbarSize = size; - - drgui_textbox__refresh_scrollbars(pTBElement); -} - - -void drgui_textbox_set_on_cursor_move(drgui_element* pTBElement, drgui_textbox_on_cursor_move_proc proc) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onCursorMove = proc; -} - -void drgui_textbox_set_on_undo_point_changed(drgui_element* pTBElement, drgui_textbox_on_undo_point_changed_proc proc) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - pTB->onUndoPointChanged = proc; -} - - -void drgui_textbox_on_size(drgui_element* pTBElement, float newWidth, float newHeight) -{ - (void)newWidth; - (void)newHeight; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - // The text engine needs to be resized. - float containerWidth; - float containerHeight; - drgui_textbox__calculate_text_engine_container_size(pTBElement, &containerWidth, &containerHeight); - drgui_text_engine_set_container_size(pTB->pTL, containerWidth, containerHeight); - - // Scrollbars need to be refreshed first. - drgui_textbox__refresh_scrollbars(pTBElement); - - // Line numbers need to be refreshed. - drgui_textbox__refresh_line_numbers(pTBElement); -} - -void drgui_textbox_on_mouse_move(drgui_element* pTBElement, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (drgui_get_element_with_mouse_capture(pTBElement->pContext) == pTBElement) - { - float offsetX; - float offsetY; - drgui_textbox__get_text_offset(pTBElement, &offsetX, &offsetY); - - drgui_text_engine_move_cursor_to_point(pTB->pTL, (float)relativeMousePosX - offsetX, (float)relativeMousePosY - offsetY); - } -} - -void drgui_textbox_on_mouse_button_down(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - // Focus the text editor. - drgui_capture_keyboard(pTBElement); - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT) - { - // If we are not in selection mode, make sure everything is deselected. - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) == 0) { - drgui_text_engine_deselect_all(pTB->pTL); - drgui_text_engine_leave_selection_mode(pTB->pTL); - } else { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - float offsetX; - float offsetY; - drgui_textbox__get_text_offset(pTBElement, &offsetX, &offsetY); - drgui_text_engine_move_cursor_to_point(pTB->pTL, (float)relativeMousePosX - offsetX, (float)relativeMousePosY - offsetY); - - // In order to support selection with the mouse we need to capture the mouse and enter selection mode. - drgui_capture_mouse(pTBElement); - - // If we didn't previously enter selection mode we'll need to do that now so we can drag select. - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) == 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - } - - if (mouseButton == DRGUI_MOUSE_BUTTON_RIGHT) - { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } -} - -void drgui_textbox_on_mouse_button_up(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT) - { - if (drgui_get_element_with_mouse_capture(pTBElement->pContext) == pTBElement) - { - // Releasing the mouse will leave selectionmode. - drgui_release_mouse(pTBElement->pContext); - } - } -} - -void drgui_textbox_on_mouse_button_dblclick(drgui_element* pTBElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)mouseButton; - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } -} - -void drgui_textbox_on_mouse_wheel(drgui_element* pTBElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_sb_scroll(pTB->pVertScrollbar, -delta * drgui_sb_get_mouse_wheel_scale(pTB->pVertScrollbar)); -} - -void drgui_textbox_on_key_down(drgui_element* pTBElement, drgui_key key, int stateFlags) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - switch (key) - { - case DRGUI_BACKSPACE: - { - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - if (drgui_text_engine_is_anything_selected(pTB->pTL)) { - wasTextChanged = drgui_text_engine_delete_selected_text(pTB->pTL); - } else { - wasTextChanged = drgui_text_engine_delete_character_to_left_of_cursor(pTB->pTL); - } - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - } break; - - case DRGUI_DELETE: - { - bool wasTextChanged = false; - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - if (drgui_text_engine_is_anything_selected(pTB->pTL)) { - wasTextChanged = drgui_text_engine_delete_selected_text(pTB->pTL); - } else { - wasTextChanged = drgui_text_engine_delete_character_to_right_of_cursor(pTB->pTL); - } - } - if (wasTextChanged) { drgui_text_engine_commit_undo_point(pTB->pTL); } - } break; - - - case DRGUI_ARROW_LEFT: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_move_cursor_to_start_of_selection(pTB->pTL); - drgui_text_engine_deselect_all(pTB->pTL); - } else { - drgui_text_engine_move_cursor_left(pTB->pTL); - } - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - case DRGUI_ARROW_RIGHT: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_move_cursor_to_end_of_selection(pTB->pTL); - drgui_text_engine_deselect_all(pTB->pTL); - } else { - drgui_text_engine_move_cursor_right(pTB->pTL); - } - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - case DRGUI_ARROW_UP: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_deselect_all(pTB->pTL); - } - - drgui_text_engine_move_cursor_up(pTB->pTL); - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - case DRGUI_ARROW_DOWN: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_deselect_all(pTB->pTL); - } - - drgui_text_engine_move_cursor_down(pTB->pTL); - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - - case DRGUI_END: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_deselect_all(pTB->pTL); - } - - if ((stateFlags & DRGUI_KEY_STATE_CTRL_DOWN) != 0) { - drgui_text_engine_move_cursor_to_end_of_text(pTB->pTL); - } else { - drgui_text_engine_move_cursor_to_end_of_line(pTB->pTL); - } - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - case DRGUI_HOME: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_deselect_all(pTB->pTL); - } - - if ((stateFlags & DRGUI_KEY_STATE_CTRL_DOWN) != 0) { - drgui_text_engine_move_cursor_to_start_of_text(pTB->pTL); - } else { - drgui_text_engine_move_cursor_to_start_of_line(pTB->pTL); - } - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - case DRGUI_PAGE_UP: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_deselect_all(pTB->pTL); - } - - int scrollOffset = drgui_sb_get_page_size(pTB->pVertScrollbar); - if ((stateFlags & DRGUI_KEY_STATE_CTRL_DOWN) == 0) { - drgui_sb_scroll(pTB->pVertScrollbar, -scrollOffset); - } - - drgui_text_engine_move_cursor_y(pTB->pTL, -drgui_sb_get_page_size(pTB->pVertScrollbar)); - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - case DRGUI_PAGE_DOWN: - { - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_enter_selection_mode(pTB->pTL); - } - - if (drgui_text_engine_is_anything_selected(pTB->pTL) && !drgui_text_engine_is_in_selection_mode(pTB->pTL)) { - drgui_text_engine_deselect_all(pTB->pTL); - } - - int scrollOffset = drgui_sb_get_page_size(pTB->pVertScrollbar); - if (scrollOffset > (int)(drgui_text_engine_get_line_count(pTB->pTL) - drgui_text_engine_get_cursor_line(pTB->pTL))) { - scrollOffset = 0; - } - - if ((stateFlags & DRGUI_KEY_STATE_CTRL_DOWN) == 0) { - drgui_sb_scroll(pTB->pVertScrollbar, scrollOffset); - } - - drgui_text_engine_move_cursor_y(pTB->pTL, drgui_sb_get_page_size(pTB->pVertScrollbar)); - - if ((stateFlags & DRGUI_KEY_STATE_SHIFT_DOWN) != 0) { - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } break; - - default: break; - } -} - -void drgui_textbox_on_key_up(drgui_element* pTBElement, drgui_key key, int stateFlags) -{ - (void)pTBElement; - (void)key; - (void)stateFlags; -} - -void drgui_textbox_on_printable_key_down(drgui_element* pTBElement, unsigned int utf32, int stateFlags) -{ - (void)stateFlags; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_prepare_undo_point(pTB->pTL); - { - if (drgui_text_engine_is_anything_selected(pTB->pTL)) { - drgui_text_engine_delete_selected_text(pTB->pTL); - } - - drgui_text_engine_insert_character_at_cursor(pTB->pTL, utf32); - } - drgui_text_engine_commit_undo_point(pTB->pTL); -} - - -DRGUI_PRIVATE void drgui_textbox__on_text_engine_paint_rect(drgui_text_engine* pTL, drgui_rect rect, drgui_color color, drgui_element* pTBElement, void* pPaintData) -{ - (void)pTL; - - float offsetX; - float offsetY; - drgui_textbox__get_text_offset(pTBElement, &offsetX, &offsetY); - - drgui_draw_rect(pTBElement, drgui_offset_rect(rect, offsetX, offsetY), color, pPaintData); -} - -DRGUI_PRIVATE void drgui_textbox__on_text_engine_paint_text(drgui_text_engine* pTL, drgui_text_run* pRun, drgui_element* pTBElement, void* pPaintData) -{ - (void)pTL; - - float offsetX; - float offsetY; - drgui_textbox__get_text_offset(pTBElement, &offsetX, &offsetY); - - drgui_draw_text(pTBElement, pRun->pFont, pRun->text, (int)pRun->textLength, (float)pRun->posX + offsetX, (float)pRun->posY + offsetY, pRun->textColor, pRun->backgroundColor, pPaintData); -} - -DRGUI_PRIVATE void drgui_textbox__on_text_engine_dirty(drgui_text_engine* pTL, drgui_rect rect) -{ - drgui_element* pTBElement = *(drgui_element**)drgui_text_engine_get_extra_data(pTL); - if (pTBElement == NULL) { - return; - } - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - float offsetX; - float offsetY; - drgui_textbox__get_text_offset(pTBElement, &offsetX, &offsetY); - - drgui_dirty(pTBElement, drgui_offset_rect(rect, offsetX, offsetY)); -} - -DRGUI_PRIVATE void drgui_textbox__on_text_engine_cursor_move(drgui_text_engine* pTL) -{ - // If the cursor is off the edge of the container we want to scroll it into position. - drgui_element* pTBElement = *(drgui_element**)drgui_text_engine_get_extra_data(pTL); - if (pTBElement == NULL) { - return; - } - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - // If the cursor is above or below the container, we need to scroll vertically. - int iLine = (int)drgui_text_engine_get_cursor_line(pTB->pTL); - if (iLine < drgui_sb_get_scroll_position(pTB->pVertScrollbar)) { - drgui_sb_scroll_to(pTB->pVertScrollbar, iLine); - } - - int iBottomLine = drgui_sb_get_scroll_position(pTB->pVertScrollbar) + drgui_sb_get_page_size(pTB->pVertScrollbar) - 1; - if (iLine >= iBottomLine) { - drgui_sb_scroll_to(pTB->pVertScrollbar, iLine - (drgui_sb_get_page_size(pTB->pVertScrollbar) - 1) + 1); - } - - - // If the cursor is to the left or right of the container we need to scroll horizontally. - float cursorPosX; - float cursorPosY; - drgui_text_engine_get_cursor_position(pTB->pTL, &cursorPosX, &cursorPosY); - - if (cursorPosX < 0) { - drgui_sb_scroll_to(pTB->pHorzScrollbar, (int)(cursorPosX - drgui_text_engine_get_inner_offset_x(pTB->pTL)) - 100); - } - if (cursorPosX >= drgui_text_engine_get_container_width(pTB->pTL)) { - drgui_sb_scroll_to(pTB->pHorzScrollbar, (int)(cursorPosX - drgui_text_engine_get_inner_offset_x(pTB->pTL) - drgui_text_engine_get_container_width(pTB->pTL)) + 100); - } - - - if (pTB->onCursorMove) { - pTB->onCursorMove(pTBElement); - } -} - -DRGUI_PRIVATE void drgui_textbox__on_text_engine_text_changed(drgui_text_engine* pTL) -{ - drgui_element* pTBElement = *(drgui_element**)drgui_text_engine_get_extra_data(pTL); - if (pTBElement == NULL) { - return; - } - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - // Scrollbars need to be refreshed whenever text is changed. - drgui_textbox__refresh_scrollbars(pTBElement); - - // The line numbers need to be redrawn. - // TODO: This can probably be optimized a bit so that it is only redrawn if a line was inserted or deleted. - drgui_dirty(pTB->pLineNumbers, drgui_get_local_rect(pTB->pLineNumbers)); -} - -DRGUI_PRIVATE void drgui_textbox__on_text_engine_undo_point_changed(drgui_text_engine* pTL, unsigned int iUndoPoint) -{ - drgui_element* pTBElement = *(drgui_element**)drgui_text_engine_get_extra_data(pTL); - if (pTBElement == NULL) { - return; - } - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - if (pTB->onUndoPointChanged) { - pTB->onUndoPointChanged(pTBElement, iUndoPoint); - } -} - - -void drgui_textbox_on_paint(drgui_element* pTBElement, drgui_rect relativeRect, void* pPaintData) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_rect textRect = drgui_textbox__get_text_rect(pTBElement); - - // The dead space between the scrollbars should always be drawn with the default background color. - drgui_draw_rect(pTBElement, drgui_textbox__get_scrollbar_dead_space_rect(pTBElement), drgui_text_engine_get_default_bg_color(pTB->pTL), pPaintData); - - // Border. - drgui_rect borderRect = drgui_get_local_rect(pTBElement); - drgui_draw_rect_outline(pTBElement, borderRect, pTB->borderColor, pTB->borderWidth, pPaintData); - - // Padding. - drgui_rect paddingRect = drgui_grow_rect(textRect, pTB->padding); - drgui_draw_rect_outline(pTBElement, paddingRect, drgui_text_engine_get_default_bg_color(pTB->pTL), pTB->padding, pPaintData); - - // Text. - drgui_set_clip(pTBElement, drgui_clamp_rect(textRect, relativeRect), pPaintData); - drgui_text_engine_paint(pTB->pTL, drgui_offset_rect(drgui_clamp_rect(textRect, relativeRect), -textRect.left, -textRect.top), pTBElement, pPaintData); -} - -void drgui_textbox_on_capture_keyboard(drgui_element* pTBElement, drgui_element* pPrevCapturedElement) -{ - (void)pPrevCapturedElement; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_show_cursor(pTB->pTL); -} - -void drgui_textbox_on_release_keyboard(drgui_element* pTBElement, drgui_element* pNewCapturedElement) -{ - (void)pNewCapturedElement; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_hide_cursor(pTB->pTL); -} - -void drgui_textbox_on_capture_mouse(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - -} - -void drgui_textbox_on_release_mouse(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return; - } - - drgui_text_engine_leave_selection_mode(pTB->pTL); -} - - - -DRGUI_PRIVATE void drgui_textbox__get_text_offset(drgui_element* pTBElement, float* pOffsetXOut, float* pOffsetYOut) -{ - float offsetX = 0; - float offsetY = 0; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB != NULL) - { - float lineNumbersWidth = 0; - if (drgui_is_visible(pTB->pLineNumbers)) { - lineNumbersWidth = drgui_get_width(pTB->pLineNumbers); - } - - offsetX = pTB->borderWidth + pTB->padding + lineNumbersWidth; - offsetY = pTB->borderWidth + pTB->padding; - } - - - if (pOffsetXOut != NULL) { - *pOffsetXOut = offsetX; - } - if (pOffsetYOut != NULL) { - *pOffsetYOut = offsetY; - } -} - -DRGUI_PRIVATE void drgui_textbox__calculate_text_engine_container_size(drgui_element* pTBElement, float* pWidthOut, float* pHeightOut) -{ - float width = 0; - float height = 0; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB != NULL) - { - float horzScrollbarSize = 0; - if (drgui_is_visible(pTB->pHorzScrollbar)) { - horzScrollbarSize = drgui_get_height(pTB->pHorzScrollbar); - } - - float vertScrollbarSize = 0; - if (drgui_is_visible(pTB->pVertScrollbar)) { - vertScrollbarSize = drgui_get_width(pTB->pVertScrollbar); - } - - float lineNumbersWidth = 0; - if (drgui_is_visible(pTB->pLineNumbers)) { - lineNumbersWidth = drgui_get_width(pTB->pLineNumbers); - } - - width = drgui_get_width(pTBElement) - (pTB->borderWidth + pTB->padding)*2 - vertScrollbarSize - lineNumbersWidth; - height = drgui_get_height(pTBElement) - (pTB->borderWidth + pTB->padding)*2 - horzScrollbarSize; - } - - if (pWidthOut != NULL) { - *pWidthOut = width; - } - if (pHeightOut != NULL) { - *pHeightOut = height; - } -} - -DRGUI_PRIVATE drgui_rect drgui_textbox__get_text_rect(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - if (pTB == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - float offsetX; - float offsetY; - drgui_textbox__get_text_offset(pTBElement, &offsetX, &offsetY); - - float width; - float height; - drgui_textbox__calculate_text_engine_container_size(pTBElement, &width, &height); - - return drgui_make_rect(offsetX, offsetY, offsetX + width, offsetY + height); -} - - -DRGUI_PRIVATE void drgui_textbox__refresh_scrollbars(drgui_element* pTBElement) -{ - // The layout depends on the range because we may be dynamically hiding and showing the scrollbars depending on the range. Thus, we - // refresh the range first. However, dynamically showing and hiding the scrollbars (which is done when the layout is refreshed) affects - // the size of the text box, which in turn affects the range. Thus, we need to refresh the ranges a second time after the layouts. - - drgui_textbox__refresh_scrollbar_ranges(pTBElement); - drgui_textbox__refresh_scrollbar_layouts(pTBElement); - drgui_textbox__refresh_scrollbar_ranges(pTBElement); -} - -DRGUI_PRIVATE void drgui_textbox__refresh_scrollbar_ranges(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - // The vertical scrollbar is based on the line count. - size_t lineCount = drgui_text_engine_get_line_count(pTB->pTL); - size_t pageSize = drgui_text_engine_get_visible_line_count_starting_at(pTB->pTL, drgui_sb_get_scroll_position(pTB->pVertScrollbar)); - drgui_sb_set_range_and_page_size(pTB->pVertScrollbar, 0, (int)(lineCount + pageSize - 1 - 1), (int)pageSize); // -1 to make the range 0 based. -1 to ensure at least one line is visible. - - if (drgui_sb_is_thumb_visible(pTB->pVertScrollbar)) { - if (!drgui_is_visible(pTB->pVertScrollbar)) { - drgui_show(pTB->pVertScrollbar); - } - } else { - if (drgui_is_visible(pTB->pVertScrollbar)) { - drgui_hide(pTB->pVertScrollbar); - } - } - - - // The horizontal scrollbar is a per-pixel scrollbar, and is based on the width of the text versus the width of the container. - drgui_rect textRect = drgui_text_engine_get_text_rect_relative_to_bounds(pTB->pTL); - float containerWidth; - drgui_text_engine_get_container_size(pTB->pTL, &containerWidth, NULL); - drgui_sb_set_range_and_page_size(pTB->pHorzScrollbar, 0, (int)(textRect.right - textRect.left + (containerWidth/2)), (int)containerWidth); - - if (drgui_sb_is_thumb_visible(pTB->pHorzScrollbar)) { - if (!drgui_is_visible(pTB->pHorzScrollbar)) { - drgui_show(pTB->pHorzScrollbar); - drgui_textbox__refresh_line_numbers(pTBElement); - } - } else { - if (drgui_is_visible(pTB->pHorzScrollbar)) { - drgui_hide(pTB->pHorzScrollbar); - drgui_textbox__refresh_line_numbers(pTBElement); - } - } -} - -DRGUI_PRIVATE void drgui_textbox__refresh_scrollbar_layouts(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - float offsetLeft = pTB->borderWidth; - float offsetTop = pTB->borderWidth; - float offsetRight = pTB->borderWidth; - float offsetBottom = pTB->borderWidth; - - float scrollbarSizeH = (drgui_sb_is_thumb_visible(pTB->pHorzScrollbar) && pTB->isHorzScrollbarEnabled) ? pTB->horzScrollbarSize : 0; - float scrollbarSizeV = (drgui_sb_is_thumb_visible(pTB->pVertScrollbar) && pTB->isVertScrollbarEnabled) ? pTB->vertScrollbarSize : 0; - - drgui_set_size(pTB->pVertScrollbar, scrollbarSizeV, drgui_get_height(pTBElement) - scrollbarSizeH - (offsetTop + offsetBottom)); - drgui_set_size(pTB->pHorzScrollbar, drgui_get_width(pTBElement) - scrollbarSizeV - (offsetLeft + offsetRight), scrollbarSizeH); - - drgui_set_relative_position(pTB->pVertScrollbar, drgui_get_width(pTBElement) - scrollbarSizeV - offsetRight, offsetTop); - drgui_set_relative_position(pTB->pHorzScrollbar, offsetLeft, drgui_get_height(pTBElement) - scrollbarSizeH - offsetBottom); - - - // A change in the layout of the horizontal scrollbar will affect the layout of the line numbers. - drgui_textbox__refresh_line_numbers(pTBElement); -} - -DRGUI_PRIVATE drgui_rect drgui_textbox__get_scrollbar_dead_space_rect(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - float offsetLeft = pTB->borderWidth; - float offsetTop = pTB->borderWidth; - float offsetRight = pTB->borderWidth; - float offsetBottom = pTB->borderWidth; - - float scrollbarSizeH = (drgui_is_visible(pTB->pHorzScrollbar) && pTB->isHorzScrollbarEnabled) ? drgui_get_width(pTB->pHorzScrollbar) : 0; - float scrollbarSizeV = (drgui_is_visible(pTB->pVertScrollbar) && pTB->isHorzScrollbarEnabled) ? drgui_get_height(pTB->pVertScrollbar) : 0; - - if (scrollbarSizeH == 0 && scrollbarSizeV == 0) { - return drgui_make_rect(0, 0, 0, 0); - } - - return drgui_make_rect(scrollbarSizeH + offsetLeft, scrollbarSizeV + offsetTop, drgui_get_width(pTBElement) - offsetRight, drgui_get_height(pTBElement) - offsetBottom); -} - - -DRGUI_PRIVATE void drgui_textbox__on_mouse_move_line_numbers(drgui_element* pLineNumbers, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - - drgui_element* pTBElement = *(drgui_element**)drgui_get_extra_data(pLineNumbers); - assert(pTBElement != NULL); - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - if ((stateFlags & DRGUI_MOUSE_BUTTON_LEFT_DOWN) != 0) - { - if (drgui_get_element_with_mouse_capture(pLineNumbers->pContext) == pLineNumbers) - { - // We just move the cursor around based on the line number we've moved over. - drgui_text_engine_enter_selection_mode(pTB->pTL); - { - //float offsetX = pTextEditorData->padding; - float offsetY = pTB->padding; - size_t iLine = drgui_text_engine_get_line_at_pos_y(pTB->pTL, relativeMousePosY - offsetY); - size_t iAnchorLine = pTB->iLineSelectAnchor; - size_t lineCount = drgui_text_engine_get_line_count(pTB->pTL); - - size_t iSelectionFirstLine = drgui_text_engine_get_selection_first_line(pTB->pTL); - size_t iSelectionLastLine = drgui_text_engine_get_selection_last_line(pTB->pTL); - if (iSelectionLastLine != iSelectionFirstLine) { - iSelectionLastLine -= 1; - } - - // If we're moving updwards we want to position the cursor at the start of the line. Otherwise we want to move the cursor to the start - // of the next line, or the end of the text. - bool movingUp = false; - if (iLine < iAnchorLine) { - movingUp = true; - } - - // If we're moving up the selection anchor needs to be placed at the end of the last line. Otherwise we need to move it to the start - // of the first line. - if (movingUp) { - if (iAnchorLine + 1 < lineCount) { - drgui_text_engine_move_selection_anchor_to_start_of_line(pTB->pTL, iAnchorLine + 1); - } else { - drgui_text_engine_move_selection_anchor_to_end_of_line(pTB->pTL, iAnchorLine); - } - } else { - drgui_text_engine_move_selection_anchor_to_start_of_line(pTB->pTL, iAnchorLine); - } - - - // If we're moving up we want the cursor to be placed at the start of the selection range. Otherwise we want to place the cursor - // at the end of the selection range. - if (movingUp) { - drgui_text_engine_move_cursor_to_start_of_line_by_index(pTB->pTL, iLine); - } else { - if (iLine + 1 < lineCount) { - drgui_text_engine_move_cursor_to_start_of_line_by_index(pTB->pTL, iLine + 1); - } else { - drgui_text_engine_move_cursor_to_end_of_line_by_index(pTB->pTL, iLine); - } - } - } - drgui_text_engine_leave_selection_mode(pTB->pTL); - } - } -} - -DRGUI_PRIVATE void drgui_textbox__on_mouse_button_down_line_numbers(drgui_element* pLineNumbers, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)stateFlags; - - drgui_element* pTBElement = *(drgui_element**)drgui_get_extra_data(pLineNumbers); - assert(pTBElement != NULL); - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT) - { - //float offsetX = pTextEditorData->padding; - float offsetY = pTB->padding; - pTB->iLineSelectAnchor = drgui_text_engine_get_line_at_pos_y(pTB->pTL, relativeMousePosY - offsetY); - - drgui_text_engine_deselect_all(pTB->pTL); - - drgui_text_engine_move_cursor_to_start_of_line_by_index(pTB->pTL, pTB->iLineSelectAnchor); - - drgui_text_engine_enter_selection_mode(pTB->pTL); - { - if (pTB->iLineSelectAnchor + 1 < drgui_text_engine_get_line_count(pTB->pTL)) { - drgui_text_engine_move_cursor_to_start_of_line_by_index(pTB->pTL, pTB->iLineSelectAnchor + 1); - } else { - drgui_text_engine_move_cursor_to_end_of_line(pTB->pTL); - } - } - drgui_text_engine_leave_selection_mode(pTB->pTL); - - drgui_capture_mouse(pLineNumbers); - } -} - -DRGUI_PRIVATE void drgui_textbox__on_mouse_button_up_line_numbers(drgui_element* pLineNumbers, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT) { - if (drgui_has_mouse_capture(pLineNumbers)) { - drgui_release_mouse(pLineNumbers->pContext); - } - } -} - -DRGUI_PRIVATE void drgui_textbox__on_paint_rect_line_numbers(drgui_text_engine* pLayout, drgui_rect rect, drgui_color color, drgui_element* pTBElement, void* pPaintData) -{ - (void)pLayout; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - float offsetX = pTB->padding; - float offsetY = pTB->padding; - - drgui_draw_rect(pTB->pLineNumbers, drgui_offset_rect(rect, offsetX, offsetY), color, pPaintData); -} - -DRGUI_PRIVATE void drgui_textbox__on_paint_text_line_numbers(drgui_text_engine* pLayout, drgui_text_run* pRun, drgui_element* pTBElement, void* pPaintData) -{ - (void)pLayout; - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - float offsetX = pTB->padding; - float offsetY = pTB->padding; - drgui_draw_text(pTB->pLineNumbers, pRun->pFont, pRun->text, (int)pRun->textLength, (float)pRun->posX + offsetX, (float)pRun->posY + offsetY, pRun->textColor, pRun->backgroundColor, pPaintData); -} - -DRGUI_PRIVATE void drgui_textbox__on_paint_line_numbers(drgui_element* pLineNumbers, drgui_rect relativeRect, void* pPaintData) -{ - (void)relativeRect; - - drgui_element* pTBElement = *((drgui_element**)drgui_get_extra_data(pLineNumbers)); - assert(pTBElement != NULL); - - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - float lineNumbersWidth = drgui_get_width(pLineNumbers) - (pTB->padding*2) - pTB->lineNumbersPaddingRight; - float lineNumbersHeight = drgui_get_height(pLineNumbers) - (pTB->padding*2); - - drgui_text_engine_paint_line_numbers(pTB->pTL, lineNumbersWidth, lineNumbersHeight, pTB->lineNumbersColor, pTB->lineNumbersBackgroundColor, drgui_textbox__on_paint_text_line_numbers, drgui_textbox__on_paint_rect_line_numbers, pTBElement, pPaintData); - - drgui_draw_rect_outline(pLineNumbers, drgui_get_local_rect(pLineNumbers), pTB->lineNumbersBackgroundColor, pTB->padding, pPaintData); - - // Right padding. - drgui_rect rightPaddingRect = drgui_get_local_rect(pLineNumbers); - rightPaddingRect.right -= pTB->padding; - rightPaddingRect.left = rightPaddingRect.right - pTB->lineNumbersPaddingRight; - drgui_draw_rect(pLineNumbers, rightPaddingRect, pTB->lineNumbersBackgroundColor, pPaintData); -} - -DRGUI_PRIVATE void drgui_textbox__refresh_line_numbers(drgui_element* pTBElement) -{ - drgui_textbox* pTB = (drgui_textbox*)drgui_get_extra_data(pTBElement); - assert(pTB != NULL); - - float lineNumbersWidth = 0; - if (drgui_is_visible(pTB->pLineNumbers)) { - lineNumbersWidth = pTB->lineNumbersWidth; - } - - float scrollbarHeight = drgui_is_visible(pTB->pHorzScrollbar) ? drgui_get_height(pTB->pHorzScrollbar) : 0; - drgui_set_size(pTB->pLineNumbers, lineNumbersWidth, drgui_get_height(pTBElement) - scrollbarHeight); - - - // The size of the text container may have changed. - float textEditorWidth; - float textEditorHeight; - drgui_textbox__calculate_text_engine_container_size(pTBElement, &textEditorWidth, &textEditorHeight); - drgui_text_engine_set_container_size(pTB->pTL, textEditorWidth, textEditorHeight); - - - // Force a redraw just to be sure everything is in a valid state. - drgui_dirty(pTBElement, drgui_get_local_rect(pTBElement)); -} -#endif //DR_GUI_IMPLEMENTATION -#endif //DRGUI_NO_TEXT_EDITING - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Tree View -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -// QUICK NOTES -// -// Tree-View Controls -// - A tree-view control is a complex control with a hierarchy of items. They are typically used for file explorers. - -#ifndef drgui_tree_view_h -#define drgui_tree_view_h - -#ifdef __cplusplus -extern "C" { -#endif - -#define EG_MAX_TREE_VIEW_ITEM_TEXT_LENGTH 256 - -typedef struct drgui_tree_view_item drgui_tree_view_item; - -typedef void (* drgui_tvi_on_mouse_move_proc) (drgui_tree_view_item* pItem, int relativeMousePosX, int relativeMousePosY, bool* pIsOverArrow); -typedef void (* drgui_tvi_on_mouse_leave_proc) (drgui_tree_view_item* pItem); -typedef void (* drgui_tvi_on_paint_proc) (drgui_element* pTVElement, drgui_tree_view_item* pItem, drgui_rect relativeClippingRect, drgui_color backgroundColor, float offsetX, float offsetY, float width, float height, void* pPaintData); -typedef void (* drgui_tvi_measure_proc) (drgui_tree_view_item* pItem, float* pWidthOut, float* pHeightOut); -typedef void (* drgui_tvi_on_picked_proc) (drgui_tree_view_item* pItem); - -/////////////////////////////////////////////////////////////////////////////// -// -// Tree-View -// -/////////////////////////////////////////////////////////////////////////////// - -/// Creates a tree-view control. -drgui_element* drgui_create_tree_view(drgui_context* pContext, drgui_element* pParent, size_t extraDataSize, const void* pExtraData); - -/// Deletes the given tree-view control. -void drgui_delete_tree_view(drgui_element* pTVElement); - - -/// Retrieves the size of the extra data associated with the given tree-view control. -size_t drgui_tv_get_extra_data_size(drgui_element* pTVElement); - -/// Retrieves a pointer to the buffer containing the given tree-view's extra data. -void* drgui_tv_get_extra_data(drgui_element* pTVElement); - -/// Retrieves a pointer to the root element of the given tree view control. -drgui_tree_view_item* drgui_tv_get_root_item(drgui_element* pTVElement); - -/// Retrieves a pointer to the vertical scrollbar. -drgui_element* drgui_tv_get_vertical_scrollbar(drgui_element* pTVElement); - -/// Retrieves a pointer to the horizontal scrollbar. -drgui_element* drgui_tv_get_horizontal_scrollbar(drgui_element* pTVElement); - - -/// Sets the default background color. -void drgui_tv_set_default_background_color(drgui_element* pTVElement, drgui_color color); - -/// Retrieves the default background color. -drgui_color drgui_tv_get_default_background_color(drgui_element* pTVElement); - -/// Sets the default background color of hovered items. -void drgui_tv_set_hovered_background_color(drgui_element* pTVElement, drgui_color color); - -/// Retrieves the default background color of hovered items. -drgui_color drgui_tv_get_hovered_background_color(drgui_element* pTVElement); - -/// Sets the default background color of selected items. -void drgui_tv_set_selected_background_color(drgui_element* pTVElement, drgui_color color); - -/// Retrieves the default background color of selected items. -drgui_color drgui_tv_get_selected_background_color(drgui_element* pTVElement); - -/// Sets the amount of indentation to apply to each child item in the given tree-view. -void drgui_tv_set_child_offset_x(drgui_element* pTVElement, float childOffsetX); - -/// Retrieves the amount of indentation to apply to each child item in the given tree-view. -float drgui_tv_get_child_offset_x(drgui_element* pTVElement); - - -/// Measures the given item. -bool drgui_tv_measure_item(drgui_element* pTVElement, drgui_tree_view_item* pItem, float* pWidthOut, float* pHeightOut); - -/// Deselects every tree-view item. -void drgui_tv_deselect_all_items(drgui_element* pTVElement); - -/// Enables multi-select. -/// -/// @remarks -/// While this is enabled, selections will accumulate. Typically you would call this when the user hits -/// the CTRL key, and then call drgui_tv_disable_multi_select() when the user releases it. -void drgui_tv_enable_multi_select(drgui_element* pTVElement); - -/// Disables multi-select. -void drgui_tv_disable_multi_select(drgui_element* pTVElement); - -/// Determines whether or not multi-select is enabled. -bool drgui_tv_is_multi_select_enabled(drgui_element* pTVElement); - - -/// Retrieves the first selected item. -/// -/// @remarks -/// This runs in linear time. -drgui_tree_view_item* drgui_tv_get_first_selected_item(drgui_element* pTVElement); - -/// Retrieves the next select item, not including the given item. -/// -/// @remarks -/// Use this in conjunction with drgui_tv_get_first_selected_item() to iterate over each selected item. -/// @par -/// The order in which retrieving selected items is based on their location in the hierarchy, and not the -/// order in which they were selected. -drgui_tree_view_item* drgui_tv_get_next_selected_item(drgui_element* pTVElement, drgui_tree_view_item* pItem); - - -/// Sets the function to call when the mouse is moved while over a tree-view item. -void drgui_tv_set_on_item_mouse_move(drgui_element* pTVElement, drgui_tvi_on_mouse_move_proc proc); - -/// Sets the function call when the mouse leaves a tree-view item. -void drgui_tv_set_on_item_mouse_leave(drgui_element* pTVElement, drgui_tvi_on_mouse_leave_proc proc); - -/// Sets the function to call when a tree-view item needs to be drawn. -void drgui_tv_set_on_item_paint(drgui_element* pTVElement, drgui_tvi_on_paint_proc proc); - -/// Sets the function to call when a tree-view item needs to be measured. -void drgui_tv_set_on_item_measure(drgui_element* pTVElement, drgui_tvi_measure_proc proc); - -/// Sets the function to call when a tree-view item is picked. -/// -/// @remarks -/// An item is "picked" when it is a leaf item (has no children) and is double-clicked. -void drgui_tv_set_on_item_picked(drgui_element* pTVElement, drgui_tvi_on_picked_proc proc); - - -/// Called when the size event needs to be processed for the given tree-view control. -void drgui_tv_on_size(drgui_element* pTVElement, float newWidth, float newHeight); - -/// Called when the mouse leave event needs to be processed for the given tree-view control. -void drgui_tv_on_mouse_leave(drgui_element* pTVElement); - -/// Called when the mouse move event needs to be processed for the given tree-view control. -void drgui_tv_on_mouse_move(drgui_element* pTVElement, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button down event needs to be processed for the given tree-view control. -void drgui_tv_on_mouse_button_down(drgui_element* pTVElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button up event needs to be processed for the given tree-view control. -void drgui_tv_on_mouse_button_up(drgui_element* pTVElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse button double-click event needs to be processed for the given tree-view control. -void drgui_tv_on_mouse_button_dblclick(drgui_element* pTVElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the mouse wheel event needs to be processed for the given tree-view control. -void drgui_tv_on_mouse_wheel(drgui_element* pTVElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags); - -/// Called when the paint event needs to be processed for the given tree-view control. -void drgui_tv_on_paint(drgui_element* pTVElement, drgui_rect relativeClippingRect, void* pPaintData); - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tree-View Item -// -/////////////////////////////////////////////////////////////////////////////// - -/// Creates a tree view item. -/// -/// @remarks -/// When pParent is non-null, the tree-view control must match that of the tree-view control that owns the -/// parent item. -drgui_tree_view_item* drgui_tv_create_item(drgui_element* pTVElement, drgui_tree_view_item* pParent, size_t extraDataSize, const void* pExtraData); - -/// Recursively deletes a tree view item. -void drgui_tvi_delete(drgui_tree_view_item* pItem); - -/// Retrieves the tree-view GUI element that owns the given item. -drgui_element* drgui_tvi_get_tree_view_element(drgui_tree_view_item* pItem); - -/// Retrieves the size of the extra data associated with the given tree-view item. -size_t drgui_tvi_get_extra_data_size(drgui_tree_view_item* pItem); - -/// Retrieves a pointer to the extra data associated with the given tree-view item. -void* drgui_tvi_get_extra_data(drgui_tree_view_item* pItem); - - -/// Retrieves the parent tree-view item. -drgui_tree_view_item* drgui_tvi_get_parent(drgui_tree_view_item* pItem); - -/// Retrieves a pointer to the first child of the given tree-view item. -drgui_tree_view_item* drgui_tvi_get_first_child(drgui_tree_view_item* pItem); - -/// Retrieves a pointer to the last child of the given tree-view item. -drgui_tree_view_item* drgui_tvi_get_last_child(drgui_tree_view_item* pItem); - -/// Retrieves a pointer to the next sibling of the given tree-view item. -drgui_tree_view_item* drgui_tvi_get_next_sibling(drgui_tree_view_item* pItem); - -/// Retrieves a pointer to the previous sibling of the given tree-view item. -drgui_tree_view_item* drgui_tvi_get_prev_sibling(drgui_tree_view_item* pItem); - -/// Appends a tree view item as a child of the given parent item. -void drgui_tvi_append(drgui_tree_view_item* pItem, drgui_tree_view_item* pParent); - -/// Prepends a tree view item as a child of the given parent item. -void drgui_tvi_prepend(drgui_tree_view_item* pItem, drgui_tree_view_item* pParent); - -/// Appends the given tree view item to the given sibling. -void drgui_tvi_append_sibling(drgui_tree_view_item* pItemToAppend, drgui_tree_view_item* pItemToAppendTo); - -/// Prepends the given tree view item to the given sibling. -void drgui_tvi_prepend_sibling(drgui_tree_view_item* pItemToPrepend, drgui_tree_view_item* pItemToPrependTo); - - -/// Determines whether or not the given item has any children. -bool drgui_tvi_has_children(drgui_tree_view_item* pItem); - -/// Retrieves the depth of the item. -/// -/// @remarks -/// This is a recursive call and runs in linear time. -int drgui_tvi_get_depth(drgui_tree_view_item* pItem); - -/// Retrieves a pointer to the next visible item in the hierarchy that is not a child. -/// -/// @remarks -/// This is used for iterating. -/// @par -/// is an input and output parameter that is decremented whenver the next item is an ancestor. -drgui_tree_view_item* drgui_tvi_next_visible_non_child(drgui_tree_view_item* pItem, int* pDepthInOut); - - -/// Selects the given item. -void drgui_tvi_select(drgui_tree_view_item* pItem); - -/// Deselects the given item. -void drgui_tvi_deselect(drgui_tree_view_item* pItem); - -/// Determines whether or not the given tree view item is selected. -bool drgui_tvi_is_selected(drgui_tree_view_item* pItem); - -/// Expands the given item. -void drgui_tvi_expand(drgui_tree_view_item* pItem); - -/// Collapses the given item. -void drgui_tvi_collapse(drgui_tree_view_item* pItem); - -/// Determines whether or not the given item is expanded. -bool drgui_tvi_is_expanded(drgui_tree_view_item* pItem); - - - -#ifdef __cplusplus -} -#endif -#endif //drgui_tree_view_h - - -#ifdef DR_GUI_IMPLEMENTATION -typedef struct drgui_tree_view drgui_tree_view; - -struct drgui_tree_view -{ - /// The root tree-view item. - drgui_tree_view_item* pRootItem; - - /// The vertical scrollbar. - drgui_element* pScrollbarV; - - /// The horizontal scrollbar. - drgui_element* pScrollbarH; - - - /// The default background color. - drgui_color defaultBGColor; - - /// The hovered background color. - drgui_color hoveredBGColor; - - /// The selected background color. - drgui_color selectedBGColor; - - /// The amount of indentation to apply to each child item. - float childOffsetX; - - - /// The function to call when an item needs to handle a mouse movement event. - drgui_tvi_on_mouse_move_proc onItemMouseMove; - - /// The function to call when an item needs to handle a mouse leave event. - drgui_tvi_on_mouse_leave_proc onItemMouseLeave; - - /// The function to call when an item needs to be drawn. - drgui_tvi_on_paint_proc onItemPaint; - - /// The function to call when an item needs to be measured. - drgui_tvi_measure_proc onItemMeasure; - - /// The function to call when an item is picked. - drgui_tvi_on_picked_proc onItemPicked; - - - /// A pointer to the item the mouse is current hovered over. - drgui_tree_view_item* pHoveredItem; - - /// Whether or not the mouse is hovered over the arrow of pHoveredItem. - bool isMouseOverArrow; - - /// Whether or not the mouse is over the given element. - bool isMouseOver; - - /// The relative position of the mouse on the x axis. This is updated whenever the mouse_move event is received. - int relativeMousePosX; - - /// The relative position of the mouse on the y axis. This is updated whenever the mouse_move event is received. - int relativeMousePosY; - - - /// Whether or not multi-select is enabled. - bool isMultiSelectEnabled; - - /// Whether or not range-select is enabled. - bool isRangeSelectEnabled; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data buffer. - char pExtraData[1]; -}; - -struct drgui_tree_view_item -{ - /// The tree-view control that owns this item. - drgui_element* pTVElement; - - - /// A pointer to the parent item. - drgui_tree_view_item* pParent; - - /// A pointer to the first child. - drgui_tree_view_item* pFirstChild; - - /// A pointer to the last child. - drgui_tree_view_item* pLastChild; - - /// A pointer to the next sibling. - drgui_tree_view_item* pNextSibling; - - /// A pointer to the prev sibling. - drgui_tree_view_item* pPrevSibling; - - - /// Whether or not the item is select. - bool isSelected; - - /// Whether or not the item is expanded. - bool isExpanded; - - - /// The size of the extra data. - size_t extraDataSize; - - /// A pointer to the extra data buffer. - char pExtraData[1]; -}; - -typedef struct -{ - /// A pointer to the relevant item. - drgui_tree_view_item* pItem; - - /// The width of the item. - float width; - - /// The height of the item. - float height; - - /// The position of the item on the x axis. - float posX; - - /// Top position of the item on the y axis. - float posY; - - /// The depth of the item. This is used to calculate the offset of the item. - int depth; - -} drgui_tree_view_iterator; - -typedef struct -{ - /// The width of the item. - float width; - - /// The height of the item. - float height; - - /// The position of the item on the x axis. - float posX; - - /// Top position of the item on the y axis. - float posY; - -} drgui_tree_view_item_metrics; - -typedef struct -{ - /// A pointer to the tree-view control that owns the scrollbar. - drgui_element* pTVElement; - -} drgui_tree_view_scrollbar_data; - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tree-View -// -/////////////////////////////////////////////////////////////////////////////// - -/// Refreshes the layout of the given tree-view control and schedules a redraw. -static void drgui_tv_refresh_and_redraw(drgui_element* pTVElement); - -/// Repositions and resizes the scrollbars of the given tree-view control. -static void drgui_tv_refresh_scrollbar_layouts(drgui_element* pTVElement); - -/// Refreshes the ranges and page sizes of the scrollbars of the given tree-view control. -static void drgui_tv_refresh_scrollbar_ranges(drgui_element* pTVElement); - -/// Retrieves the rectangle of the little space that sits between the two scrollbars. -static drgui_rect drgui_tv_get_scrollbar_dead_space_rect(drgui_element* pTVElement); - -/// Retrieves the rectangle region that does not include the scrollbars. This rectangle is used for clipping when drawing the tree-view. -static drgui_rect drgui_tv_get_inner_rect(drgui_element* pTVElement); - -/// Paints the items of the given tree-view control. -static void drgui_tv_paint_items(drgui_element* pTVElement, drgui_rect relativeClippingRect, void* pPaintData, float* pItemsBottomOut); - -/// Creates an iterator beginning at the given item. -static bool drgui_tv_begin_at(drgui_tree_view_item* pFirst, drgui_tree_view_iterator* pIteratorOut); - -/// Moves to the next item in the iterator. -static bool drgui_tv_next_visible(drgui_tree_view_iterator* pIterator); - -/// Paints the given item. -static void drgui_tv_paint_item(drgui_element* pTVElement, drgui_tree_view_item* pItem, drgui_rect relativeClippingRect, float posX, float posY, float width, float height, void* pPaintData); - -/// Finds the item under the given point. -static drgui_tree_view_item* drgui_tv_find_item_under_point(drgui_element* pTV, float relativePosX, float relativePosY, drgui_tree_view_item_metrics* pMetricsOut); - -/// Recursively deselects every item, including the given one. -static void drgui_tv_deselect_all_items_recursive(drgui_tree_view_item* pItem); - -/// Called when the mouse enters a scrollbar. We use this to ensure there are no items marked as hovered as the use moves the -/// mouse from the tree-view to the scrollbars. -static void drgui_tv_on_mouse_enter_scrollbar(drgui_element* pSBElement); - -/// Called when the vertical scrollbar is scrolled. -static void drgui_tv_on_scroll_v(drgui_element* pSBElement, int scrollPos); - -/// Called when the horizontal scrollbar is scrolled. -static void drgui_tv_on_scroll_h(drgui_element* pSBElement, int scrollPos); - -/// Retrieves a pointer to the first visible item on the page, based on the scroll position. -static drgui_tree_view_item* drgui_tv_find_first_visible_item_on_page(drgui_element* pTVElement); - - -drgui_element* drgui_create_tree_view(drgui_context* pContext, drgui_element* pParent, size_t extraDataSize, const void* pExtraData) -{ - drgui_element* pTVElement = drgui_create_element(pContext, pParent, sizeof(drgui_tree_view) + extraDataSize, NULL); - if (pTVElement == NULL) { - return NULL; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - pTV->pRootItem = drgui_tv_create_item(pTVElement, NULL, 0, NULL); - if (pTV->pRootItem == NULL) { - return NULL; - } - - - drgui_tree_view_scrollbar_data sbdata; - sbdata.pTVElement = pTVElement; - - pTV->pScrollbarV = drgui_create_scrollbar(pContext, pTVElement, drgui_sb_orientation_vertical, sizeof(sbdata), &sbdata); - drgui_set_on_mouse_enter(pTV->pScrollbarV, drgui_tv_on_mouse_enter_scrollbar); - drgui_sb_set_on_scroll(pTV->pScrollbarV, drgui_tv_on_scroll_v); - - pTV->pScrollbarH = drgui_create_scrollbar(pContext, pTVElement, drgui_sb_orientation_horizontal, sizeof(sbdata), &sbdata); - drgui_set_on_mouse_enter(pTV->pScrollbarH, drgui_tv_on_mouse_enter_scrollbar); - drgui_sb_set_on_scroll(pTV->pScrollbarH, drgui_tv_on_scroll_h); - - - pTV->defaultBGColor = drgui_rgb(96, 96, 96); - pTV->hoveredBGColor = drgui_rgb(112, 112, 112); - pTV->selectedBGColor = drgui_rgb(80, 160, 255); - pTV->childOffsetX = 16; - - pTV->onItemMouseMove = NULL; - pTV->onItemMouseLeave = NULL; - pTV->onItemPaint = NULL; - pTV->onItemMeasure = NULL; - pTV->onItemPicked = NULL; - - pTV->pHoveredItem = NULL; - pTV->isMouseOverArrow = false; - pTV->isMouseOver = false; - pTV->relativeMousePosX = 0; - pTV->relativeMousePosY = 0; - - pTV->isMultiSelectEnabled = false; - pTV->isRangeSelectEnabled = false; - - pTV->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pTV->pExtraData, pExtraData, extraDataSize); - } - - - // Default event handlers. - drgui_set_on_size(pTVElement, drgui_tv_on_size); - drgui_set_on_mouse_leave(pTVElement, drgui_tv_on_mouse_leave); - drgui_set_on_mouse_move(pTVElement, drgui_tv_on_mouse_move); - drgui_set_on_mouse_button_down(pTVElement, drgui_tv_on_mouse_button_down); - drgui_set_on_mouse_button_up(pTVElement, drgui_tv_on_mouse_button_up); - drgui_set_on_mouse_button_dblclick(pTVElement, drgui_tv_on_mouse_button_dblclick); - drgui_set_on_mouse_wheel(pTVElement, drgui_tv_on_mouse_wheel); - drgui_set_on_paint(pTVElement, drgui_tv_on_paint); - - - // Set the mouse wheel scale to 3 by default for the vertical scrollbar. - drgui_sb_set_mouse_wheel_scele(pTV->pScrollbarV, 3); - - - return pTVElement; -} - -void drgui_delete_tree_view(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - // Recursively delete the tree view items. - drgui_tvi_delete(pTV->pRootItem); - - // Delete the element last. - drgui_delete_element(pTVElement); -} - - -size_t drgui_tv_get_extra_data_size(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return 0; - } - - return pTV->extraDataSize; -} - -void* drgui_tv_get_extra_data(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - return pTV->pExtraData; -} - -drgui_tree_view_item* drgui_tv_get_root_item(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - return pTV->pRootItem; -} - -drgui_element* drgui_tv_get_vertical_scrollbar(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - return pTV->pScrollbarV; -} - -drgui_element* drgui_tv_get_horizontal_scrollbar(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - return pTV->pScrollbarH; -} - - -void drgui_tv_set_default_background_color(drgui_element* pTVElement, drgui_color color) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->defaultBGColor = color; -} - -drgui_color drgui_tv_get_default_background_color(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTV->defaultBGColor; -} - -void drgui_tv_set_hovered_background_color(drgui_element* pTVElement, drgui_color color) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->hoveredBGColor = color; -} - -drgui_color drgui_tv_get_hovered_background_color(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTV->hoveredBGColor; -} - -void drgui_tv_set_selected_background_color(drgui_element* pTVElement, drgui_color color) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->selectedBGColor = color; -} - -drgui_color drgui_tv_get_selected_background_color(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return drgui_rgb(0, 0, 0); - } - - return pTV->selectedBGColor; -} - -void drgui_tv_set_child_offset_x(drgui_element* pTVElement, float childOffsetX) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->childOffsetX = childOffsetX; -} - -float drgui_tv_get_child_offset_x(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return 0; - } - - return pTV->childOffsetX; -} - - -bool drgui_tv_measure_item(drgui_element* pTVElement, drgui_tree_view_item* pItem, float* pWidthOut, float* pHeightOut) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return false; - } - - if (pItem == NULL || pItem->pTVElement != pTVElement) { - return false; - } - - if (pTV->onItemMeasure) - { - pTV->onItemMeasure(pItem, pWidthOut, pHeightOut); - return true; - } - - return false; -} - -void drgui_tv_deselect_all_items(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - drgui_tv_deselect_all_items_recursive(pTV->pRootItem); - - // TODO: Only redraw the region that actually changed. - drgui_dirty(pTVElement, drgui_get_local_rect(pTVElement)); -} - - -void drgui_tv_enable_multi_select(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->isMultiSelectEnabled = true; -} - -void drgui_tv_disable_multi_select(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->isMultiSelectEnabled = false; -} - -bool drgui_tv_is_multi_select_enabled(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return false; - } - - return pTV->isMultiSelectEnabled; -} - -drgui_tree_view_item* drgui_tv_get_first_selected_item(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - drgui_tree_view_iterator i; - if (drgui_tv_begin_at(pTV->pRootItem->pFirstChild, &i)) - { - do - { - if (drgui_tvi_is_selected(i.pItem)) { - return i.pItem; - } - - } while (drgui_tv_next_visible(&i)); - } - - return NULL; -} - -drgui_tree_view_item* drgui_tv_get_next_selected_item(drgui_element* pTVElement, drgui_tree_view_item* pItem) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - drgui_tree_view_iterator i; - if (drgui_tv_begin_at(pItem, &i)) - { - // Note that we're not including in this iteration. - while (drgui_tv_next_visible(&i)) - { - if (drgui_tvi_is_selected(i.pItem)) { - return i.pItem; - } - } - } - - return NULL; -} - - -void drgui_tv_set_on_item_mouse_move(drgui_element* pTVElement, drgui_tvi_on_mouse_move_proc proc) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->onItemMouseMove = proc; -} - -void drgui_tv_set_on_item_mouse_leave(drgui_element* pTVElement, drgui_tvi_on_mouse_leave_proc proc) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->onItemMouseLeave = proc; -} - -void drgui_tv_set_on_item_paint(drgui_element* pTVElement, drgui_tvi_on_paint_proc proc) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->onItemPaint = proc; -} - -void drgui_tv_set_on_item_measure(drgui_element* pTVElement, drgui_tvi_measure_proc proc) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->onItemMeasure = proc; -} - -void drgui_tv_set_on_item_picked(drgui_element* pTVElement, drgui_tvi_on_picked_proc proc) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->onItemPicked = proc; -} - - -void drgui_tv_on_size(drgui_element* pTVElement, float newWidth, float newHeight) -{ - (void)newWidth; - (void)newHeight; - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - // Move the scrollbars. - drgui_tv_refresh_scrollbar_layouts(pTVElement); - - // Refresh the scrollbar ranges. - drgui_tv_refresh_scrollbar_ranges(pTVElement); -} - -void drgui_tv_on_mouse_leave(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->isMouseOver = false; - - if (pTV->pHoveredItem != NULL || pTV->isMouseOverArrow) - { - if (pTV->onItemMouseLeave) { - pTV->onItemMouseLeave(pTV->pHoveredItem); - } - - pTV->pHoveredItem = NULL; - pTV->isMouseOverArrow = false; - - // For now just redraw the entire control, but should optimize this to only redraw the regions of the new and old hovered items. - drgui_dirty(pTVElement, drgui_get_local_rect(pTVElement)); - } -} - -void drgui_tv_on_mouse_move(drgui_element* pTVElement, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)stateFlags; - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - pTV->isMouseOver = true; - pTV->relativeMousePosX = relativeMousePosX; - pTV->relativeMousePosY = relativeMousePosY; - - // If the mouse has entered into the dead space between the scrollbars, we just pretend the mouse has left the tree-view - // control entirely by posting a manual on_mouse_leave event and returning straight away. - if (drgui_rect_contains_point(drgui_tv_get_scrollbar_dead_space_rect(pTVElement), (float)relativeMousePosX, (float)relativeMousePosY)) { - drgui_tv_on_mouse_leave(pTVElement); - return; - } - - - drgui_tree_view_item_metrics newHoveredItemMetrics; - drgui_tree_view_item* pNewHoveredItem = drgui_tv_find_item_under_point(pTVElement, (float)relativeMousePosX, (float)relativeMousePosY, &newHoveredItemMetrics); - drgui_tree_view_item* pOldHoveredItem = pTV->pHoveredItem; - - bool wasMouseOverArrow = pTV->isMouseOverArrow; - pTV->isMouseOverArrow = false; - - if (pNewHoveredItem != NULL) - { - if (pTV->onItemMouseMove) - { - float relativeMousePosXToItem = (float)relativeMousePosX - newHoveredItemMetrics.posX + drgui_sb_get_scroll_position(pTV->pScrollbarH); - float relativeMousePosYToItem = (float)relativeMousePosY - newHoveredItemMetrics.posY; - - if (relativeMousePosXToItem >= 0 && relativeMousePosXToItem < newHoveredItemMetrics.width && - relativeMousePosYToItem >= 0 && relativeMousePosYToItem < newHoveredItemMetrics.height) - { - pTV->onItemMouseMove(pNewHoveredItem, (int)relativeMousePosXToItem, (int)relativeMousePosYToItem, &pTV->isMouseOverArrow); - } - } - } - - if (pNewHoveredItem != pOldHoveredItem || wasMouseOverArrow != pTV->isMouseOverArrow) - { - if (pNewHoveredItem != pOldHoveredItem && pOldHoveredItem != NULL) - { - if (pTV->onItemMouseLeave) { - pTV->onItemMouseLeave(pOldHoveredItem); - } - } - - - pTV->pHoveredItem = pNewHoveredItem; - - // TODO: Optimize this so that only the rectangle region encompassing the two relevant items is marked as dirty. - drgui_dirty(pTVElement, drgui_get_local_rect(pTVElement)); - } -} - -void drgui_tv_on_mouse_button_down(drgui_element* pTVElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT) - { - if (pTV->isMouseOverArrow) - { - if (drgui_tvi_is_expanded(pTV->pHoveredItem)) { - drgui_tvi_collapse(pTV->pHoveredItem); - } else { - drgui_tvi_expand(pTV->pHoveredItem); - } - } - else - { - if (pTV->isMultiSelectEnabled) - { - if (drgui_tvi_is_selected(pTV->pHoveredItem)) { - drgui_tvi_deselect(pTV->pHoveredItem); - } else { - drgui_tvi_select(pTV->pHoveredItem); - } - } - else - { - // TODO: Check if range selection is enabled and handle it here. - - drgui_tv_deselect_all_items(pTVElement); - drgui_tvi_select(pTV->pHoveredItem); - } - } - } -} - -void drgui_tv_on_mouse_button_up(drgui_element* pTVElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)mouseButton; - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - // TODO: Implement me. -} - -void drgui_tv_on_mouse_button_dblclick(drgui_element* pTVElement, int mouseButton, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - if (mouseButton == DRGUI_MOUSE_BUTTON_LEFT) - { - if (!pTV->isMouseOverArrow) - { - if (drgui_tvi_has_children(pTV->pHoveredItem)) - { - // It is a parent item, so toggle it. - if (drgui_tvi_is_expanded(pTV->pHoveredItem)) { - drgui_tvi_collapse(pTV->pHoveredItem); - } else { - drgui_tvi_expand(pTV->pHoveredItem); - } - } - else - { - // It is a leaf item, so pick it. - if (pTV->onItemPicked) { - pTV->onItemPicked(pTV->pHoveredItem); - } - } - } - } -} - -void drgui_tv_on_mouse_wheel(drgui_element* pTVElement, int delta, int relativeMousePosX, int relativeMousePosY, int stateFlags) -{ - (void)relativeMousePosX; - (void)relativeMousePosY; - (void)stateFlags; - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - drgui_sb_scroll(pTV->pScrollbarV, -delta * drgui_sb_get_mouse_wheel_scale(pTV->pScrollbarV)); -} - -void drgui_tv_on_paint(drgui_element* pTVElement, drgui_rect relativeClippingRect, void* pPaintData) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - // The dead space between the scrollbars should always be drawn with the default background color. - drgui_draw_rect(pTVElement, drgui_tv_get_scrollbar_dead_space_rect(pTVElement), pTV->defaultBGColor, pPaintData); - - // The clipping rectangle needs to be clamped to the local rectangle that is shrunk such that it does not - // include the scrollbars. If we don't do this we'll end up drawing underneath the scrollbars which will - // cause flickering. - drgui_rect innerClippingRect = drgui_clamp_rect(drgui_tv_get_inner_rect(pTVElement), relativeClippingRect); - drgui_set_clip(pTVElement, innerClippingRect, pPaintData); - - - // The main content of the tree-view is drawn in two parts. The first part (the top part) contains all of - // the tree-view items. The second part (the bottom part) is just the background region that is not covered - // by items. - - // We draw the tree-view items (the top part) first. This will retrieve the position of the bottom of the - // items which is used to determine how much empty space is remaining below it so we can draw a quad over - // that part. - float itemsBottom = 0; - drgui_tv_paint_items(pTVElement, innerClippingRect, pPaintData, &itemsBottom); - - - // At this point the items have been drawn. All that remains is the part of the background that is not - // covered by items. We can determine this by looking at . - if (itemsBottom < relativeClippingRect.bottom && itemsBottom < drgui_get_relative_position_y(pTV->pScrollbarH)) - { - drgui_draw_rect(pTVElement, drgui_make_rect(0, itemsBottom, drgui_get_relative_position_x(pTV->pScrollbarV), drgui_get_relative_position_y(pTV->pScrollbarH)), pTV->defaultBGColor, pPaintData); - } -} - - -static void drgui_tv_refresh_and_redraw(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - - // Refresh scrollbar ranges and page sizes. - drgui_tv_refresh_scrollbar_ranges(pTVElement); - - // For now, just redraw the entire control. - drgui_dirty(pTVElement, drgui_get_local_rect(pTVElement)); -} - -static void drgui_tv_refresh_scrollbar_layouts(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - - // Vertical scrollbar. - drgui_set_size(pTV->pScrollbarV, 16, drgui_get_height(pTVElement) - 16); - drgui_set_relative_position(pTV->pScrollbarV, drgui_get_width(pTVElement) - drgui_get_width(pTV->pScrollbarV), 0); - - // Horizontal scrollbar. - drgui_set_size(pTV->pScrollbarH, drgui_get_width(pTVElement) - 16, 16); - drgui_set_relative_position(pTV->pScrollbarH, 0, drgui_get_height(pTVElement) - drgui_get_height(pTV->pScrollbarH)); -} - -static void drgui_tv_refresh_scrollbar_ranges(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - float innerWidth = 0; - unsigned int totalItemCount = 0; - unsigned int pageItemCount = 0; - - drgui_tree_view_iterator i; - if (drgui_tv_begin_at(pTV->pRootItem->pFirstChild, &i)) - { - do - { - float itemRight = i.posX + i.width; - if (itemRight > innerWidth) { - innerWidth = itemRight; - } - - float itemBottom = i.posY + i.height; - if (itemBottom > 0 && itemBottom < drgui_get_relative_position_y(pTV->pScrollbarH)) { - pageItemCount += 1; - } - - totalItemCount += 1; - - } while (drgui_tv_next_visible(&i)); - } - - if (totalItemCount == 0) - { - // Vertical. - drgui_sb_set_range(pTV->pScrollbarV, 0, 0); - drgui_sb_set_page_size(pTV->pScrollbarV, 0); - - // Horizontal. - drgui_sb_set_range(pTV->pScrollbarH, 0, 0); - drgui_sb_set_page_size(pTV->pScrollbarH, 0); - } - else - { - // Vertical. - drgui_sb_set_range(pTV->pScrollbarV, 0, (int)totalItemCount - 1); // - 1 because it's a 0-based range. - drgui_sb_set_page_size(pTV->pScrollbarV, pageItemCount); - - // Horizontal. - drgui_sb_set_range(pTV->pScrollbarH, 0, (int)innerWidth); - drgui_sb_set_page_size(pTV->pScrollbarH, (int)drgui_get_relative_position_x(pTV->pScrollbarV)); - } -} - -static drgui_rect drgui_tv_get_scrollbar_dead_space_rect(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - return drgui_make_rect(drgui_get_width(pTV->pScrollbarH), drgui_get_height(pTV->pScrollbarV), drgui_get_width(pTVElement), drgui_get_height(pTVElement)); -} - -static drgui_rect drgui_tv_get_inner_rect(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return drgui_make_rect(0, 0, 0, 0); - } - - drgui_rect result = drgui_get_local_rect(pTVElement); - result.right -= drgui_get_width(pTV->pScrollbarV); - result.bottom -= drgui_get_height(pTV->pScrollbarH); - - return result; -} - -static void drgui_tv_paint_items(drgui_element* pTVElement, drgui_rect relativeClippingRect, void* pPaintData, float* pItemsBottomOut) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - float itemsBottom = 0; - - // For now we will begin at the root item, but later we want to begin at the first visible item which will be based on the - // scroll position. - drgui_tree_view_iterator i; - if (drgui_tv_begin_at(drgui_tv_find_first_visible_item_on_page(pTVElement), &i)) - { - do - { - drgui_tv_paint_item(pTVElement, i.pItem, relativeClippingRect, i.posX, i.posY, i.width, i.height, pPaintData); - - // Restore the clipping rectangle in case the application changed the clipping rectangle. - drgui_set_clip(pTVElement, relativeClippingRect, pPaintData); - - itemsBottom = i.posY + i.height; - - } while (itemsBottom < relativeClippingRect.bottom && drgui_tv_next_visible(&i)); - } - - - if (pItemsBottomOut != NULL) { - *pItemsBottomOut = itemsBottom; - } -} - -static bool drgui_tv_begin_at(drgui_tree_view_item* pFirst, drgui_tree_view_iterator* pIteratorOut) -{ - if (pFirst == NULL || pIteratorOut == NULL) { - return false; - } - - if (!drgui_tv_measure_item(pFirst->pTVElement, pFirst, &pIteratorOut->width, &pIteratorOut->height)) { - return false; - } - - const int depth = drgui_tvi_get_depth(pFirst); - - pIteratorOut->pItem = pFirst; - pIteratorOut->depth = depth; - pIteratorOut->posX = depth * drgui_tv_get_child_offset_x(pFirst->pTVElement); - pIteratorOut->posY = 0; - - return true; -} - -static bool drgui_tv_next_visible(drgui_tree_view_iterator* pIterator) -{ - assert(pIterator != NULL); - - if (pIterator->pItem == NULL) { - return false; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pIterator->pItem->pTVElement); - if (pTV == NULL) { - return false; - } - - if (drgui_tvi_has_children(pIterator->pItem) && drgui_tvi_is_expanded(pIterator->pItem)) - { - pIterator->pItem = pIterator->pItem->pFirstChild; - pIterator->depth += 1; - } - else - { - pIterator->pItem = drgui_tvi_next_visible_non_child(pIterator->pItem, &pIterator->depth); - } - - - if (pIterator->pItem == NULL) { - return false; - } - - pIterator->posX = pIterator->depth * drgui_tv_get_child_offset_x(pIterator->pItem->pTVElement); - pIterator->posY += pIterator->height; - - if (!drgui_tv_measure_item(pIterator->pItem->pTVElement, pIterator->pItem, &pIterator->width, &pIterator->height)) { - return false; - } - - return true; -} - -static void drgui_tv_paint_item(drgui_element* pTVElement, drgui_tree_view_item* pItem, drgui_rect relativeClippingRect, float posX, float posY, float width, float height, void* pPaintData) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return; - } - - if (pTV->onItemPaint) - { - // We draw an item in two main parts, with the first part being the background section to the left and right of the item and the - // second part being the item itself. The first part we do ourselves, whereas the second part we pass off to the host application. - - // The background section to the left and right of the main content is done first, by us. - drgui_color bgcolor; - if (drgui_tvi_is_selected(pItem)) { - bgcolor = pTV->selectedBGColor; - } else if (pTV->pHoveredItem == pItem) { - bgcolor = pTV->hoveredBGColor; - } else { - bgcolor = pTV->defaultBGColor; - } - - float innerOffsetX = (float)-drgui_sb_get_scroll_position(pTV->pScrollbarH); - - // Left. - if (posX + innerOffsetX > 0) { - drgui_draw_rect(pTVElement, drgui_make_rect(0, posY, posX + innerOffsetX, posY + height), bgcolor, pPaintData); - } - - // Right. - if (posX + width + innerOffsetX < drgui_get_relative_position_x(pTV->pScrollbarV)) { - drgui_draw_rect(pTVElement, drgui_make_rect(posX + width + innerOffsetX, posY, drgui_get_relative_position_x(pTV->pScrollbarV), posY + height), bgcolor, pPaintData); - } - - - // At this point if were to finish drawing we'd have a hole where the main content of the item should be. To fill this we need to - // let the host application do it. - pTV->onItemPaint(pTVElement, pItem, relativeClippingRect, bgcolor, posX + innerOffsetX, posY, width, height, pPaintData); - } -} - -static drgui_tree_view_item* drgui_tv_find_item_under_point(drgui_element* pTVElement, float relativePosX, float relativePosY, drgui_tree_view_item_metrics* pMetricsOut) -{ - (void)relativePosX; // <-- Unused because we treat items as though they are infinitely wide. - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - // For now we will begin at the root item, but later we want to begin at the first visible item which will be based on the - // scroll position. - drgui_tree_view_iterator i; - if (drgui_tv_begin_at(drgui_tv_find_first_visible_item_on_page(pTVElement), &i)) - { - do - { - if (relativePosY >= i.posY && relativePosY < i.posY + i.height) - { - if (pMetricsOut != NULL) - { - pMetricsOut->posX = i.posX; - pMetricsOut->posY = i.posY; - pMetricsOut->width = i.width; - pMetricsOut->height = i.height; - } - - return i.pItem; - } - - } while ((i.posY + i.height < drgui_get_relative_position_y(pTV->pScrollbarH)) && drgui_tv_next_visible(&i)); - } - - return NULL; -} - -static void drgui_tv_deselect_all_items_recursive(drgui_tree_view_item* pItem) -{ - pItem->isSelected = false; - - for (drgui_tree_view_item* pChild = pItem->pFirstChild; pChild != NULL; pChild = pChild->pNextSibling) - { - drgui_tv_deselect_all_items_recursive(pChild); - } -} - -static void drgui_tv_on_mouse_enter_scrollbar(drgui_element* pSBElement) -{ - drgui_tree_view_scrollbar_data* pSB = (drgui_tree_view_scrollbar_data*)drgui_sb_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - // We just pretend the mouse has left the tree-view entirely. This will ensure any item marked as hovered is unmarked and redrawn. - drgui_tv_on_mouse_leave(pSB->pTVElement); -} - -static void drgui_tv_on_scroll_v(drgui_element* pSBElement, int scrollPos) -{ - (void)scrollPos; - - drgui_tree_view_scrollbar_data* pSB = (drgui_tree_view_scrollbar_data*)drgui_sb_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pSB->pTVElement); - if (pTV == NULL) { - return; - } - - // As we scroll, the mouse will be placed over a different item. We just post a manual mouse_move event to trigger a refresh. - if (pTV->isMouseOver) { - drgui_tv_on_mouse_move(pSB->pTVElement, pTV->relativeMousePosX, pTV->relativeMousePosY, 0); - } - - // The paint routine is tied directly to the scrollbars, so all we need to do is mark it as dirty to trigger a redraw. - drgui_dirty(pSB->pTVElement, drgui_get_local_rect(pSB->pTVElement)); -} - -static void drgui_tv_on_scroll_h(drgui_element* pSBElement, int scrollPos) -{ - (void)scrollPos; - - drgui_tree_view_scrollbar_data* pSB = (drgui_tree_view_scrollbar_data*)drgui_sb_get_extra_data(pSBElement); - if (pSB == NULL) { - return; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pSB->pTVElement); - if (pTV == NULL) { - return; - } - - // The paint routine is tied directly to the scrollbars, so all we need to do is mark it as dirty to trigger a redraw. - drgui_dirty(pSB->pTVElement, drgui_get_local_rect(pSB->pTVElement)); -} - -static drgui_tree_view_item* drgui_tv_find_first_visible_item_on_page(drgui_element* pTVElement) -{ - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pTVElement); - if (pTV == NULL) { - return NULL; - } - - // We just keep iterating until we hit the index of the scroll position. - int index = 0; - - drgui_tree_view_iterator i; - if (drgui_tv_begin_at(pTV->pRootItem->pFirstChild, &i)) - { - do - { - if (index == drgui_sb_get_scroll_position(pTV->pScrollbarV)) { - return i.pItem; - } - - index += 1; - - } while (drgui_tv_next_visible(&i)); - } - - return NULL; -} - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Tree-View Item -// -/////////////////////////////////////////////////////////////////////////////// - -/// Detaches the given tree-view item from it's parent and siblings. -static void drgui_tvi_detach(drgui_tree_view_item* pItem); - -drgui_tree_view_item* drgui_tv_create_item(drgui_element* pTVElement, drgui_tree_view_item* pParent, size_t extraDataSize, const void* pExtraData) -{ - if (pTVElement == NULL) { - return NULL; - } - - if (pParent != NULL && pParent->pTVElement != pTVElement) { - return NULL; - } - - - drgui_tree_view_item* pItem = (drgui_tree_view_item*)malloc(sizeof(*pItem) + extraDataSize); - if (pItem == NULL) { - return NULL; - } - - pItem->pTVElement = pTVElement; - pItem->pParent = NULL; - pItem->pFirstChild = NULL; - pItem->pLastChild = NULL; - pItem->pNextSibling = NULL; - pItem->pPrevSibling = NULL; - pItem->isSelected = false; - pItem->isExpanded = false; - - pItem->extraDataSize = extraDataSize; - if (pExtraData != NULL) { - memcpy(pItem->pExtraData, pExtraData, extraDataSize); - } - - - // Append the item to the end of the parent item. - drgui_tvi_append(pItem, pParent); - - return pItem; -} - -void drgui_tvi_delete(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return; - } - - - // Children need to be deleted first. - while (pItem->pFirstChild != NULL) { - drgui_tvi_delete(pItem->pFirstChild); - } - - // We need to grab a pointer to the main tree-view control so we can refresh and redraw it after we have detached the item. - drgui_element* pTVElement = pItem->pTVElement; - - // The item needs to be completely detached first. - drgui_tvi_detach(pItem); - - // Refresh the layout and redraw the tree-view control. - drgui_tv_refresh_and_redraw(pTVElement); - - // Free the item last for safety. - free(pItem); -} - -drgui_element* drgui_tvi_get_tree_view_element(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pTVElement; -} - -size_t drgui_tvi_get_extra_data_size(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return 0; - } - - return pItem->extraDataSize; -} - -void* drgui_tvi_get_extra_data(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pExtraData; -} - - -drgui_tree_view_item* drgui_tvi_get_parent(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pParent; -} - -drgui_tree_view_item* drgui_tvi_get_first_child(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pFirstChild; -} - -drgui_tree_view_item* drgui_tvi_get_last_child(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pLastChild; -} - -drgui_tree_view_item* drgui_tvi_get_next_sibling(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pNextSibling; -} - -drgui_tree_view_item* drgui_tvi_get_prev_sibling(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return NULL; - } - - return pItem->pPrevSibling; -} - -void drgui_tvi_append(drgui_tree_view_item* pItem, drgui_tree_view_item* pParent) -{ - if (pItem == NULL) { - return; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pItem->pTVElement); - if (pTV == NULL) { - return; - } - - - // If a parent was not specified, append to the root item. - if (pParent == NULL) - { - if (pTV->pRootItem != NULL) { - drgui_tvi_append(pItem, pTV->pRootItem); - } - } - else - { - assert(pItem->pTVElement == pParent->pTVElement); - - // Detach the child from it's current parent first. - drgui_tvi_detach(pItem); - - pItem->pParent = pParent; - assert(pItem->pParent != NULL); - - if (pItem->pParent->pLastChild != NULL) { - pItem->pPrevSibling = pItem->pParent->pLastChild; - pItem->pPrevSibling->pNextSibling = pItem; - } - - if (pItem->pParent->pFirstChild == NULL) { - pItem->pParent->pFirstChild = pItem; - } - - pItem->pParent->pLastChild = pItem; - - - // Refresh the layout and redraw the tree-view control. - drgui_tv_refresh_and_redraw(pItem->pTVElement); - } -} - -void drgui_tvi_prepend(drgui_tree_view_item* pItem, drgui_tree_view_item* pParent) -{ - if (pItem == NULL) { - return; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pItem->pTVElement); - if (pTV == NULL) { - return; - } - - - // If a parent was not specified, prepend to the root item. - if (pParent == NULL) - { - if (pTV->pRootItem != NULL) { - drgui_tvi_prepend(pItem, pTV->pRootItem); - } - } - else - { - assert(pItem->pTVElement == pParent->pTVElement); - - // Detach the child from it's current parent first. - drgui_tvi_detach(pItem); - - pItem->pParent = pParent; - assert(pItem->pParent != NULL); - - if (pItem->pParent->pFirstChild != NULL) { - pItem->pNextSibling = pItem->pParent->pFirstChild; - pItem->pNextSibling->pPrevSibling = pItem; - } - - if (pItem->pParent->pLastChild == NULL) { - pItem->pParent->pLastChild = pItem; - } - - pItem->pParent->pFirstChild = pItem; - - - // Refresh the layout and redraw the tree-view control. - drgui_tv_refresh_and_redraw(pItem->pTVElement); - } -} - -void drgui_tvi_append_sibling(drgui_tree_view_item* pItemToAppend, drgui_tree_view_item* pItemToAppendTo) -{ - if (pItemToAppend == NULL) { - return; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pItemToAppend->pTVElement); - if (pTV == NULL) { - return; - } - - - // If a parent was not specified, append to the root item. - if (pItemToAppendTo == NULL) - { - if (pTV->pRootItem != NULL) { - drgui_tvi_append(pItemToAppend, pTV->pRootItem); - } - } - else - { - assert(pItemToAppend->pTVElement == pItemToAppendTo->pTVElement); - - // Detach the child from it's current parent first. - drgui_tvi_detach(pItemToAppend); - - - pItemToAppend->pParent = pItemToAppendTo->pParent; - assert(pItemToAppend->pParent != NULL); - - pItemToAppend->pNextSibling = pItemToAppendTo->pNextSibling; - pItemToAppend->pPrevSibling = pItemToAppendTo; - - pItemToAppendTo->pNextSibling->pPrevSibling = pItemToAppend; - pItemToAppendTo->pNextSibling = pItemToAppend; - - if (pItemToAppend->pParent->pLastChild == pItemToAppendTo) { - pItemToAppend->pParent->pLastChild = pItemToAppend; - } - - - // Refresh the layout and redraw the tree-view control. - drgui_tv_refresh_and_redraw(pItemToAppend->pTVElement); - } -} - -void drgui_tvi_prepend_sibling(drgui_tree_view_item* pItemToPrepend, drgui_tree_view_item* pItemToPrependTo) -{ - if (pItemToPrepend == NULL) { - return; - } - - drgui_tree_view* pTV = (drgui_tree_view*)drgui_get_extra_data(pItemToPrepend->pTVElement); - if (pTV == NULL) { - return; - } - - - // If a parent was not specified, prepend to the root item. - if (pItemToPrependTo == NULL) - { - if (pTV->pRootItem != NULL) { - drgui_tvi_prepend(pItemToPrepend, pTV->pRootItem); - } - } - else - { - assert(pItemToPrepend->pTVElement == pItemToPrependTo->pTVElement); - - // Detach the child from it's current parent first. - drgui_tvi_detach(pItemToPrepend); - - - pItemToPrepend->pParent = pItemToPrependTo->pParent; - assert(pItemToPrepend->pParent != NULL); - - pItemToPrepend->pPrevSibling = pItemToPrependTo->pNextSibling; - pItemToPrepend->pNextSibling = pItemToPrependTo; - - pItemToPrependTo->pPrevSibling->pNextSibling = pItemToPrepend; - pItemToPrependTo->pNextSibling = pItemToPrepend; - - if (pItemToPrepend->pParent->pFirstChild == pItemToPrependTo) { - pItemToPrepend->pParent->pFirstChild = pItemToPrepend; - } - - - // Refresh the layout and redraw the tree-view control. - drgui_tv_refresh_and_redraw(pItemToPrepend->pTVElement); - } -} - - -bool drgui_tvi_has_children(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return false; - } - - return pItem->pFirstChild != NULL; -} - -int drgui_tvi_get_depth(drgui_tree_view_item* pItem) -{ - if (pItem->pParent == NULL || pItem->pParent == drgui_tv_get_root_item(pItem->pTVElement)) { - return 0; - } - - return drgui_tvi_get_depth(pItem->pParent) + 1; -} - -drgui_tree_view_item* drgui_tvi_next_visible_non_child(drgui_tree_view_item* pItem, int* pDepthInOut) -{ - if (pItem == NULL) { - return NULL; - } - - if (pItem->pNextSibling != NULL) { - return pItem->pNextSibling; - } - - - if (pDepthInOut != NULL) { - *pDepthInOut -= 1; - } - - return drgui_tvi_next_visible_non_child(pItem->pParent, pDepthInOut); -} - - -void drgui_tvi_select(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return; - } - - if (!pItem->isSelected) - { - pItem->isSelected = true; - drgui_dirty(pItem->pTVElement, drgui_get_local_rect(pItem->pTVElement)); - } -} - -void drgui_tvi_deselect(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return; - } - - if (pItem->isSelected) - { - pItem->isSelected = false; - drgui_dirty(pItem->pTVElement, drgui_get_local_rect(pItem->pTVElement)); - } -} - -bool drgui_tvi_is_selected(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return false; - } - - return pItem->isSelected; -} - -void drgui_tvi_expand(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return; - } - - if (!pItem->isExpanded) - { - pItem->isExpanded = true; - drgui_tv_refresh_and_redraw(pItem->pTVElement); - } -} - -void drgui_tvi_collapse(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return; - } - - if (pItem->isExpanded) - { - pItem->isExpanded = false; - drgui_tv_refresh_and_redraw(pItem->pTVElement); - } -} - -bool drgui_tvi_is_expanded(drgui_tree_view_item* pItem) -{ - if (pItem == NULL) { - return false; - } - - return pItem->isExpanded; -} - - - -static void drgui_tvi_detach(drgui_tree_view_item* pItem) -{ - assert(pItem != NULL); - - if (pItem->pParent != NULL) - { - if (pItem->pParent->pFirstChild == pItem) { - pItem->pParent->pFirstChild = pItem->pNextSibling; - } - - if (pItem->pParent->pLastChild == pItem) { - pItem->pParent->pLastChild = pItem->pPrevSibling; - } - - - if (pItem->pPrevSibling != NULL) { - pItem->pPrevSibling->pNextSibling = pItem->pNextSibling; - } - - if (pItem->pNextSibling != NULL) { - pItem->pNextSibling->pPrevSibling = pItem->pPrevSibling; - } - } - - pItem->pParent = NULL; - pItem->pPrevSibling = NULL; - pItem->pNextSibling = NULL; -} -#endif //DR_GUI_IMPLEMENTATION - - -#ifdef DR_GUI_INCLUDE_WIP -// #include WIP files here. -#endif //DR_GUI_INCLUDE_WIP - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_math.h b/source/engine/thirdparty/dr_libs/old/dr_math.h deleted file mode 100644 index 0a74c05..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_math.h +++ /dev/null @@ -1,676 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. - -// NOTE: This is still very much work in progress and is only being updated as I need it. You don't want to be using this library -// in its current state. - -// QUICK NOTES -// - This library does not use SSE for its basic types (vec4, etc.). Rationale: 1) It keeps things simple; 2) SSE is not always -// faster than the FPU(s) on modern CPUs; 3) The library can always implement functions that work on __m128 variables directly -// in the future if the need arises; 4) It doesn't work well with the pass-by-value API this library uses. -// - Use DISABLE_SSE to disable SSE optimized functions. -// - Angles are always specified in radians, unless otherwise noted. Rationale: Consistency with the standard library and most -// other math libraries. -// - Use radians() and degrees() to convert between the two. - -#ifndef dr_math_h -#define dr_math_h - -#include - -#if defined(_MSC_VER) -#define DR_MATHCALL static __forceinline -#else -#define DR_MATHCALL static inline -#endif - -#define DR_PI 3.14159265358979323846 -#define DR_PIF 3.14159265358979323846f - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - float x; - float y; - float z; - float w; -} vec4; - -typedef struct -{ - float x; - float y; - float z; -} vec3; - -typedef struct -{ - float x; - float y; -} vec2; - -typedef struct -{ - vec4 col[4]; -} mat4; - -typedef struct -{ - float x; - float y; - float z; - float w; -} quat; - - -// Radians to degrees. -DR_MATHCALL float dr_degrees(float radians) -{ - return radians * 57.29577951308232087685f; -} - -// Degrees to radians. -DR_MATHCALL float dr_radians(float degrees) -{ - return degrees * 0.01745329251994329577f; -} - - - -/////////////////////////////////////////////// -// -// VEC4 -// -/////////////////////////////////////////////// - -DR_MATHCALL vec4 vec4f(float x, float y, float z, float w) -{ - vec4 result; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - - return result; -} -DR_MATHCALL vec4 vec4v(const float* v) -{ - return vec4f(v[0], v[1], v[2], v[3]); -} -DR_MATHCALL vec4 vec4_zero() -{ - return vec4f(0, 0, 0, 0); -} -DR_MATHCALL vec4 vec4_one() -{ - return vec4f(1, 1, 1, 1); -} - - - -DR_MATHCALL vec4 vec4_add(vec4 a, vec4 b) -{ - return vec4f(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); -} - -DR_MATHCALL vec4 vec4_sub(vec4 a, vec4 b) -{ - return vec4f(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); -} - - -DR_MATHCALL vec4 vec4_mul(vec4 a, vec4 b) -{ - return vec4f(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); -} -DR_MATHCALL vec4 vec4_mul_1f(vec4 a, float x) -{ - return vec4f(a.x * x, a.y * x, a.z * x, a.w * x); -} -DR_MATHCALL vec4 vec4_mul_mat4(vec4 v, mat4 m) -{ - const vec4 m0 = m.col[0]; - const vec4 m1 = m.col[1]; - const vec4 m2 = m.col[2]; - const vec4 m3 = m.col[3]; - - return vec4f( - m0.x*v.x + m0.y*v.y + m0.z*v.z + m0.w*v.w, - m1.x*v.x + m1.y*v.y + m1.z*v.z + m1.w*v.w, - m2.x*v.x + m2.y*v.y + m2.z*v.z + m2.w*v.w, - m3.x*v.x + m3.y*v.y + m3.z*v.z + m3.w*v.w - ); -} - - -DR_MATHCALL vec4 vec4_div(vec4 a, vec4 b) -{ - return vec4f(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); -} - - - - - - -/////////////////////////////////////////////// -// -// VEC3 -// -/////////////////////////////////////////////// - -DR_MATHCALL vec3 vec3f(float x, float y, float z) -{ - vec3 result; - result.x = x; - result.y = y; - result.z = z; - - return result; -} -DR_MATHCALL vec3 vec3v(const float* v) -{ - return vec3f(v[0], v[1], v[2]); -} -DR_MATHCALL vec3 vec3_zero() -{ - return vec3f(0, 0, 0); -} -DR_MATHCALL vec3 vec3_one() -{ - return vec3f(1, 1, 1); -} - - -DR_MATHCALL vec3 vec3_add(vec3 a, vec3 b) -{ - return vec3f(a.x + b.x, a.y + b.y, a.z + b.z); -} - -DR_MATHCALL vec3 vec3_sub(vec3 a, vec3 b) -{ - return vec3f(a.x - b.x, a.y - b.y, a.z - b.z); -} - - -DR_MATHCALL vec3 vec3_mul(vec3 a, vec3 b) -{ - return vec3f(a.x * b.x, a.y * b.y, a.z * b.z); -} -DR_MATHCALL vec3 vec3_mul_1f(vec3 a, float x) -{ - return vec3f(a.x * x, a.y * x, a.z * x); -} - - -DR_MATHCALL vec3 vec3_div(vec3 a, vec3 b) -{ - return vec3f(a.x / b.x, a.y / b.y, a.z / b.z); -} - - -DR_MATHCALL float vec3_dot(vec3 a, vec3 b) -{ - return a.x*b.x + a.y*b.y + a.z*b.z; -} - - -DR_MATHCALL float vec3_length2(vec3 a) -{ - return vec3_dot(a, a); -} - -DR_MATHCALL float vec3_length(vec3 a) -{ - return sqrtf(vec3_length2(a)); -} - - -DR_MATHCALL vec3 vec3_normalize(vec3 a) -{ - float len = vec3_length(a); - - return vec3f( - a.x / len, - a.y / len, - a.z / len - ); -} - -DR_MATHCALL vec3 vec3_cross(vec3 a, vec3 b) -{ - return vec3f( - a.y*b.z - a.z*b.y, - a.z*b.x - a.x*b.z, - a.x*b.y - a.y*b.x - ); -} - - -DR_MATHCALL vec3 vec3_triangle_normal(vec3 p1, vec3 p2, vec3 p3) -{ - vec3 u = vec3_sub(p2, p1); - vec3 v = vec3_sub(p3, p1); - return vec3_normalize(vec3_cross(u, v)); -} - - - -/////////////////////////////////////////////// -// -// VEC2 -// -/////////////////////////////////////////////// - -DR_MATHCALL vec2 vec2f(float x, float y) -{ - vec2 result; - result.x = x; - result.y = y; - - return result; -} -DR_MATHCALL vec2 vec2v(const float* v) -{ - return vec2f(v[0], v[1]); -} -DR_MATHCALL vec2 vec2_zero() -{ - return vec2f(0, 0); -} -DR_MATHCALL vec2 vec2_one() -{ - return vec2f(1, 1); -} - - -DR_MATHCALL vec2 vec2_add(vec2 a, vec2 b) -{ - return vec2f(a.x + b.x, a.y + b.y); -} - -DR_MATHCALL vec2 vec2_sub(vec2 a, vec2 b) -{ - return vec2f(a.x - b.x, a.y - b.y); -} - - -DR_MATHCALL vec2 vec2_mul(vec2 a, vec2 b) -{ - return vec2f(a.x * b.x, a.y * b.y); -} -DR_MATHCALL vec2 vec2_mul_1f(vec2 a, float x) -{ - return vec2f(a.x * x, a.y * x); -} - - -DR_MATHCALL vec2 vec2_div(vec2 a, vec2 b) -{ - return vec2f(a.x / b.x, a.y / b.y); -} - - -DR_MATHCALL float vec2_dot(vec2 a, vec2 b) -{ - return a.x*b.x + a.y*b.y; -} - - -DR_MATHCALL float vec2_length2(vec2 a) -{ - return vec2_dot(a, a); -} - -DR_MATHCALL float vec2_length(vec2 a) -{ - return sqrtf(vec2_length2(a)); -} - - -DR_MATHCALL vec2 vec2_normalize(vec2 a) -{ - float len = vec2_length(a); - - return vec2f( - a.x / len, - a.y / len - ); -} - - -DR_MATHCALL float vec2_angle(vec2 a, vec2 b) -{ - return atanf(a.y / a.x) - atanf(b.y / b.x); -} - -DR_MATHCALL vec2 vec2_rotate(vec2 a, float angleInRadians) -{ - float c = cosf(angleInRadians); - float s = sinf(angleInRadians); - - return vec2f( - a.x*c - a.y*s, - a.x*s + a.y*c - ); -} - - -/////////////////////////////////////////////// -// -// MAT4 -// -/////////////////////////////////////////////// - -DR_MATHCALL mat4 mat4f(vec4 col0, vec4 col1, vec4 col2, vec4 col3) -{ - mat4 result; - result.col[0] = col0; - result.col[1] = col1; - result.col[2] = col2; - result.col[3] = col3; - - return result; -} - -DR_MATHCALL mat4 mat4_identity() -{ - mat4 result; - result.col[0] = vec4f(1, 0, 0, 0); - result.col[1] = vec4f(0, 1, 0, 0); - result.col[2] = vec4f(0, 0, 1, 0); - result.col[3] = vec4f(0, 0, 0, 1); - - return result; -} - -DR_MATHCALL mat4 mat4_ortho(float left, float right, float bottom, float top, float znear, float zfar) -{ - float rml = right - left; - float tmb = top - bottom; - float fmn = zfar - znear; - - float rpl = right + left; - float tpb = top + bottom; - float fpn = zfar + znear; - - mat4 result; - result.col[0] = vec4f(2/rml, 0, 0, 0); - result.col[1] = vec4f(0, 2/tmb, 0, 0); - result.col[2] = vec4f(0, 0, -2/fmn, 0); - result.col[3] = vec4f(-(rpl/rml), -(tpb/tmb), -(fpn/fmn), 1); - - return result; -} - -DR_MATHCALL mat4 mat4_perspective(float fovy, float aspect, float znear, float zfar) -{ - float f = (float)tan(DR_PI/2 - fovy/2); - - mat4 result; - result.col[0] = vec4f(f / aspect, 0, 0, 0); - result.col[1] = vec4f(0, f, 0, 0); - result.col[2] = vec4f(0, 0, (zfar + znear) / (znear - zfar), -1); - result.col[3] = vec4f(0, 0, (2 * zfar * znear) / (znear - zfar), 0); - - return result; -} - -DR_MATHCALL mat4 mat4_vulkan_clip_correction() -{ - mat4 result; - result.col[0] = vec4f(1, 0, 0, 0); - result.col[1] = vec4f(0, -1, 0, 0); - result.col[2] = vec4f(0, 0, 0.5f, 0); - result.col[3] = vec4f(0, 0, 0.5f, 1); - - return result; -} - -DR_MATHCALL mat4 mat4_translate(vec3 translation) -{ - mat4 result; - result.col[0] = vec4f(1, 0, 0, 0); - result.col[1] = vec4f(0, 1, 0, 0); - result.col[2] = vec4f(0, 0, 1, 0); - result.col[3] = vec4f(translation.x, translation.y, translation.z, 1); - - return result; -} - -DR_MATHCALL mat4 mat4_rotate(float angleInRadians, vec3 axis) -{ - float c = cosf(angleInRadians); - float s = sinf(angleInRadians); - - float x = axis.x; - float y = axis.y; - float z = axis.z; - - float xx = x*x; - float xy = x*y; - float xz = x*z; - float yy = y*y; - float yz = y*z; - float zz = z*z; - - float xs = x*s; - float ys = y*s; - float zs = z*s; - - mat4 result; - result.col[0] = vec4f(xx * (1 - c) + c, xy * (1 - c) - zs, xz * (1 - c) + ys, 0); - result.col[1] = vec4f(xy * (1 - c) + zs, yy * (1 - c) + c, yz * (1 - c) - xs, 0); - result.col[2] = vec4f(xz * (1 - c) - ys, yz * (1 - c) + xs, zz * (1 - c) + c, 0); - result.col[3] = vec4f(0, 0, 0, 1); - - return result; -} - -DR_MATHCALL mat4 mat4_scale(vec3 scale) -{ - mat4 result; - result.col[0] = vec4f(scale.x, 0, 0, 0); - result.col[1] = vec4f(0, scale.y, 0, 0); - result.col[2] = vec4f(0, 0, scale.z, 0); - result.col[3] = vec4f(0, 0, 0, 1); - - return result; -} - - -DR_MATHCALL mat4 mat4_mul(mat4 a, mat4 b) -{ - const vec4 a0 = a.col[0]; - const vec4 a1 = a.col[1]; - const vec4 a2 = a.col[2]; - const vec4 a3 = a.col[3]; - - const vec4 b0 = b.col[0]; - const vec4 b1 = b.col[1]; - const vec4 b2 = b.col[2]; - const vec4 b3 = b.col[3]; - - mat4 result; - result.col[0] = vec4f( - a0.x*b0.x + a1.x*b0.y + a2.x*b0.z + a3.x*b0.w, - a0.y*b0.x + a1.y*b0.y + a2.y*b0.z + a3.y*b0.w, - a0.z*b0.x + a1.z*b0.y + a2.z*b0.z + a3.z*b0.w, - a0.w*b0.x + a1.w*b0.y + a2.w*b0.z + a3.w*b0.w - ); - - result.col[1] = vec4f( - a0.x*b1.x + a1.x*b1.y + a2.x*b1.z + a3.x*b1.w, - a0.y*b1.x + a1.y*b1.y + a2.y*b1.z + a3.y*b1.w, - a0.z*b1.x + a1.z*b1.y + a2.z*b1.z + a3.z*b1.w, - a0.w*b1.x + a1.w*b1.y + a2.w*b1.z + a3.w*b1.w - ); - - result.col[2] = vec4f( - a0.x*b2.x + a1.x*b2.y + a2.x*b2.z + a3.x*b2.w, - a0.y*b2.x + a1.y*b2.y + a2.y*b2.z + a3.y*b2.w, - a0.z*b2.x + a1.z*b2.y + a2.z*b2.z + a3.z*b2.w, - a0.w*b2.x + a1.w*b2.y + a2.w*b2.z + a3.w*b2.w - ); - - result.col[3] = vec4f( - a0.x*b3.x + a1.x*b3.y + a2.x*b3.z + a3.x*b3.w, - a0.y*b3.x + a1.y*b3.y + a2.y*b3.z + a3.y*b3.w, - a0.z*b3.x + a1.z*b3.y + a2.z*b3.z + a3.z*b3.w, - a0.w*b3.x + a1.w*b3.y + a2.w*b3.z + a3.w*b3.w - ); - - return result; -} - -DR_MATHCALL vec4 mat4_mul_vec4(mat4 m, vec4 v) -{ - const vec4 m0 = m.col[0]; - const vec4 m1 = m.col[1]; - const vec4 m2 = m.col[2]; - const vec4 m3 = m.col[3]; - - return vec4f( - m0.x*v.x + m1.x*v.y + m2.x*v.z + m3.x*v.w, - m0.y*v.x + m1.y*v.y + m2.y*v.z + m3.y*v.w, - m0.z*v.x + m1.z*v.y + m2.z*v.z + m3.z*v.w, - m0.w*v.x + m1.w*v.y + m2.w*v.z + m3.w*v.w - ); -} - - -/////////////////////////////////////////////// -// -// QUAT -// -/////////////////////////////////////////////// - -DR_MATHCALL quat quatf(float x, float y, float z, float w) -{ - quat result; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - - return result; -} -DR_MATHCALL quat quatv(const float* v) -{ - return quatf(v[0], v[1], v[2], v[3]); -} - -DR_MATHCALL quat quat_identity() -{ - return quatf(0, 0, 0, 1); -} - - - - - -/////////////////////////////////////////////// -// -// TRANSFORM -// -/////////////////////////////////////////////// - -typedef struct -{ - vec3 position; - quat rotation; - vec3 scale; -}transform_t; - -DR_MATHCALL transform_t transform_init(vec3 position, quat rotation, vec3 scale) -{ - transform_t result; - result.position = position; - result.rotation = rotation; - result.scale = scale; - - return result; -} - -DR_MATHCALL transform_t transform_identity() -{ - transform_t result; - result.position = vec3_zero(); - result.rotation = quat_identity(); - result.scale = vec3_one(); - - return result; -} - - -DR_MATHCALL transform_t transform_translate(transform_t transform, vec3 offset) -{ - transform_t result = transform; - result.position = vec3_add(transform.position, offset); - - return result; -} - - - - -/////////////////////////////////////////////// -// -// SSE IMPLEMENTATION -// -/////////////////////////////////////////////// - -// Not supporting SSE on x86/MSVC due to pass-by-value errors with aligned types. -#if (defined(_MSC_VER) && defined(_M_X64)) || defined(__SSE2__) -#define SUPPORTS_SSE -#endif - -#if !defined(DISABLE_SSE) && defined(SUPPORTS_SSE) -#define ENABLE_SSE -#endif - -#ifdef ENABLE_SSE -#if defined(__MINGW32__) -#include -#endif -#include -#endif - - - - - -#ifdef __cplusplus -} -#endif - -#endif //dr_math_h - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_mtl.h b/source/engine/thirdparty/dr_libs/old/dr_mtl.h deleted file mode 100644 index cf97a98..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_mtl.h +++ /dev/null @@ -1,4512 +0,0 @@ -// Public Domain. See "unlicense" statement at the end of this file. - -// ABOUT -// -// dr_mtl is a library for loading materials for use in 2D or 3D graphics. But it's a bit different to -// what you may expect. It does not reprsent materials as a static data, but rather as a series of -// instructions that interface with a set of inputs. Indeed, this library is more like a compiler - you -// specify an input file (such as a Wavefront MTL file), compile it into an intermediate bytecode -// represenation, and then run it through a code generator to generate shader code such as GLSL, HLSL, -// Spir-V, etc. -// -// -// -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_MTL_IMPLEMENTATION -// #include "dr_mtl.h" -// -// You can then #include dr_mtl.h in other parts of the program as you would with any other header file. -// -// -// -// OPTIONS -// -// #define DRMTL_NO_MTL_COMPILER -// Disables the Wavefront MTL compiler. -// -// #define DRMTL_NO_GLSL_CODEGEN -// Disables the GLSL code generator. -// -// -// -// TODO -// - Add more documentation. -// - Add a demo to demonstrate the awesomeness of this library. -// - Add trigonometric instructions. - -#ifndef dr_mtl_h -#define dr_mtl_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4201) // Non-standard extension used: nameless struct/union. -#endif - - -#define DRMTL_MAGIC_NUMBER 0x81DF7405 -#define DRMTL_CURRENT_VERSION 1 - -#define DRMTL_INPUT_DESC_CONSTI ((unsigned char)-2) -#define DRMTL_INPUT_DESC_CONSTF ((unsigned char)-1) -#define DRMTL_INPUT_DESC_VARX ((unsigned char)0) -#define DRMTL_INPUT_DESC_VARY ((unsigned char)1) -#define DRMTL_INPUT_DESC_VARZ ((unsigned char)2) -#define DRMTL_INPUT_DESC_VARW ((unsigned char)3) - -#define DRMTL_MAX_IDENTIFIER_NAME 28 -#define DRMTL_MAX_CHANNEL_NAME 28 -#define DRMTL_MAX_PROPERTY_NAME 28 - -#define DRMTL_MAX_INPUT_PATH 252 -#define DRMTL_MAX_PROPERTY_PATH 224 - - -typedef unsigned char drmtl_uint8; -typedef unsigned int drmtl_uint32; - -typedef struct drmtl_material drmtl_material; - - -/// The various data type available to the material. -typedef enum -{ - drmtl_type_float = 1, - drmtl_type_float2 = 2, - drmtl_type_float3 = 3, - drmtl_type_float4 = 4, - drmtl_type_int = 5, - drmtl_type_int2 = 6, - drmtl_type_int3 = 7, - drmtl_type_int4 = 8, - drmtl_type_tex1d = 9, - drmtl_type_tex2d = 10, - drmtl_type_tex3d = 11, - drmtl_type_texcube = 12, - drmtl_type_bool = 13 - -} drmtl_type; - -/// The various run-time opcodes. -typedef enum -{ - ////////////////////////// - // Assignment - - // mov - drmtl_opcode_movf1 = 0x00000001, - drmtl_opcode_movf2 = 0x00000002, - drmtl_opcode_movf3 = 0x00000003, - drmtl_opcode_movf4 = 0x00000004, - drmtl_opcode_movi1 = 0x00000005, - drmtl_opcode_movi2 = 0x00000006, - drmtl_opcode_movi3 = 0x00000007, - drmtl_opcode_movi4 = 0x00000008, - - - ////////////////////////// - // Arithmetic - - // add - drmtl_opcode_addf1 = 0x00001001, - drmtl_opcode_addf2 = 0x00001002, - drmtl_opcode_addf3 = 0x00001003, - drmtl_opcode_addf4 = 0x00001004, - drmtl_opcode_addi1 = 0x00001005, - drmtl_opcode_addi2 = 0x00001006, - drmtl_opcode_addi3 = 0x00001007, - drmtl_opcode_addi4 = 0x00001008, - - // sub - drmtl_opcode_subf1 = 0x00001101, - drmtl_opcode_subf2 = 0x00001102, - drmtl_opcode_subf3 = 0x00001103, - drmtl_opcode_subf4 = 0x00001104, - drmtl_opcode_subi1 = 0x00001105, - drmtl_opcode_subi2 = 0x00001106, - drmtl_opcode_subi3 = 0x00001107, - drmtl_opcode_subi4 = 0x00001108, - - // mul - drmtl_opcode_mulf1 = 0x00001201, - drmtl_opcode_mulf2 = 0x00001202, - drmtl_opcode_mulf3 = 0x00001203, - drmtl_opcode_mulf4 = 0x00001204, - drmtl_opcode_muli1 = 0x00001205, - drmtl_opcode_muli2 = 0x00001206, - drmtl_opcode_muli3 = 0x00001207, - drmtl_opcode_muli4 = 0x00001208, - - // div - drmtl_opcode_divf1 = 0x00001301, - drmtl_opcode_divf2 = 0x00001302, - drmtl_opcode_divf3 = 0x00001303, - drmtl_opcode_divf4 = 0x00001304, - drmtl_opcode_divi1 = 0x00001305, - drmtl_opcode_divi2 = 0x00001306, - drmtl_opcode_divi3 = 0x00001307, - drmtl_opcode_divi4 = 0x00001308, - - // pow - drmtl_opcode_powf1 = 0x00001401, - drmtl_opcode_powf2 = 0x00001402, - drmtl_opcode_powf3 = 0x00001403, - drmtl_opcode_powf4 = 0x00001404, - drmtl_opcode_powi1 = 0x00001405, - drmtl_opcode_powi2 = 0x00001406, - drmtl_opcode_powi3 = 0x00001407, - drmtl_opcode_powi4 = 0x00001408, - - - ////////////////////////// - // Textures - - // tex - drmtl_opcode_tex1 = 0x00002001, - drmtl_opcode_tex2 = 0x00002002, - drmtl_opcode_tex3 = 0x00002003, - drmtl_opcode_texcube = 0x00002004, - - - ////////////////////////// - // Miscellaneous - - // var - drmtl_opcode_var = 0x00003000, - - // ret - drmtl_opcode_retf1 = 0x00003001, - drmtl_opcode_retf2 = 0x00003002, - drmtl_opcode_retf3 = 0x00003003, - drmtl_opcode_retf4 = 0x00003004, - drmtl_opcode_reti1 = 0x00003005, - drmtl_opcode_reti2 = 0x00003006, - drmtl_opcode_reti3 = 0x00003007, - drmtl_opcode_reti4 = 0x00003008 - -} drmtl_opcode; - - -/// Structure containing information about an identifier. An identifier contains a type (float, float2, etc.) and a name. The -/// total size of this structure is 32 bytes. The name is null terminated. -typedef struct -{ - /// The type of the identifier. - drmtl_type type; - - /// The name of the identifier. - char name[DRMTL_MAX_IDENTIFIER_NAME]; - -} drmtl_identifier; - - -/// Structure containing information about an input variable. -typedef struct -{ - /// The index into the identifier table that this input variable is identified by. - unsigned int identifierIndex; - - /// The default value of the input variable. - union - { - struct - { - float x; - } f1; - struct - { - float x; - float y; - } f2; - struct - { - float x; - float y; - float z; - } f3; - struct - { - float x; - float y; - float z; - float w; - } f4; - - struct - { - int x; - } i1; - struct - { - int x; - int y; - } i2; - struct - { - int x; - int y; - int z; - } i3; - struct - { - int x; - int y; - int z; - int w; - } i4; - - struct - { - char value[DRMTL_MAX_INPUT_PATH]; // Enough room for a path, but less to keep the total size of the structure at 256 bytes. Null terminated. - } path; - - - struct - { - drmtl_uint32 x; - drmtl_uint32 y; - drmtl_uint32 z; - drmtl_uint32 w; - } raw4; - }; - -} drmtl_input; - - -typedef struct -{ - /// The return type of the channel. - drmtl_type type; - - /// The name of the channel. Null terminated. - char name[DRMTL_MAX_CHANNEL_NAME]; - -} drmtl_channel; - - -/// An instruction input value. An input value to an instruction can usually be a constant or the identifier index of the -/// applicable variable. -typedef union -{ - /// The identifier index of the applicable variable. - unsigned int id; - - /// The constant value, as a float. - float valuef; - - /// The constant value, as an integer. - int valuei; - -}drmtl_instruction_input; - - -/// Structure used for describing an instructions input data. -typedef struct -{ - unsigned char x; - unsigned char y; - unsigned char z; - unsigned char w; - -} drmtl_instruction_input_descriptor; - -/// Structure containing information about an instruction. -typedef struct -{ - /// The instruction's opcode. - drmtl_opcode opcode; - - /// The instruction's data. - union - { - // mov data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int output; - } mov; - - - // add data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int output; - } add; - - // sub data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int output; - } sub; - - // mul data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int output; - } mul; - - // div data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int output; - } div; - - // pow data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int output; - } pow; - - - // tex data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - unsigned int texture; - unsigned int output; - } tex; - - - // ret data. - struct - { - drmtl_instruction_input_descriptor inputDesc; - drmtl_instruction_input inputX; - drmtl_instruction_input inputY; - drmtl_instruction_input inputZ; - drmtl_instruction_input inputW; - } ret; - - - // var data - struct - { - //drmtl_type type; - unsigned int identifierIndex; - } var; - - - // Ensures the size of the instruction is always 32 bytes. - struct - { - drmtl_uint8 _unused[32]; - } unused; - }; - -} drmtl_instruction; - - -typedef struct -{ - /// The type of the property. - drmtl_type type; - - /// The name of the property. - char name[DRMTL_MAX_PROPERTY_NAME]; - - /// The default value of the input variable. - union - { - struct - { - float x; - } f1; - struct - { - float x; - float y; - } f2; - struct - { - float x; - float y; - float z; - } f3; - struct - { - float x; - float y; - float z; - float w; - } f4; - - struct - { - int x; - } i1; - struct - { - int x; - int y; - } i2; - struct - { - int x; - int y; - int z; - } i3; - struct - { - int x; - int y; - int z; - int w; - } i4; - - struct - { - char value[DRMTL_MAX_PROPERTY_PATH]; // Enough room for a path, but less to keep the total size of the structure at 256 bytes. Null terminated. - } path; - - struct - { - int x; - } b1; - }; - -} drmtl_property; - - -/// Structure containing the header information of the material. -typedef struct -{ - /// The magic number: 0x81DF7405 - unsigned int magic; - - /// The version number. There is currently only a single version - version 1. In the future there may be other versions - /// which will affect how the file is formatted. - unsigned int version; - - - /// The size in bytes of an identifier. - unsigned int identifierSizeInBytes; - - /// The size in bytes of an input variable. - unsigned int inputSizeInBytes; - - /// The size of a channel header, in bytes. - unsigned int channelHeaderSizeInBytes; - - /// The size in bytes of an instruction. - unsigned int instructionSizeInBytes; - - /// The size in bytes of a property. - unsigned int propertySizeInBytes; - - - /// The total number of identifiers. - unsigned int identifierCount; - - /// The total number of private input variables. - unsigned int privateInputCount; - - /// The total number of public input variables. - unsigned int publicInputCount; - - /// The total number of channels. - unsigned int channelCount; - - /// The total number of properties. - unsigned int propertyCount; - - - /// The offset of the identifiers. - unsigned int identifiersOffset; - - /// The offset of the input variables. - unsigned int inputsOffset; - - /// The offset of the channels. - unsigned int channelsOffset; - - /// The offset of the properties. - unsigned int propertiesOffset; - - -} drmtl_header; - -typedef struct -{ - /// The channel information. - drmtl_channel channel; - - /// The instruction count of the channel. - unsigned int instructionCount; - -} drmtl_channel_header; - - -/// Structure containing the definition of the material. -struct drmtl_material -{ - /// A pointer to the raw data. This will at least be the size of drmtl_header (128 bytes, as of version 1). - drmtl_uint8* pRawData; - - /// The size of the data, in bytes. - unsigned int sizeInBytes; - - /// The size of the buffer, in bytes. This is used to determine when the buffer needs to be inflated. - unsigned int bufferSizeInBytes; - - - /// The current stage of the construction process of the material. A material must be constructed in order, so this - /// keeps track of the current stage to ensure the proper errors are returned. - unsigned int currentStage; - - /// The offset of the current channel. This is needed to we can determine which bytes need to be updated as - /// instructions are added to the channel. - unsigned int currentChannelOffset; - - - /// Whether or not the material data is owned by this library. When this is set to false, the library will - /// never modify the original pointer. - bool ownsRawData; -}; - - - -//////////////////////////////////////////////////////// -// Low-Level APIs -// -// Use these APIs to work on materials directly. Note that these are intentionally restrictive in that things can -// be added to the material, however they can never be removed. In addition, everything must be added in order which -// means identifiers need to be added first, followed by private inputs, followed by public inputs, followed by -// channels, followed by properties. -// -// Use these to construct a material after everything has been processed at a higher level. - -/// Initializes the given material. -/// -/// @param pMaterial [in] A pointer to the material to initialize. -/// -/// @return True if the material is initialized successfully; false otherwise. -bool drmtl_init(drmtl_material* pMaterial); -bool drmtl_initfromexisting(drmtl_material* pMaterial, const void* pRawData, unsigned int dataSizeInBytes); -bool drmtl_initfromexisting_nocopy(drmtl_material* pMaterial, const void* pRawData, unsigned int dataSizeInBytes); - -/// Uninitializes the given material. -/// -/// @param pMaterial [in] A pointer to the material to uninitialize. -void drmtl_uninit(drmtl_material* pMaterial); - - -/// Retrieve a pointer to the header information. -drmtl_header* drmtl_getheader(drmtl_material* pMaterial); - - -/// Appends an identifier to the end of the identifier list. Use drmtl_getidentifiercount() to determine it's index. -/// -/// @param pMaterial [in] A pointer to the material to append the identifier to. -bool drmtl_appendidentifier(drmtl_material* pMaterial, drmtl_identifier identifier, unsigned int* indexOut); - -/// Appends a private input variable. -bool drmtl_appendprivateinput(drmtl_material* pMaterial, drmtl_input input); - -/// Appends a public input variable. -bool drmtl_appendpublicinput(drmtl_material* pMaterial, drmtl_input input); - -/// Begins a new channel. -/// -/// @remarks -/// Any instructions that are appended from now on will be part of this channel until another channel is begun. -/// @par -/// The end of the channel is marked when a new channel is appended or a property begins. -bool drmtl_appendchannel(drmtl_material* pMaterial, drmtl_channel channelHeader); - -/// Appends an instruction to the most recently appended channel. -bool drmtl_appendinstruction(drmtl_material* pMaterial, drmtl_instruction instruction); - -/// Append a property. -bool drmtl_appendproperty(drmtl_material* pMaterial, drmtl_property prop); - - -/// Retrieves a pointer to the channel header by it's index. -/// -/// @remarks -/// This runs in linear time. -drmtl_channel_header* drmtl_getchannelheaderbyindex(drmtl_material* pMaterial, unsigned int channelIndex); - -/// Retrieves a pointer to the channel header by it's name. -/// -/// @remarks -/// This runs in linear time. -drmtl_channel_header* drmtl_getchannelheaderbyname(drmtl_material* pMaterial, const char* channelName); - - -/// Retrieves a pointer to the buffer containing the list of identifiers. -drmtl_identifier* drmtl_getidentifiers(drmtl_material* pMaterial); -drmtl_identifier* drmtl_getidentifier(drmtl_material* pMaterial, unsigned int index); - -/// Retrieves the number of identifiers defined by the given material. -unsigned int drmtl_getidentifiercount(drmtl_material* pMaterial); - - -/// Retrieves the number of private + public input variables. -unsigned int drmtl_getinputcount(drmtl_material* pMaterial); - -/// Retrieves the input variable by it's index. -drmtl_input* drmtl_getinputbyindex(drmtl_material* pMaterial, unsigned int index); - -/// Retrieves the number of private input variables. -unsigned int drmtl_getprivateinputcount(drmtl_material* pMaterial); - -/// Retrieves the private input variable by it's index. -drmtl_input* drmtl_getprivateinputbyindex(drmtl_material* pMaterial, unsigned int index); - -/// Retrieves the number of public input variables. -unsigned int drmtl_getpublicinputcount(drmtl_material* pMaterial); - -/// Retrieves the public input variable by it's index. -drmtl_input* drmtl_getpublicinputbyindex(drmtl_material* pMaterial, unsigned int index); - - -/// Retrieves the number of properties. -unsigned int drmtl_getpropertycount(drmtl_material* pMaterial); - -/// Retrieves a property by it's index. -drmtl_property* drmtl_getpropertybyindex(drmtl_material* pMaterial, unsigned int index); - -/// Retrieves a properties by it's name. -/// -/// @remarks -/// This is case-sensitive. -drmtl_property* drmtl_getpropertybyname(drmtl_material* pMaterial, const char* name); - - - -//////////////////////////////////////////////////////// -// Mid-Level APIs - -/// Helper for creating an identifier. -drmtl_identifier drmtl_identifier_float(const char* name); -drmtl_identifier drmtl_identifier_float2(const char* name); -drmtl_identifier drmtl_identifier_float3(const char* name); -drmtl_identifier drmtl_identifier_float4(const char* name); -drmtl_identifier drmtl_identifier_int(const char* name); -drmtl_identifier drmtl_identifier_int2(const char* name); -drmtl_identifier drmtl_identifier_int3(const char* name); -drmtl_identifier drmtl_identifier_int4(const char* name); -drmtl_identifier drmtl_identifier_tex2d(const char* name); - -/// Helper for creating an input variable. -drmtl_input drmtl_input_float(unsigned int identifierIndex, float x); -drmtl_input drmtl_input_float2(unsigned int identifierIndex, float x, float y); -drmtl_input drmtl_input_float3(unsigned int identifierIndex, float x, float y, float z); -drmtl_input drmtl_input_float4(unsigned int identifierIndex, float x, float y, float z, float w); -drmtl_input drmtl_input_int(unsigned int identifierIndex, int x); -drmtl_input drmtl_input_int2(unsigned int identifierIndex, int x, int y); -drmtl_input drmtl_input_int3(unsigned int identifierIndex, int x, int y, int z); -drmtl_input drmtl_input_int4(unsigned int identifierIndex, int x, int y, int z, int w); -drmtl_input drmtl_input_tex(unsigned int identifierIndex, const char* path); - -/// Helper for creating a channel. -drmtl_channel drmtl_channel_float(const char* name); -drmtl_channel drmtl_channel_float2(const char* name); -drmtl_channel drmtl_channel_float3(const char* name); -drmtl_channel drmtl_channel_float4(const char* name); -drmtl_channel drmtl_channel_int(const char* name); -drmtl_channel drmtl_channel_int2(const char* name); -drmtl_channel drmtl_channel_int3(const char* name); -drmtl_channel drmtl_channel_int4(const char* name); - -/// Helper for creating an instruction. These are heavily simplified and more complex setups are possible using lower level APIs. -drmtl_instruction drmtl_movf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_movf1_c1(unsigned int outputIdentifierIndex, float x); -drmtl_instruction drmtl_movf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_movf2_c2(unsigned int outputIdentifierIndex, float x, float y); -drmtl_instruction drmtl_movf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_movf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z); -drmtl_instruction drmtl_movf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_movf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w); - -drmtl_instruction drmtl_addf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_addf1_c1(unsigned int outputIdentifierIndex, float x); -drmtl_instruction drmtl_addf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_addf2_c2(unsigned int outputIdentifierIndex, float x, float y); -drmtl_instruction drmtl_addf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_addf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z); -drmtl_instruction drmtl_addf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_addf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w); - -drmtl_instruction drmtl_subf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_subf1_c1(unsigned int outputIdentifierIndex, float x); -drmtl_instruction drmtl_subf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_subf2_c2(unsigned int outputIdentifierIndex, float x, float y); -drmtl_instruction drmtl_subf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_subf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z); -drmtl_instruction drmtl_subf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_subf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w); - -drmtl_instruction drmtl_mulf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_mulf1_c1(unsigned int outputIdentifierIndex, float x); -drmtl_instruction drmtl_mulf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_mulf2_c2(unsigned int outputIdentifierIndex, float x, float y); -drmtl_instruction drmtl_mulf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_mulf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z); -drmtl_instruction drmtl_mulf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_mulf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w); -drmtl_instruction drmtl_mulf4_v3v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndexXYZ, unsigned int inputIdentifierIndexW); -drmtl_instruction drmtl_mulf4_v3c1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex, float w); -drmtl_instruction drmtl_mulf4_v2c2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex, float z, float w); -drmtl_instruction drmtl_mulf4_v1c3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex, float y, float z, float w); -drmtl_instruction drmtl_mulf4_v1v1v1v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndexX, unsigned int inputIdentifierIndexY, unsigned int inputIdentifierIndexZ, unsigned int inputIdentifierIndexW); - -drmtl_instruction drmtl_divf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_divf1_c1(unsigned int outputIdentifierIndex, float x); -drmtl_instruction drmtl_divf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_divf2_c2(unsigned int outputIdentifierIndex, float x, float y); -drmtl_instruction drmtl_divf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_divf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z); -drmtl_instruction drmtl_divf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex); -drmtl_instruction drmtl_divf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w); - -drmtl_instruction drmtl_tex2(unsigned int outputIdentifierIndex, unsigned int textureIdentifierIndex, unsigned int texcoordIdentifierIndex); -drmtl_instruction drmtl_var(unsigned int identifierIndex); -drmtl_instruction drmtl_retf1(unsigned int identifierIndex); -drmtl_instruction drmtl_retf2(unsigned int identifierIndex); -drmtl_instruction drmtl_retf3(unsigned int identifierIndex); -drmtl_instruction drmtl_retf4(unsigned int identifierIndex); -drmtl_instruction drmtl_retf1_c1(float x); -drmtl_instruction drmtl_retf2_c2(float x, float y); -drmtl_instruction drmtl_retf3_c3(float x, float y, float z); -drmtl_instruction drmtl_retf4_c4(float x, float y, float z, float w); -drmtl_instruction drmtl_reti1(unsigned int identifierIndex); -drmtl_instruction drmtl_reti2(unsigned int identifierIndex); -drmtl_instruction drmtl_reti3(unsigned int identifierIndex); -drmtl_instruction drmtl_reti4(unsigned int identifierIndex); -drmtl_instruction drmtl_reti1_c1(int x); -drmtl_instruction drmtl_reti2_c2(int x, int y); -drmtl_instruction drmtl_reti3_c3(int x, int y, int z); -drmtl_instruction drmtl_reti4_c4(int x, int y, int z, int w); - -/// Helper for creating a property. -drmtl_property drmtl_property_float(const char* name, float x); -drmtl_property drmtl_property_float2(const char* name, float x, float y); -drmtl_property drmtl_property_float3(const char* name, float x, float y, float z); -drmtl_property drmtl_property_float4(const char* name, float x, float y, float z, float w); -drmtl_property drmtl_property_int(const char* name, int x); -drmtl_property drmtl_property_int2(const char* name, int x, int y); -drmtl_property drmtl_property_int3(const char* name, int x, int y, int z); -drmtl_property drmtl_property_int4(const char* name, int x, int y, int z, int w); -drmtl_property drmtl_property_bool(const char* name, bool value); - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Compilers -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef DRMTL_NO_MTL_COMPILER -/// Compiles a Wavefront MTL file. -/// -/// @param pMaterial [in] A pointer to the destination material. -/// -/// @remarks -/// This will compile the material at the first occurance of the "newmtl" statement, and will end at either the next -/// occurance of "newmtl" of when the input buffer has been exhausted. -/// @par -/// This will initialize the material, so ensure that you have not already initialized it before calling this. If this -/// returns successfully, call drmtl_uninit() to uninitialize the material. -/// @par -/// MTL files require texture coordinates in order to know how to select the appropriate sample from textures. The -/// of the variable to use is specified in "texcoordInputName", and assumed to have at least 2 components (x and y). -bool drmtl_compile_wavefront_mtl(drmtl_material* pMaterial, const char* mtlData, size_t mtlDataSizeInBytes, const char* texcoordInputName); -#endif - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Code Generators -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef DRMTL_NO_GLSL_CODEGEN -/// Generates GLSL code for the channel with the given name. -bool drmtl_codegen_glsl_channel(drmtl_material* pMaterial, const char* channelName, char* codeOut, size_t codeOutSizeInBytes, size_t* pBytesWrittenOut); - -/// Generates GLSL code for the uniform variables as defined by the material's public input variables. -bool drmtl_codegen_glsl_uniforms(drmtl_material* pMaterial, char* codeOut, size_t codeOutSizeInBytes, size_t* pBytesWritteOut); -#endif - - - - - -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - -#ifdef __cplusplus -} -#endif - -#endif //dr_mtl_h - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_MTL_IMPLEMENTATION -#include -#include -#include -#include -#include - -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -// When constructing the material's raw data, memory is allocated in blocks of this amount. This must be at least 256. -#define DRMTL_CHUNK_SIZE 4096 - -#define DRMTL_STAGE_IDS 0 -#define DRMTL_STAGE_PRIVATE_INPUTS 1 -#define DRMTL_STAGE_PUBLIC_INPUTS 2 -#define DRMTL_STAGE_CHANNELS 3 -#define DRMTL_STAGE_PROPERTIES 4 -#define DRMTL_STAGE_COMPLETE UINT_MAX - - -//////////////////////////////////////////////////////// -// Utilities - -// strcpy() -static int drmtl_strcpy(char* dst, size_t dstSizeInBytes, const char* src) -{ -#if defined(_MSC_VER) - return strcpy_s(dst, dstSizeInBytes, src); -#else - if (dst == 0) { - return EINVAL; - } - if (dstSizeInBytes == 0) { - return ERANGE; - } - if (src == 0) { - dst[0] = '\0'; - return EINVAL; - } - - char* iDst = dst; - const char* iSrc = src; - size_t remainingSizeInBytes = dstSizeInBytes; - while (remainingSizeInBytes > 0 && iSrc[0] != '\0') - { - iDst[0] = iSrc[0]; - - iDst += 1; - iSrc += 1; - remainingSizeInBytes -= 1; - } - - if (remainingSizeInBytes > 0) { - iDst[0] = '\0'; - } else { - dst[0] = '\0'; - return ERANGE; - } - - return 0; -#endif -} - - - -/// Inflates the materials data buffer by DRMTL_CHUNK_SIZE. -bool _drmtl_inflate(drmtl_material* pMaterial); - - -bool drmtl_init(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - assert(DRMTL_CHUNK_SIZE >= 256); - - pMaterial->pRawData = (drmtl_uint8*)malloc(DRMTL_CHUNK_SIZE); - if (pMaterial->pRawData != NULL) - { - pMaterial->sizeInBytes = sizeof(drmtl_header); - pMaterial->bufferSizeInBytes = DRMTL_CHUNK_SIZE; - pMaterial->currentStage = DRMTL_STAGE_IDS; - pMaterial->currentChannelOffset = 0; - pMaterial->ownsRawData = 1; - - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - pHeader->magic = DRMTL_MAGIC_NUMBER; - pHeader->version = DRMTL_CURRENT_VERSION; - pHeader->identifierSizeInBytes = sizeof(drmtl_identifier); - pHeader->inputSizeInBytes = sizeof(drmtl_input); - pHeader->channelHeaderSizeInBytes = sizeof(drmtl_channel_header); - pHeader->instructionSizeInBytes = sizeof(drmtl_instruction); - pHeader->propertySizeInBytes = sizeof(drmtl_property); - pHeader->identifierCount = 0; - pHeader->privateInputCount = 0; - pHeader->publicInputCount = 0; - pHeader->channelCount = 0; - pHeader->propertyCount = 0; - pHeader->identifiersOffset = pMaterial->sizeInBytes; - pHeader->inputsOffset = pMaterial->sizeInBytes; - pHeader->channelsOffset = pMaterial->sizeInBytes; - pHeader->propertiesOffset = pMaterial->sizeInBytes; - - return 1; - } - } - - return 0; -} - -bool drmtl_initfromexisting(drmtl_material* pMaterial, const void* pRawData, unsigned int dataSizeInBytes) -{ - if (pMaterial != NULL) - { - if (pRawData != NULL && dataSizeInBytes >= sizeof(drmtl_header)) - { - if (((drmtl_header*)pMaterial->pRawData)->magic == DRMTL_MAGIC_NUMBER) - { - pMaterial->pRawData = (drmtl_uint8*)malloc(DRMTL_CHUNK_SIZE); - if (pMaterial->pRawData != NULL) - { - memcpy(pMaterial->pRawData, pRawData, dataSizeInBytes); - pMaterial->sizeInBytes = dataSizeInBytes; - pMaterial->bufferSizeInBytes = dataSizeInBytes; - pMaterial->currentStage = DRMTL_STAGE_COMPLETE; - pMaterial->currentChannelOffset = 0; - pMaterial->ownsRawData = 1; - - return 1; - } - } - } - } - - return 0; -} - -bool drmtl_initfromexisting_nocopy(drmtl_material* pMaterial, const void* pRawData, unsigned int dataSizeInBytes) -{ - if (pMaterial != NULL) - { - if (pRawData != NULL && dataSizeInBytes >= sizeof(drmtl_header)) - { - if (((const drmtl_header*)pRawData)->magic == DRMTL_MAGIC_NUMBER) - { - pMaterial->pRawData = (drmtl_uint8*)pRawData; - pMaterial->sizeInBytes = dataSizeInBytes; - pMaterial->bufferSizeInBytes = dataSizeInBytes; - pMaterial->currentStage = DRMTL_STAGE_COMPLETE; - pMaterial->currentChannelOffset = 0; - pMaterial->ownsRawData = 0; - - return 1; - } - } - } - - return 0; -} - -void drmtl_uninit(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - if (pMaterial->ownsRawData) - { - free(pMaterial->pRawData); - } - - pMaterial->pRawData = NULL; - } -} - - -drmtl_header* drmtl_getheader(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - return (drmtl_header*)pMaterial->pRawData; - } - - return NULL; -} - - -bool drmtl_appendidentifier(drmtl_material* pMaterial, drmtl_identifier identifier, unsigned int* indexOut) -{ - if (pMaterial != NULL) - { - if (pMaterial->currentStage <= DRMTL_STAGE_IDS) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - if (pMaterial->sizeInBytes + pHeader->identifierSizeInBytes > pMaterial->bufferSizeInBytes) - { - if (!_drmtl_inflate(pMaterial)) - { - // An error occured when trying to inflate the buffer. Might be out of memory. - return 0; - } - - pHeader = drmtl_getheader(pMaterial); - assert(pMaterial->sizeInBytes + pHeader->identifierSizeInBytes <= pMaterial->bufferSizeInBytes); - } - - - memcpy(pMaterial->pRawData + pHeader->inputsOffset, &identifier, pHeader->identifierSizeInBytes); - pMaterial->sizeInBytes += pHeader->identifierSizeInBytes; - - pHeader->identifierCount += 1; - pHeader->inputsOffset += pHeader->identifierSizeInBytes; - pHeader->channelsOffset += pHeader->identifierSizeInBytes; - pHeader->propertiesOffset += pHeader->identifierSizeInBytes; - - - if (indexOut != NULL) - { - *indexOut = pHeader->identifierCount - 1; - } - - return 1; - } - } - } - - return 0; -} - -bool drmtl_appendprivateinput(drmtl_material* pMaterial, drmtl_input input) -{ - if (pMaterial != NULL) - { - if (pMaterial->currentStage <= DRMTL_STAGE_PRIVATE_INPUTS) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - if (pMaterial->sizeInBytes + pHeader->inputSizeInBytes > pMaterial->bufferSizeInBytes) - { - if (!_drmtl_inflate(pMaterial)) - { - // An error occured when trying to inflate the buffer. Might be out of memory. - return 0; - } - - pHeader = drmtl_getheader(pMaterial); - assert(pMaterial->sizeInBytes + pHeader->inputSizeInBytes <= pMaterial->bufferSizeInBytes); - } - - - memcpy(pMaterial->pRawData + pHeader->channelsOffset, &input, pHeader->inputSizeInBytes); - pMaterial->sizeInBytes += pHeader->inputSizeInBytes; - - pHeader->privateInputCount += 1; - pHeader->channelsOffset += pHeader->inputSizeInBytes; - pHeader->propertiesOffset += pHeader->inputSizeInBytes; - - - pMaterial->currentStage = DRMTL_STAGE_PRIVATE_INPUTS; - return 1; - } - } - } - - return 0; -} - -bool drmtl_appendpublicinput(drmtl_material* pMaterial, drmtl_input input) -{ - if (pMaterial != NULL) - { - if (pMaterial->currentStage <= DRMTL_STAGE_PUBLIC_INPUTS) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - if (pMaterial->sizeInBytes + pHeader->inputSizeInBytes > pMaterial->bufferSizeInBytes) - { - if (!_drmtl_inflate(pMaterial)) - { - // An error occured when trying to inflate the buffer. Might be out of memory. - return 0; - } - - pHeader = drmtl_getheader(pMaterial); - assert(pMaterial->sizeInBytes + pHeader->inputSizeInBytes <= pMaterial->bufferSizeInBytes); - } - - - memcpy(pMaterial->pRawData + pHeader->channelsOffset, &input, pHeader->inputSizeInBytes); - pMaterial->sizeInBytes += pHeader->inputSizeInBytes; - - pHeader->publicInputCount += 1; - pHeader->channelsOffset += pHeader->inputSizeInBytes; - pHeader->propertiesOffset += pHeader->inputSizeInBytes; - - - pMaterial->currentStage = DRMTL_STAGE_PUBLIC_INPUTS; - return 1; - } - } - } - - return 0; -} - -bool drmtl_appendchannel(drmtl_material* pMaterial, drmtl_channel channel) -{ - if (pMaterial != NULL) - { - if (pMaterial->currentStage <= DRMTL_STAGE_CHANNELS) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - drmtl_channel_header channelHeader; - channelHeader.channel = channel; - channelHeader.instructionCount = 0; - - if (pMaterial->sizeInBytes + pHeader->channelHeaderSizeInBytes > pMaterial->bufferSizeInBytes) - { - if (!_drmtl_inflate(pMaterial)) - { - // An error occured when trying to inflate the buffer. Might be out of memory. - return 0; - } - - pHeader = drmtl_getheader(pMaterial); - assert(pMaterial->sizeInBytes + pHeader->channelHeaderSizeInBytes <= pMaterial->bufferSizeInBytes); - } - - - memcpy(pMaterial->pRawData + pHeader->propertiesOffset, &channelHeader, pHeader->channelHeaderSizeInBytes); - pMaterial->currentChannelOffset = pMaterial->sizeInBytes; - pMaterial->sizeInBytes += pHeader->channelHeaderSizeInBytes; - - pHeader->channelCount += 1; - pHeader->propertiesOffset += pHeader->channelHeaderSizeInBytes; - - - pMaterial->currentStage = DRMTL_STAGE_CHANNELS; - return 1; - } - } - } - - return 0; -} - -bool drmtl_appendinstruction(drmtl_material* pMaterial, drmtl_instruction instruction) -{ - if (pMaterial != NULL) - { - if (pMaterial->currentStage == DRMTL_STAGE_CHANNELS) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - if (pMaterial->sizeInBytes + pHeader->instructionSizeInBytes > pMaterial->bufferSizeInBytes) - { - if (!_drmtl_inflate(pMaterial)) - { - // An error occured when trying to inflate the buffer. Might be out of memory. - return 0; - } - - pHeader = drmtl_getheader(pMaterial); - assert(pMaterial->sizeInBytes + pHeader->instructionSizeInBytes <= pMaterial->bufferSizeInBytes); - } - - - memcpy(pMaterial->pRawData + pHeader->propertiesOffset, &instruction, pHeader->instructionSizeInBytes); - pMaterial->sizeInBytes += pHeader->instructionSizeInBytes; - - drmtl_channel_header* pChannelHeader = (drmtl_channel_header*)(pMaterial->pRawData + pMaterial->currentChannelOffset); - if (pChannelHeader != NULL) - { - pChannelHeader->instructionCount += 1; - } - - pHeader->propertiesOffset += pHeader->instructionSizeInBytes; - - - return 1; - } - } - } - - return 0; -} - -bool drmtl_appendproperty(drmtl_material* pMaterial, drmtl_property prop) -{ - if (pMaterial != NULL) - { - if (pMaterial->currentStage <= DRMTL_STAGE_CHANNELS) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - if (pMaterial->sizeInBytes + pHeader->propertySizeInBytes > pMaterial->bufferSizeInBytes) - { - if (!_drmtl_inflate(pMaterial)) - { - // An error occured when trying to inflate the buffer. Might be out of memory. - return 0; - } - - pHeader = drmtl_getheader(pMaterial); - assert(pMaterial->sizeInBytes + pHeader->propertySizeInBytes <= pMaterial->bufferSizeInBytes); - } - - - memcpy(pMaterial->pRawData + pMaterial->sizeInBytes, &prop, pHeader->propertySizeInBytes); - pMaterial->sizeInBytes += pHeader->propertySizeInBytes; - - pHeader->propertyCount += 1; - - - pMaterial->currentStage = DRMTL_STAGE_PROPERTIES; - return 1; - } - } - } - - return 0; -} - - -drmtl_channel_header* drmtl_getchannelheaderbyindex(drmtl_material* pMaterial, unsigned int channelIndex) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - if (channelIndex < pHeader->channelCount) - { - drmtl_uint8* pChannelHeader = pMaterial->pRawData + pHeader->channelsOffset; - for (unsigned int iChannel = 0; iChannel < channelIndex; ++iChannel) - { - pChannelHeader += sizeof(drmtl_channel_header) + (sizeof(drmtl_instruction) * ((drmtl_channel_header*)pChannelHeader)->instructionCount); - } - - return (drmtl_channel_header*)pChannelHeader; - } - } - - return NULL; -} - -drmtl_channel_header* drmtl_getchannelheaderbyname(drmtl_material* pMaterial, const char* channelName) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - drmtl_uint8* pChannelHeader = pMaterial->pRawData + pHeader->channelsOffset; - for (unsigned int iChannel = 0; iChannel < pHeader->channelCount; ++iChannel) - { - if (strcmp(((drmtl_channel_header*)pChannelHeader)->channel.name, channelName) == 0) - { - return (drmtl_channel_header*)pChannelHeader; - } - - pChannelHeader += sizeof(drmtl_channel_header) + (sizeof(drmtl_instruction) * ((drmtl_channel_header*)pChannelHeader)->instructionCount); - } - } - - return NULL; -} - -drmtl_identifier* drmtl_getidentifiers(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - return (drmtl_identifier*)(pMaterial->pRawData + pHeader->identifiersOffset); - } - - return NULL; -} - -drmtl_identifier* drmtl_getidentifier(drmtl_material* pMaterial, unsigned int index) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - if (index < pHeader->identifierCount) - { - drmtl_identifier* firstIdentifier = (drmtl_identifier*)(pMaterial->pRawData + pHeader->identifiersOffset); - return firstIdentifier + index; - } - } - - return NULL; -} - -unsigned int drmtl_getidentifiercount(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - return pHeader->identifierCount; - } - - return 0; -} - - -unsigned int drmtl_getinputcount(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - return pHeader->privateInputCount + pHeader->publicInputCount; - } - - return 0; -} - -drmtl_input* drmtl_getinputbyindex(drmtl_material* pMaterial, unsigned int index) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - if (index < (pHeader->privateInputCount + pHeader->publicInputCount)) - { - drmtl_input* firstInput = (drmtl_input*)(pMaterial->pRawData + pHeader->inputsOffset); - return firstInput + index; - } - } - - return NULL; -} - -unsigned int drmtl_getprivateinputcount(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - return pHeader->privateInputCount; - } - - return 0; -} - -drmtl_input* drmtl_getprivateinputbyindex(drmtl_material* pMaterial, unsigned int index) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - if (index < pHeader->privateInputCount) - { - drmtl_input* firstInput = (drmtl_input*)(pMaterial->pRawData + pHeader->inputsOffset); - return firstInput + index; - } - } - - return NULL; -} - -unsigned int drmtl_getpublicinputcount(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - return pHeader->publicInputCount; - } - - return 0; -} - -drmtl_input* drmtl_getpublicinputbyindex(drmtl_material* pMaterial, unsigned int index) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - if (index < pHeader->publicInputCount) - { - drmtl_input* firstInput = (drmtl_input*)(pMaterial->pRawData + pHeader->inputsOffset); - return firstInput + pHeader->privateInputCount + index; - } - } - - return NULL; -} - - -unsigned int drmtl_getpropertycount(drmtl_material* pMaterial) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - return pHeader->propertyCount; - } - - return 0; -} - -drmtl_property* drmtl_getpropertybyindex(drmtl_material* pMaterial, unsigned int index) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - if (index < pHeader->propertyCount) - { - drmtl_property* firstProperty = (drmtl_property*)(pMaterial->pRawData + pHeader->propertiesOffset); - return firstProperty + index; - } - } - - return NULL; -} - -drmtl_property* drmtl_getpropertybyname(drmtl_material* pMaterial, const char* name) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - assert(pHeader != NULL); - - for (unsigned int i = 0; i < pHeader->propertyCount; ++i) - { - drmtl_property* pProperty = ((drmtl_property*)(pMaterial->pRawData + pHeader->propertiesOffset)) + i; - assert(pProperty != NULL); - - if (strcmp(pProperty->name, name) == 0) - { - return pProperty; - } - } - } - - return NULL; -} - - -////////////////////////////////// -// Private low-level API. - -bool _drmtl_inflate(drmtl_material* pMaterial) -{ - assert(pMaterial != NULL); - - drmtl_uint8* pOldBuffer = pMaterial->pRawData; - drmtl_uint8* pNewBuffer = (drmtl_uint8*)malloc(pMaterial->bufferSizeInBytes + DRMTL_CHUNK_SIZE); - if (pNewBuffer != NULL) - { - memcpy(pNewBuffer, pOldBuffer, pMaterial->sizeInBytes); - pMaterial->pRawData = pNewBuffer; - pMaterial->bufferSizeInBytes += DRMTL_CHUNK_SIZE; - - free(pOldBuffer); - return 1; - } - - return 0; -} - - - -//////////////////////////////////////////////////////// -// Mid-Level APIs - -drmtl_identifier drmtl_identifier_float(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_float; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_float2(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_float2; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_float3(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_float3; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_float4(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_float4; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_int(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_int; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_int2(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_int2; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_int3(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_int3; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_int4(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_int4; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - -drmtl_identifier drmtl_identifier_tex2d(const char* name) -{ - drmtl_identifier identifier; - identifier.type = drmtl_type_tex2d; - drmtl_strcpy(identifier.name, DRMTL_MAX_IDENTIFIER_NAME, name); - - return identifier; -} - - -drmtl_input drmtl_input_float(unsigned int identifierIndex, float x) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.f1.x = x; - - return input; -} - -drmtl_input drmtl_input_float2(unsigned int identifierIndex, float x, float y) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.f2.x = x; - input.f2.y = y; - - return input; -} - -drmtl_input drmtl_input_float3(unsigned int identifierIndex, float x, float y, float z) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.f3.x = x; - input.f3.y = y; - input.f3.z = z; - - return input; -} - -drmtl_input drmtl_input_float4(unsigned int identifierIndex, float x, float y, float z, float w) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.f4.x = x; - input.f4.y = y; - input.f4.z = z; - input.f4.w = w; - - return input; -} - -drmtl_input drmtl_input_int(unsigned int identifierIndex, int x) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.i1.x = x; - - return input; -} - -drmtl_input drmtl_input_int2(unsigned int identifierIndex, int x, int y) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.i2.x = x; - input.i2.y = y; - - return input; -} - -drmtl_input drmtl_input_int3(unsigned int identifierIndex, int x, int y, int z) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.i3.x = x; - input.i3.y = y; - input.i3.z = z; - - return input; -} - -drmtl_input drmtl_input_int4(unsigned int identifierIndex, int x, int y, int z, int w) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - input.i4.x = x; - input.i4.y = y; - input.i4.z = z; - input.i4.w = w; - - return input; -} - -drmtl_input drmtl_input_tex(unsigned int identifierIndex, const char* path) -{ - drmtl_input input; - input.identifierIndex = identifierIndex; - drmtl_strcpy(input.path.value, DRMTL_MAX_INPUT_PATH, path); - - return input; -} - - -drmtl_channel drmtl_channel_float(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_float; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_float2(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_float2; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_float3(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_float3; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_float4(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_float4; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_int(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_int; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_int2(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_int2; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_int3(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_int3; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - -drmtl_channel drmtl_channel_int4(const char* name) -{ - drmtl_channel channel; - channel.type = drmtl_type_int4; - drmtl_strcpy(channel.name, DRMTL_MAX_CHANNEL_NAME, name); - - return channel; -} - - -drmtl_instruction drmtl_movf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf1; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mov.inputX.id = inputIdentifierIndex; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf1_c1(unsigned int outputIdentifierIndex, float x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf1; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputX.valuef = x; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf2; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mov.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mov.inputX.id = inputIdentifierIndex; - inst.mov.inputY.id = inputIdentifierIndex; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf2_c2(unsigned int outputIdentifierIndex, float x, float y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf2; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputX.valuef = x; - inst.mov.inputY.valuef = y; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf3; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mov.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mov.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.mov.inputX.id = inputIdentifierIndex; - inst.mov.inputY.id = inputIdentifierIndex; - inst.mov.inputZ.id = inputIdentifierIndex; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf3; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputX.valuef = x; - inst.mov.inputY.valuef = y; - inst.mov.inputZ.valuef = z; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf4; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mov.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mov.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.mov.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.mov.inputX.id = inputIdentifierIndex; - inst.mov.inputY.id = inputIdentifierIndex; - inst.mov.inputZ.id = inputIdentifierIndex; - inst.mov.inputW.id = inputIdentifierIndex; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_movf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_movf4; - inst.mov.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.mov.inputX.valuef = x; - inst.mov.inputY.valuef = y; - inst.mov.inputZ.valuef = z; - inst.mov.inputW.valuef = w; - inst.mov.output = outputIdentifierIndex; - - return inst; -} - - -drmtl_instruction drmtl_addf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf1; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.add.inputX.id = inputIdentifierIndex; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf1_c1(unsigned int outputIdentifierIndex, float x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf1; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputX.valuef = x; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf2; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.add.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.add.inputX.id = inputIdentifierIndex; - inst.add.inputY.id = inputIdentifierIndex; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf2_c2(unsigned int outputIdentifierIndex, float x, float y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf2; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputX.valuef = x; - inst.add.inputY.valuef = y; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf3; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.add.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.add.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.add.inputX.id = inputIdentifierIndex; - inst.add.inputY.id = inputIdentifierIndex; - inst.add.inputZ.id = inputIdentifierIndex; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf3; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputX.valuef = x; - inst.add.inputY.valuef = y; - inst.add.inputZ.valuef = z; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf4; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.add.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.add.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.add.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.add.inputX.id = inputIdentifierIndex; - inst.add.inputY.id = inputIdentifierIndex; - inst.add.inputZ.id = inputIdentifierIndex; - inst.add.inputW.id = inputIdentifierIndex; - inst.add.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_addf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_addf4; - inst.add.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.add.inputX.valuef = x; - inst.add.inputY.valuef = y; - inst.add.inputZ.valuef = z; - inst.add.inputW.valuef = w; - inst.add.output = outputIdentifierIndex; - - return inst; -} - - -drmtl_instruction drmtl_subf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf1; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.sub.inputX.id = inputIdentifierIndex; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf1_c1(unsigned int outputIdentifierIndex, float x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf1; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputX.valuef = x; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf2; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.sub.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.sub.inputX.id = inputIdentifierIndex; - inst.sub.inputY.id = inputIdentifierIndex; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf2_c2(unsigned int outputIdentifierIndex, float x, float y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf2; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputX.valuef = x; - inst.sub.inputY.valuef = y; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf3; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.sub.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.sub.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.sub.inputX.id = inputIdentifierIndex; - inst.sub.inputY.id = inputIdentifierIndex; - inst.sub.inputZ.id = inputIdentifierIndex; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf3; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputX.valuef = x; - inst.sub.inputY.valuef = y; - inst.sub.inputZ.valuef = z; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf4; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.sub.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.sub.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.sub.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.sub.inputX.id = inputIdentifierIndex; - inst.sub.inputY.id = inputIdentifierIndex; - inst.sub.inputZ.id = inputIdentifierIndex; - inst.sub.inputW.id = inputIdentifierIndex; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_subf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_subf4; - inst.sub.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.sub.inputX.valuef = x; - inst.sub.inputY.valuef = y; - inst.sub.inputZ.valuef = z; - inst.sub.inputW.valuef = w; - inst.sub.output = outputIdentifierIndex; - - return inst; -} - - -drmtl_instruction drmtl_mulf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf1; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf1_c1(unsigned int outputIdentifierIndex, float x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf1; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.valuef = x; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf2; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.inputY.id = inputIdentifierIndex; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf2_c2(unsigned int outputIdentifierIndex, float x, float y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf2; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.valuef = x; - inst.mul.inputY.valuef = y; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf3; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.inputY.id = inputIdentifierIndex; - inst.mul.inputZ.id = inputIdentifierIndex; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf3; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.valuef = x; - inst.mul.inputY.valuef = y; - inst.mul.inputZ.valuef = z; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.inputY.id = inputIdentifierIndex; - inst.mul.inputZ.id = inputIdentifierIndex; - inst.mul.inputW.id = inputIdentifierIndex; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.valuef = x; - inst.mul.inputY.valuef = y; - inst.mul.inputZ.valuef = z; - inst.mul.inputW.valuef = w; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_v3v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndexXYZ, unsigned int inputIdentifierIndexW) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_VARX; - inst.mul.inputX.id = inputIdentifierIndexXYZ; - inst.mul.inputY.id = inputIdentifierIndexXYZ; - inst.mul.inputZ.id = inputIdentifierIndexXYZ; - inst.mul.inputW.id = inputIdentifierIndexW; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_v3c1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.inputY.id = inputIdentifierIndex; - inst.mul.inputZ.id = inputIdentifierIndex; - inst.mul.inputW.valuef = w; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_v2c2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.inputY.id = inputIdentifierIndex; - inst.mul.inputZ.valuef = z; - inst.mul.inputW.valuef = w; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_v1c3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.mul.inputX.id = inputIdentifierIndex; - inst.mul.inputY.valuef = y; - inst.mul.inputZ.valuef = z; - inst.mul.inputW.valuef = w; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_mulf4_v1v1v1v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndexX, unsigned int inputIdentifierIndexY, unsigned int inputIdentifierIndexZ, unsigned int inputIdentifierIndexW) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_mulf4; - inst.mul.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.y = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.z = DRMTL_INPUT_DESC_VARX; - inst.mul.inputDesc.w = DRMTL_INPUT_DESC_VARX; - inst.mul.inputX.id = inputIdentifierIndexX; - inst.mul.inputY.id = inputIdentifierIndexY; - inst.mul.inputZ.id = inputIdentifierIndexZ; - inst.mul.inputW.id = inputIdentifierIndexW; - inst.mul.output = outputIdentifierIndex; - - return inst; -} - - -drmtl_instruction drmtl_divf1_v1(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf1; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.div.inputX.id = inputIdentifierIndex; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf1_c1(unsigned int outputIdentifierIndex, float x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf1; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputX.valuef = x; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf2_v2(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf2; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.div.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.div.inputX.id = inputIdentifierIndex; - inst.div.inputY.id = inputIdentifierIndex; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf2_c2(unsigned int outputIdentifierIndex, float x, float y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf2; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputX.valuef = x; - inst.div.inputY.valuef = y; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf3_v3(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf3; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.div.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.div.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.div.inputX.id = inputIdentifierIndex; - inst.div.inputY.id = inputIdentifierIndex; - inst.div.inputZ.id = inputIdentifierIndex; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf3_c3(unsigned int outputIdentifierIndex, float x, float y, float z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf3; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputX.valuef = x; - inst.div.inputY.valuef = y; - inst.div.inputZ.valuef = z; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf4_v4(unsigned int outputIdentifierIndex, unsigned int inputIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf4; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.div.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.div.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.div.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.div.inputX.id = inputIdentifierIndex; - inst.div.inputY.id = inputIdentifierIndex; - inst.div.inputZ.id = inputIdentifierIndex; - inst.div.inputW.id = inputIdentifierIndex; - inst.div.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_divf4_c4(unsigned int outputIdentifierIndex, float x, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_divf4; - inst.div.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.div.inputX.valuef = x; - inst.div.inputY.valuef = y; - inst.div.inputZ.valuef = z; - inst.div.inputW.valuef = w; - inst.div.output = outputIdentifierIndex; - - return inst; -} - - -drmtl_instruction drmtl_tex2(unsigned int outputIdentifierIndex, unsigned int textureIdentifierIndex, unsigned int texcoordIdentifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_tex2; - inst.tex.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.tex.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.tex.inputX.id = texcoordIdentifierIndex; - inst.tex.inputY.id = texcoordIdentifierIndex; - inst.tex.texture = textureIdentifierIndex; - inst.tex.output = outputIdentifierIndex; - - return inst; -} - -drmtl_instruction drmtl_var(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_var; - inst.var.identifierIndex = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_retf1(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf1; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputX.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_retf2(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf2; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.ret.inputX.id = identifierIndex; - inst.ret.inputY.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_retf3(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf3; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.ret.inputX.id = identifierIndex; - inst.ret.inputY.id = identifierIndex; - inst.ret.inputZ.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_retf4(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf4; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.ret.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.ret.inputX.id = identifierIndex; - inst.ret.inputY.id = identifierIndex; - inst.ret.inputZ.id = identifierIndex; - inst.ret.inputW.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_retf1_c1(float x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf1; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputX.valuef = x; - - return inst; -} - -drmtl_instruction drmtl_retf2_c2(float x, float y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf2; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputX.valuef = x; - inst.ret.inputY.valuef = y; - - return inst; -} - -drmtl_instruction drmtl_retf3_c3(float x, float y, float z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf3; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputX.valuef = x; - inst.ret.inputY.valuef = y; - inst.ret.inputZ.valuef = z; - - return inst; -} - -drmtl_instruction drmtl_retf4_c4(float x, float y, float z, float w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_retf4; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputDesc.w = DRMTL_INPUT_DESC_CONSTF; - inst.ret.inputX.valuef = x; - inst.ret.inputY.valuef = y; - inst.ret.inputZ.valuef = z; - inst.ret.inputW.valuef = w; - - return inst; -} - -drmtl_instruction drmtl_reti1(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti1; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputX.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_reti2(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti2; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.ret.inputX.id = identifierIndex; - inst.ret.inputY.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_reti3(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti3; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.ret.inputX.id = identifierIndex; - inst.ret.inputY.id = identifierIndex; - inst.ret.inputZ.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_reti4(unsigned int identifierIndex) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti4; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_VARX; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_VARY; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_VARZ; - inst.ret.inputDesc.w = DRMTL_INPUT_DESC_VARW; - inst.ret.inputX.id = identifierIndex; - inst.ret.inputY.id = identifierIndex; - inst.ret.inputZ.id = identifierIndex; - inst.ret.inputW.id = identifierIndex; - - return inst; -} - -drmtl_instruction drmtl_reti1_c1(int x) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti1; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputX.valuei = x; - - return inst; -} - -drmtl_instruction drmtl_reti2_c2(int x, int y) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti2; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputX.valuei = x; - inst.ret.inputY.valuei = y; - - return inst; -} - -drmtl_instruction drmtl_reti3_c3(int x, int y, int z) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti3; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputX.valuei = x; - inst.ret.inputY.valuei = y; - inst.ret.inputZ.valuei = z; - - return inst; -} - -drmtl_instruction drmtl_reti4_c4(int x, int y, int z, int w) -{ - drmtl_instruction inst; - inst.opcode = drmtl_opcode_reti4; - inst.ret.inputDesc.x = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputDesc.y = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputDesc.z = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputDesc.w = DRMTL_INPUT_DESC_CONSTI; - inst.ret.inputX.valuei = x; - inst.ret.inputY.valuei = y; - inst.ret.inputZ.valuei = z; - inst.ret.inputW.valuei = w; - - return inst; -} - - - -drmtl_property drmtl_property_float(const char* name, float x) -{ - drmtl_property prop; - prop.type = drmtl_type_float; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.f1.x = x; - - return prop; -} - -drmtl_property drmtl_property_float2(const char* name, float x, float y) -{ - drmtl_property prop; - prop.type = drmtl_type_float2; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.f2.x = x; - prop.f2.y = y; - - return prop; -} - -drmtl_property drmtl_property_float3(const char* name, float x, float y, float z) -{ - drmtl_property prop; - prop.type = drmtl_type_float3; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.f3.x = x; - prop.f3.y = y; - prop.f3.z = z; - - return prop; -} - -drmtl_property drmtl_property_float4(const char* name, float x, float y, float z, float w) -{ - drmtl_property prop; - prop.type = drmtl_type_float4; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.f4.x = x; - prop.f4.y = y; - prop.f4.z = z; - prop.f4.w = w; - - return prop; -} - -drmtl_property drmtl_property_int(const char* name, int x) -{ - drmtl_property prop; - prop.type = drmtl_type_int; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.i1.x = x; - - return prop; -} - -drmtl_property drmtl_property_int2(const char* name, int x, int y) -{ - drmtl_property prop; - prop.type = drmtl_type_int2; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.i2.x = x; - prop.i2.y = y; - - return prop; -} - -drmtl_property drmtl_property_int3(const char* name, int x, int y, int z) -{ - drmtl_property prop; - prop.type = drmtl_type_int3; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.i3.x = x; - prop.i3.y = y; - prop.i3.z = z; - - return prop; -} - -drmtl_property drmtl_property_int4(const char* name, int x, int y, int z, int w) -{ - drmtl_property prop; - prop.type = drmtl_type_int4; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.i4.x = x; - prop.i4.y = y; - prop.i4.z = z; - prop.i4.w = w; - - return prop; -} - -drmtl_property drmtl_property_bool(const char* name, bool value) -{ - drmtl_property prop; - prop.type = drmtl_type_bool; - drmtl_strcpy(prop.name, DRMTL_MAX_PROPERTY_NAME, name); - prop.b1.x = value; - - return prop; -} - - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Compilers -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef DRMTL_NO_MTL_COMPILER -typedef struct -{ - /// A pointer to the buffer containing the Wavefront MTL data. - const char* pData; - - /// The size of the data buffer size. - unsigned int dataSizeInBytes; - - /// A pointer to the next bytes to read. - const char* pDataCur; - - /// A pointer to the end of the buffer. - const char* pDataEnd; - - - /// The diffuse colour. - float diffuse[3]; - - /// The diffuse map. - char diffuseMap[DRMTL_MAX_INPUT_PATH]; - - - /// The specular colour. - float specular[3]; - - /// The specular map. - char specularMap[DRMTL_MAX_INPUT_PATH]; - - - /// The specular exponent. - float specularExponent; - - /// The specular exponent map. - char specularExponentMap[DRMTL_MAX_INPUT_PATH]; - - - /// The alpha transparency value. - float alpha; - - /// The alpha transparency map. - char alphaMap[DRMTL_MAX_INPUT_PATH]; - - -} drmtl_wavefront; - -bool drmtl_wavefront_is_whitespace(char c) -{ - return c == ' ' || c == '\t'; -} - -bool drmtl_wavefront_is_valid_digit(char c) -{ - return c >= '0' && c <= '9'; -} - -bool drmtl_wavefront_atof(const char* str, const char* strEnd, const char** strEndOut, float* valueOut) -{ - // Skip leading whitespace. - while (str < strEnd && drmtl_wavefront_is_whitespace(*str)) - { - str += 1; - } - - - // Check that we have a string after moving the whitespace. - if (str < strEnd) - { - float sign = 1.0f; - float value = 0.0f; - - // Sign. - if (*str == '-') - { - sign = -1.0f; - str += 1; - } - else if (*str == '+') - { - sign = 1.0f; - str += 1; - } - - - // Digits before the decimal point. - while (str < strEnd && drmtl_wavefront_is_valid_digit(*str)) - { - value = value * 10.0f + (*str - '0'); - - str += 1; - } - - // Digits after the decimal point. - if (*str == '.') - { - float pow10 = 10.0f; - - str += 1; - while (str < strEnd && drmtl_wavefront_is_valid_digit(*str)) - { - value += (*str - '0') / pow10; - pow10 *= 10.0f; - - str += 1; - } - } - - - if (strEndOut != NULL) - { - *strEndOut = str; - } - - if (valueOut != NULL) - { - *valueOut = sign * value; - } - - return 1; - } - else - { - // Empty string. Leave output untouched and return 0. - return 0; - } -} - -bool drmtl_wavefront_atof_3(const char* str, const char* strEnd, const char** strEndOut, float valueOut[3]) -{ - float value[3]; - if (drmtl_wavefront_atof(str, strEnd, &str, &value[0])) - { - value[1] = value[0]; - value[2] = value[0]; - - if (drmtl_wavefront_atof(str, strEnd, &str, &value[1])) - { - // We got two numbers which means we must have the third for this to be successful. - if (!drmtl_wavefront_atof(str, strEnd, strEndOut, &value[2])) - { - // Failed to get the third number. We only found 2 which is not valid. Error. - return 0; - } - } - - - valueOut[0] = value[0]; - valueOut[1] = value[1]; - valueOut[2] = value[2]; - - return 1; - } - - return 0; -} - -const char* drmtl_wavefront_find_end_of_line(const char* pDataCur, const char* pDataEnd) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - while (pDataCur < pDataEnd) - { - if (pDataCur[0] == '\n') - { - return pDataCur; - } - else - { - if (pDataCur + 1 < pDataEnd) - { - if (pDataCur[0] == '\r' && pDataCur[1] == '\n') - { - return pDataCur; - } - } - } - - pDataCur += 1; - } - - // If we get here it means we hit the end of the file before find a new-line character. - return pDataEnd; -} - -const char* drmtl_wavefront_find_next_line(const char* pDataCur, const char* pDataEnd) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - pDataCur = drmtl_wavefront_find_end_of_line(pDataCur, pDataEnd); - if (pDataCur != NULL) - { - if (pDataCur < pDataEnd) - { - if (pDataCur[0] == '\n') - { - return pDataCur + 1; - } - else - { - if (pDataCur + 1 < pDataEnd) - { - if (pDataCur[0] == '\r' && pDataCur[1] == '\n') - { - return pDataCur + 2; - } - } - } - } - } - - return NULL; -} - -const char* drmtl_wavefront_find_next_newmtl(const char* pDataCur, const char* pDataEnd) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - while (pDataCur + 7 < pDataEnd) // +7 for "newmtl" + a whitespace character. - { - if (pDataCur[0] == 'n' && pDataCur[1] == 'e' && pDataCur[2] == 'w' && pDataCur[3] == 'm' && pDataCur[4] == 't' && pDataCur[5] == 'l') - { - // We found "newmtl", however the next line must be whitespace. - if (drmtl_wavefront_is_whitespace(pDataCur[6])) - { - // We found it. - return pDataCur; - } - } - - - const char* nextLineStart = drmtl_wavefront_find_next_line(pDataCur, pDataEnd); - if (nextLineStart != NULL) - { - pDataCur = nextLineStart; - } - else - { - // Reached the end before finding "newmtl". Return null. - return NULL; - } - } - - return NULL; -} - -const char* drmtl_wavefront_find_next_nonwhitespace(const char* pDataCur, const char* pDataEnd) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - while (pDataCur < pDataEnd) - { - if (!drmtl_wavefront_is_whitespace(pDataCur[0])) - { - return pDataCur; - } - - pDataCur += 1; - } - - return NULL; -} - - -bool drmtl_wavefront_parse_K(const char* pDataCur, const char* pDataEnd, float valueOut[3]) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - return drmtl_wavefront_atof_3(pDataCur, pDataEnd, &pDataEnd, valueOut); -} - -bool drmtl_wavefront_parse_N(const char* pDataCur, const char* pDataEnd, float* valueOut) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - return drmtl_wavefront_atof(pDataCur, pDataEnd, &pDataEnd, valueOut); -} - -bool drmtl_wavefront_parse_map(const char* pDataCur, const char* pDataEnd, char* pathOut, unsigned int pathSizeInBytes) -{ - assert(pDataCur != NULL); - assert(pDataEnd != NULL); - - // For now we're not supporting options, however support for that will be added later. - - const char* pPathStart = drmtl_wavefront_find_next_nonwhitespace(pDataCur, pDataEnd); - if (pPathStart != NULL) - { - if (pPathStart < pDataEnd) - { - if (pPathStart[0] != '#') - { - // Find the last non-whitespace, making sure we don't include comments. - pDataCur = pPathStart; - const char* pPathEnd = pDataCur; - while (pDataCur < pDataEnd && pDataCur[0] != '#') - { - if (!drmtl_wavefront_is_whitespace(pDataCur[0])) - { - pPathEnd = pDataCur + 1; - } - - pDataCur += 1; - } - - assert(pPathStart < pPathEnd); - - ptrdiff_t pathLength = pPathEnd - pPathStart; - if ((size_t)pathLength + 1 < pathSizeInBytes) - { - memcpy(pathOut, pPathStart, (size_t)pathLength); - pathOut[pathLength] = '\0'; - - return 1; - } - } - } - } - - return 0; -} - - -bool drmtl_wavefront_seek_to_next_line(drmtl_wavefront* pWavefront) -{ - assert(pWavefront != NULL); - - const char* lineStart = drmtl_wavefront_find_next_line(pWavefront->pDataCur, pWavefront->pDataEnd); - if (lineStart != NULL) - { - pWavefront->pDataCur = lineStart; - return 1; - } - - return 0; -} - -bool drmtl_wavefront_seek_to_newmtl(drmtl_wavefront* pWavefront) -{ - assert(pWavefront != NULL); - - const char* usemtl = drmtl_wavefront_find_next_newmtl(pWavefront->pDataCur, pWavefront->pDataEnd); - if (usemtl != NULL) - { - pWavefront->pDataCur = usemtl; - return 1; - } - - return 0; -} - -bool drmtl_wavefront_parse(drmtl_wavefront* pWavefront) -{ - assert(pWavefront != NULL); - - if (drmtl_wavefront_seek_to_newmtl(pWavefront) && drmtl_wavefront_seek_to_next_line(pWavefront)) - { - // Set the end of the material to the start of the second usemtl statement, if it exists. - const char* usemtl2 = drmtl_wavefront_find_next_newmtl(pWavefront->pDataCur, pWavefront->pDataEnd); - if (usemtl2 != NULL) - { - pWavefront->pDataEnd = usemtl2; - } - - - while (pWavefront->pDataCur < pWavefront->pDataEnd) - { - const char* lineCur = pWavefront->pDataCur; - const char* lineEnd = drmtl_wavefront_find_end_of_line(lineCur, pWavefront->pDataEnd); - - lineCur = drmtl_wavefront_find_next_nonwhitespace(lineCur, lineEnd); - if (lineCur != NULL && (lineCur + 2 < lineEnd)) - { - if (lineCur[0] == 'K' && lineCur[1] == 'd' && drmtl_wavefront_is_whitespace(lineCur[2])) // Diffuse colour - { - lineCur += 3; - drmtl_wavefront_parse_K(lineCur, lineEnd, pWavefront->diffuse); - } - else if (lineCur[0] == 'K' && lineCur[1] == 's' && drmtl_wavefront_is_whitespace(lineCur[2])) // Specular colour - { - lineCur += 3; - drmtl_wavefront_parse_K(lineCur, lineEnd, pWavefront->specular); - } - else if (lineCur[0] == 'N' && lineCur[1] == 's' && drmtl_wavefront_is_whitespace(lineCur[2])) // Specular exponent - { - lineCur += 3; - drmtl_wavefront_parse_N(lineCur, lineEnd, &pWavefront->specularExponent); - } - else if (lineCur[0] == 'd' && drmtl_wavefront_is_whitespace(lineCur[1])) // Opacity/Alpha - { - lineCur += 2; - drmtl_wavefront_parse_N(lineCur, lineEnd, &pWavefront->alpha); - } - else - { - // Check for maps. - if (lineCur + 6 < lineEnd) - { - if (lineCur[0] == 'm' && lineCur[1] == 'a' && lineCur[2] == 'p' && lineCur[3] == '_') - { - if (lineCur[4] == 'K' && lineCur[5] == 'd' && drmtl_wavefront_is_whitespace(lineCur[6])) // Diffuse map - { - lineCur += 7; - drmtl_wavefront_parse_map(lineCur, lineEnd, pWavefront->diffuseMap, DRMTL_MAX_INPUT_PATH); - } - else if (lineCur[4] == 'K' && lineCur[5] == 's' && drmtl_wavefront_is_whitespace(lineCur[6])) // Specular map - { - lineCur += 7; - drmtl_wavefront_parse_map(lineCur, lineEnd, pWavefront->specularMap, DRMTL_MAX_INPUT_PATH); - } - else if (lineCur[4] == 'N' && lineCur[5] == 's' && drmtl_wavefront_is_whitespace(lineCur[6])) // Specular exponent map - { - lineCur += 7; - drmtl_wavefront_parse_map(lineCur, lineEnd, pWavefront->specularExponentMap, DRMTL_MAX_INPUT_PATH); - } - else if (lineCur[4] == 'd' && drmtl_wavefront_is_whitespace(lineCur[5])) // Opacity/Alpha map - { - lineCur += 6; - drmtl_wavefront_parse_map(lineCur, lineEnd, pWavefront->alphaMap, DRMTL_MAX_INPUT_PATH); - } - } - } - } - } - - - // Move to the end of the line. - pWavefront->pDataCur = lineEnd; - - // Move to the start of the next line. If this fails it probably means we've reached the end of the data so we just break from the loop - if (!drmtl_wavefront_seek_to_next_line(pWavefront)) - { - break; - } - } - - - return 1; - } - - return 0; -} - -bool drmtl_wavefront_compile(drmtl_material* pMaterial, drmtl_wavefront* pWavefront, const char* texcoordInputName) -{ - assert(pMaterial != NULL); - assert(pWavefront != NULL); - - unsigned int texCoordID; // Private input for texture coordinates. - unsigned int diffuseID; - unsigned int specularID; - unsigned int specularExponentID; - unsigned int alphaID; - unsigned int diffuseMapID = (unsigned int)-1; - unsigned int specularMapID = (unsigned int)-1; - unsigned int specularExponentMapID = (unsigned int)-1; - unsigned int alphaMapID = (unsigned int)-1; - unsigned int diffuseResultID = (unsigned int)-1; - unsigned int specularResultID = (unsigned int)-1; - unsigned int specularExponentResultID = (unsigned int)-1; - unsigned int alphaResultID = (unsigned int)-1; - - - // Identifiers. - drmtl_appendidentifier(pMaterial, drmtl_identifier_float2(texcoordInputName), &texCoordID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float4("DiffuseColor"), &diffuseID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float3("SpecularColor"), &specularID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float("SpecularExponent"), &specularExponentID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float("Alpha"), &alphaID); - - if (pWavefront->diffuseMap[0] != '\0') { - drmtl_appendidentifier(pMaterial, drmtl_identifier_tex2d("DiffuseMap"), &diffuseMapID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float4("DiffuseResult"), &diffuseResultID); - } - if (pWavefront->specularMap[0] != '\0') { - drmtl_appendidentifier(pMaterial, drmtl_identifier_tex2d("SpecularMap"), &specularMapID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float4("SpecularResult"), &specularResultID); - } - if (pWavefront->specularExponentMap[0] != '\0') { - drmtl_appendidentifier(pMaterial, drmtl_identifier_tex2d("SpecularExponentMap"), &specularExponentMapID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float4("SpecularExponentResult"), &specularExponentResultID); - } - if (pWavefront->alphaMap[0] != '\0') { - drmtl_appendidentifier(pMaterial, drmtl_identifier_tex2d("AlphaMap"), &alphaMapID); - drmtl_appendidentifier(pMaterial, drmtl_identifier_float4("AlphaResult"), &alphaResultID); - } - - - // Inputs. - drmtl_appendprivateinput(pMaterial, drmtl_input_float2(texCoordID, 0, 0)); - drmtl_appendpublicinput(pMaterial, drmtl_input_float4(diffuseID, pWavefront->diffuse[0], pWavefront->diffuse[1], pWavefront->diffuse[2], 1.0f)); - drmtl_appendpublicinput(pMaterial, drmtl_input_float3(specularID, pWavefront->specular[0], pWavefront->specular[1], pWavefront->specular[2])); - drmtl_appendpublicinput(pMaterial, drmtl_input_float(specularExponentID, pWavefront->specularExponent)); - drmtl_appendpublicinput(pMaterial, drmtl_input_float(alphaID, pWavefront->alpha)); - - if (pWavefront->diffuseMap[0] != '\0') { - drmtl_appendpublicinput(pMaterial, drmtl_input_tex(diffuseMapID, pWavefront->diffuseMap)); - } - if (pWavefront->specularMap[0] != '\0') { - drmtl_appendpublicinput(pMaterial, drmtl_input_tex(specularMapID, pWavefront->specularMap)); - } - if (pWavefront->specularExponentMap[0] != '\0') { - drmtl_appendpublicinput(pMaterial, drmtl_input_tex(specularExponentMapID, pWavefront->specularExponentMap)); - } - if (pWavefront->alphaMap[0] != '\0') { - drmtl_appendpublicinput(pMaterial, drmtl_input_tex(alphaMapID, pWavefront->alphaMap)); - } - - - // Channels. - drmtl_appendchannel(pMaterial, drmtl_channel_float4("DiffuseChannel")); - if (pWavefront->diffuseMap[0] != '\0') { - drmtl_appendinstruction(pMaterial, drmtl_var(diffuseResultID)); - drmtl_appendinstruction(pMaterial, drmtl_tex2(diffuseResultID, diffuseMapID, texCoordID)); - drmtl_appendinstruction(pMaterial, drmtl_mulf4_v3c1(diffuseResultID, diffuseID, 1.0f)); - drmtl_appendinstruction(pMaterial, drmtl_retf4(diffuseResultID)); - } else { - drmtl_appendinstruction(pMaterial, drmtl_retf4(diffuseID)); - } - - drmtl_appendchannel(pMaterial, drmtl_channel_float3("SpecularChannel")); - if (pWavefront->specularMap[0] != '\0') { - drmtl_appendinstruction(pMaterial, drmtl_var(specularResultID)); - drmtl_appendinstruction(pMaterial, drmtl_tex2(specularResultID, specularMapID, texCoordID)); - drmtl_appendinstruction(pMaterial, drmtl_mulf4_v3c1(specularResultID, specularID, 1.0f)); - drmtl_appendinstruction(pMaterial, drmtl_retf3(specularResultID)); - } else { - drmtl_appendinstruction(pMaterial, drmtl_retf3(specularID)); - } - - drmtl_appendchannel(pMaterial, drmtl_channel_float("SpecularExponentChannel")); - if (pWavefront->specularExponentMap[0] != '\0') { - drmtl_appendinstruction(pMaterial, drmtl_var(specularExponentResultID)); - drmtl_appendinstruction(pMaterial, drmtl_tex2(specularResultID, specularMapID, texCoordID)); - drmtl_appendinstruction(pMaterial, drmtl_mulf4_v1c3(specularResultID, specularID, 1.0f, 1.0f, 1.0f)); - drmtl_appendinstruction(pMaterial, drmtl_retf1(specularResultID)); - } else { - drmtl_appendinstruction(pMaterial, drmtl_retf1(specularExponentID)); - } - - drmtl_appendchannel(pMaterial, drmtl_channel_float("AlphaChannel")); - if (pWavefront->alphaMap[0] != '\0') { - drmtl_appendinstruction(pMaterial, drmtl_var(alphaResultID)); - drmtl_appendinstruction(pMaterial, drmtl_tex2(alphaResultID, alphaMapID, texCoordID)); - drmtl_appendinstruction(pMaterial, drmtl_mulf4_v1c3(alphaResultID, alphaID, 1.0f, 1.0f, 1.0f)); - drmtl_appendinstruction(pMaterial, drmtl_retf1(alphaResultID)); - } else { - drmtl_appendinstruction(pMaterial, drmtl_retf1(alphaID)); - } - - - - // Properties. - if (pWavefront->alphaMap[0] != '\0' || pWavefront->alpha < 1) - { - drmtl_appendproperty(pMaterial, drmtl_property_bool("IsTransparent", 1)); - } - - return 1; -} - - -bool drmtl_compile_wavefront_mtl(drmtl_material* pMaterial, const char* mtlData, size_t mtlDataSizeInBytes, const char* texcoordInputName) -{ - if (pMaterial != NULL && mtlData != NULL && mtlDataSizeInBytes > 0) - { - if (drmtl_init(pMaterial)) - { - drmtl_wavefront wavefront; - wavefront.pData = mtlData; - wavefront.dataSizeInBytes = mtlDataSizeInBytes; - wavefront.pDataCur = wavefront.pData; - wavefront.pDataEnd = wavefront.pData + wavefront.dataSizeInBytes; - wavefront.diffuse[0] = 1; wavefront.diffuse[1] = 1; wavefront.diffuse[2] = 1; - wavefront.diffuseMap[0] = '\0'; - wavefront.specular[0] = 1; wavefront.specular[1] = 1; wavefront.specular[2] = 1; - wavefront.specularMap[0] = '\0'; - wavefront.specularExponent = 10; - wavefront.specularExponentMap[0] = '\0'; - wavefront.alpha = 1; - wavefront.alphaMap[0] = '\0'; - - if (drmtl_wavefront_parse(&wavefront)) - { - if (drmtl_wavefront_compile(pMaterial, &wavefront, texcoordInputName)) - { - return 1; - } - else - { - // Failed to compile. - drmtl_uninit(pMaterial); - } - } - else - { - // Failed to parse the file. - drmtl_uninit(pMaterial); - } - } - } - - return 0; -} -#endif - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// Code Generators -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef DRMTL_NO_GLSL_CODEGEN -#include - -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wswitch-enum" - #pragma GCC diagnostic ignored "-Wcovered-switch-default" - #pragma GCC diagnostic ignored "-Wused-but-marked-unused" // This ie emitted for snprintf() for some reason. Need to investigate... -#endif - -typedef struct -{ - /// The output buffer. Can be null, in which case nothing is written. - char* pBufferOut; - - /// The size of the output buffer. - unsigned int bufferOutSizeInBytes; - - /// The current length of the string copied to the output buffer. - unsigned int runningLength; - - - /// A pointer to the material that is being used as the source of the code generation. - drmtl_material* pMaterial; - - /// A pointer to the buffer containing the material's identifiers. - drmtl_identifier* pIdentifiers; - - /// The number of identifiers. - unsigned int identifierCount; - - - /// The current indentation level, in spaces. - unsigned int indentationLevel; - -} drmtl_codegen_glsl; - -bool drmtl_codegen_glsl_write(drmtl_codegen_glsl* pCodegen, const char* src) -{ - assert(pCodegen != NULL); - assert(src != NULL); - - if (pCodegen->pBufferOut != NULL) - { - unsigned int dstSizeInBytes = (pCodegen->bufferOutSizeInBytes - pCodegen->runningLength); - while (dstSizeInBytes > 0 && src[0] != '\0') - { - pCodegen->pBufferOut[pCodegen->runningLength + 0] = src[0]; - - pCodegen->runningLength += 1; - src += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes > 0) - { - // There's enough room for the null terminator which means there was enough room in the buffer. All good. - pCodegen->pBufferOut[pCodegen->runningLength] = '\0'; - return 1; - } - else - { - // There's not enough room for the null terminator which means there was NOT enough room in the buffer. Error. - return 0; - } - } - else - { - // We're just measuring. - pCodegen->runningLength += (unsigned int)strlen(src); - return 1; - } -} - -bool drmtl_codegen_glsl_write_float(drmtl_codegen_glsl* pCodegen, float src) -{ - assert(pCodegen != NULL); - - char str[32]; - if (snprintf(str, 32, "%f", src) > 0) - { - return drmtl_codegen_glsl_write(pCodegen, str); - } - else - { - return 0; - } -} - -bool drmtl_codegen_glsl_write_int(drmtl_codegen_glsl* pCodegen, int src) -{ - assert(pCodegen != NULL); - - char str[32]; - if (snprintf(str, 32, "%d", src) > 0) - { - return drmtl_codegen_glsl_write(pCodegen, str); - } - else - { - return 0; - } -} - -bool drmtl_codegen_glsl_write_indentation(drmtl_codegen_glsl* pCodegen) -{ - assert(pCodegen != NULL); - - for (unsigned int i = 0; i < pCodegen->indentationLevel; ++i) - { - drmtl_codegen_glsl_write(pCodegen, " "); - } - - return 1; -} - -bool drmtl_codegen_glsl_write_type(drmtl_codegen_glsl* pCodegen, drmtl_type type) -{ - assert(pCodegen != NULL); - - switch (type) - { - case drmtl_type_float: - { - if (!drmtl_codegen_glsl_write(pCodegen, "float")) - { - return 0; - } - - break; - } - case drmtl_type_float2: - { - if (!drmtl_codegen_glsl_write(pCodegen, "vec2")) - { - return 0; - } - - break; - } - case drmtl_type_float3: - { - if (!drmtl_codegen_glsl_write(pCodegen, "vec3")) - { - return 0; - } - - break; - } - case drmtl_type_float4: - { - if (!drmtl_codegen_glsl_write(pCodegen, "vec4")) - { - return 0; - } - - break; - } - - case drmtl_type_int: - { - if (!drmtl_codegen_glsl_write(pCodegen, "int")) - { - return 0; - } - - break; - } - case drmtl_type_int2: - { - if (!drmtl_codegen_glsl_write(pCodegen, "ivec2")) - { - return 0; - } - - break; - } - case drmtl_type_int3: - { - if (!drmtl_codegen_glsl_write(pCodegen, "ivec3")) - { - return 0; - } - - break; - } - case drmtl_type_int4: - { - if (!drmtl_codegen_glsl_write(pCodegen, "ivec4")) - { - return 0; - } - - break; - } - - case drmtl_type_tex1d: - { - if (!drmtl_codegen_glsl_write(pCodegen, "sampler1D")) - { - return 0; - } - - break; - } - case drmtl_type_tex2d: - { - if (!drmtl_codegen_glsl_write(pCodegen, "sampler2D")) - { - return 0; - } - - break; - } - case drmtl_type_tex3d: - { - if (!drmtl_codegen_glsl_write(pCodegen, "sampler3D")) - { - return 0; - } - - break; - } - case drmtl_type_texcube: - { - if (!drmtl_codegen_glsl_write(pCodegen, "samplerCube")) - { - return 0; - } - - break; - } - - default: - { - // Unsupported return type. - return 0; - } - } - - return 1; -} - -bool drmtl_codegen_glsl_write_instruction_input_scalar(drmtl_codegen_glsl* pCodegen, unsigned char descriptor, drmtl_instruction_input* pInput) -{ - assert(pCodegen != NULL); - assert(pInput != NULL); - - if (descriptor == DRMTL_INPUT_DESC_CONSTF) - { - // It's a constant float. - return drmtl_codegen_glsl_write_float(pCodegen, pInput->valuef); - } - else if (descriptor == DRMTL_INPUT_DESC_CONSTI) - { - // It's a constant int. - return drmtl_codegen_glsl_write_int(pCodegen, pInput->valuei); - } - else - { - // It's a variable. - if (pInput->id < pCodegen->identifierCount) - { - drmtl_identifier* pIdentifier = pCodegen->pIdentifiers + pInput->id; - assert(pIdentifier != NULL); - - if (pIdentifier->type == drmtl_type_float) - { - // The input variable is a float, so we don't want to use any selectors. - return drmtl_codegen_glsl_write(pCodegen, pIdentifier->name); - } - else - { - if (drmtl_codegen_glsl_write(pCodegen, pIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, ".")) - { - switch (descriptor) - { - case 0: return drmtl_codegen_glsl_write(pCodegen, "x"); - case 1: return drmtl_codegen_glsl_write(pCodegen, "y"); - case 2: return drmtl_codegen_glsl_write(pCodegen, "z"); - case 3: return drmtl_codegen_glsl_write(pCodegen, "w"); - default: return 0; - } - } - } - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_input_initializer(drmtl_codegen_glsl* pCodegen, drmtl_type type, drmtl_instruction_input_descriptor inputDesc, drmtl_instruction_input* pInputs) -{ - assert(pCodegen != NULL); - assert(pInputs != NULL); - - switch (type) - { - case drmtl_type_float: - { - return drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0); - } - - case drmtl_type_float2: - { - if (drmtl_codegen_glsl_write(pCodegen, "vec2(")) - { - if (drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.y, pInputs + 1)) - { - return drmtl_codegen_glsl_write(pCodegen, ")"); - } - } - - break; - } - - case drmtl_type_float3: - { - if (drmtl_codegen_glsl_write(pCodegen, "vec3(")) - { - if (drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.y, pInputs + 1) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.z, pInputs + 2)) - { - return drmtl_codegen_glsl_write(pCodegen, ")"); - } - } - - break; - } - - case drmtl_type_float4: - { - if (drmtl_codegen_glsl_write(pCodegen, "vec4(")) - { - if (drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.y, pInputs + 1) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.z, pInputs + 2) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.w, pInputs + 3)) - { - return drmtl_codegen_glsl_write(pCodegen, ")"); - } - } - - break; - } - - - case drmtl_type_int: - { - return drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0); - } - - case drmtl_type_int2: - { - if (drmtl_codegen_glsl_write(pCodegen, "ivec2(")) - { - if (drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.y, pInputs + 1)) - { - return drmtl_codegen_glsl_write(pCodegen, ")"); - } - } - - break; - } - - case drmtl_type_int3: - { - if (drmtl_codegen_glsl_write(pCodegen, "ivec3(")) - { - if (drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.y, pInputs + 1) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.z, pInputs + 2)) - { - return drmtl_codegen_glsl_write(pCodegen, ")"); - } - } - - break; - } - - case drmtl_type_int4: - { - if (drmtl_codegen_glsl_write(pCodegen, "ivec4(")) - { - if (drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.x, pInputs + 0) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.y, pInputs + 1) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.z, pInputs + 2) && drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_scalar(pCodegen, inputDesc.w, pInputs + 3)) - { - return drmtl_codegen_glsl_write(pCodegen, ")"); - } - } - - break; - } - - - default: - { - // Unsupported return type. - return 0; - } - } - - return 0; -} - - -bool drmtl_codegen_glsl_write_instruction_mov(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->mov.output < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->mov.output; - assert(pOutputIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " = ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_movf1: type = drmtl_type_float; break; - case drmtl_opcode_movf2: type = drmtl_type_float2; break; - case drmtl_opcode_movf3: type = drmtl_type_float3; break; - case drmtl_opcode_movf4: type = drmtl_type_float4; break; - case drmtl_opcode_movi1: type = drmtl_type_int; break; - case drmtl_opcode_movi2: type = drmtl_type_int2; break; - case drmtl_opcode_movi3: type = drmtl_type_int3; break; - case drmtl_opcode_movi4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->mov.inputDesc, &pInstruction->mov.inputX) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_add(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->add.output < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->add.output; - assert(pOutputIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " += ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_addf1: type = drmtl_type_float; break; - case drmtl_opcode_addf2: type = drmtl_type_float2; break; - case drmtl_opcode_addf3: type = drmtl_type_float3; break; - case drmtl_opcode_addf4: type = drmtl_type_float4; break; - case drmtl_opcode_addi1: type = drmtl_type_int; break; - case drmtl_opcode_addi2: type = drmtl_type_int2; break; - case drmtl_opcode_addi3: type = drmtl_type_int3; break; - case drmtl_opcode_addi4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->add.inputDesc, &pInstruction->add.inputX) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_sub(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->add.output < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->sub.output; - assert(pOutputIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " -= ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_subf1: type = drmtl_type_float; break; - case drmtl_opcode_subf2: type = drmtl_type_float2; break; - case drmtl_opcode_subf3: type = drmtl_type_float3; break; - case drmtl_opcode_subf4: type = drmtl_type_float4; break; - case drmtl_opcode_subi1: type = drmtl_type_int; break; - case drmtl_opcode_subi2: type = drmtl_type_int2; break; - case drmtl_opcode_subi3: type = drmtl_type_int3; break; - case drmtl_opcode_subi4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->sub.inputDesc, &pInstruction->sub.inputX) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_mul(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->mul.output < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->mul.output; - assert(pOutputIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " *= ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_mulf1: type = drmtl_type_float; break; - case drmtl_opcode_mulf2: type = drmtl_type_float2; break; - case drmtl_opcode_mulf3: type = drmtl_type_float3; break; - case drmtl_opcode_mulf4: type = drmtl_type_float4; break; - case drmtl_opcode_muli1: type = drmtl_type_int; break; - case drmtl_opcode_muli2: type = drmtl_type_int2; break; - case drmtl_opcode_muli3: type = drmtl_type_int3; break; - case drmtl_opcode_muli4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->mul.inputDesc, &pInstruction->mul.inputX) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_div(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->div.output < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->div.output; - assert(pOutputIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " = ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_divf1: type = drmtl_type_float; break; - case drmtl_opcode_divf2: type = drmtl_type_float2; break; - case drmtl_opcode_divf3: type = drmtl_type_float3; break; - case drmtl_opcode_divf4: type = drmtl_type_float4; break; - case drmtl_opcode_divi1: type = drmtl_type_int; break; - case drmtl_opcode_divi2: type = drmtl_type_int2; break; - case drmtl_opcode_divi3: type = drmtl_type_int3; break; - case drmtl_opcode_divi4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->div.inputDesc, &pInstruction->div.inputX) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_pow(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->pow.output < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->pow.output; - assert(pOutputIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " = pow(") && drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, ", ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_powf1: type = drmtl_type_float; break; - case drmtl_opcode_powf2: type = drmtl_type_float2; break; - case drmtl_opcode_powf3: type = drmtl_type_float3; break; - case drmtl_opcode_powf4: type = drmtl_type_float4; break; - case drmtl_opcode_powi1: type = drmtl_type_int; break; - case drmtl_opcode_powi2: type = drmtl_type_int2; break; - case drmtl_opcode_powi3: type = drmtl_type_int3; break; - case drmtl_opcode_powi4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->pow.inputDesc, &pInstruction->pow.inputX) && drmtl_codegen_glsl_write(pCodegen, ");\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_tex(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->tex.output < pCodegen->identifierCount && pInstruction->tex.texture < pCodegen->identifierCount) - { - drmtl_identifier* pOutputIdentifier = pCodegen->pIdentifiers + pInstruction->tex.output; - assert(pOutputIdentifier != NULL); - - drmtl_identifier* pTextureIdentifier = pCodegen->pIdentifiers + pInstruction->tex.texture; - assert(pTextureIdentifier != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, pOutputIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, " = ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_tex1: - { - type = drmtl_type_float; - if (!drmtl_codegen_glsl_write(pCodegen, "texture1D(")) - { - return 0; - } - - break; - } - - case drmtl_opcode_tex2: - { - type = drmtl_type_float2; - if (!drmtl_codegen_glsl_write(pCodegen, "texture2D(")) - { - return 0; - } - - break; - } - - case drmtl_opcode_tex3: - { - type = drmtl_type_float3; - if (!drmtl_codegen_glsl_write(pCodegen, "texture3D(")) - { - return 0; - } - - break; - } - - case drmtl_opcode_texcube: - { - type = drmtl_type_float3; - if (!drmtl_codegen_glsl_write(pCodegen, "textureCube(")) - { - return 0; - } - - break; - } - - default: return 0; - } - - return - drmtl_codegen_glsl_write(pCodegen, pTextureIdentifier->name) && - drmtl_codegen_glsl_write(pCodegen, ", ") && - drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->tex.inputDesc, &pInstruction->tex.inputX) && - drmtl_codegen_glsl_write(pCodegen, ");\n"); - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_var(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (pInstruction->var.identifierIndex < pCodegen->identifierCount) - { - drmtl_identifier* pIdentifier = pCodegen->pIdentifiers + pInstruction->var.identifierIndex; - assert(pIdentifier != NULL); - - return drmtl_codegen_glsl_write_type(pCodegen, pIdentifier->type) && drmtl_codegen_glsl_write(pCodegen, " ") && drmtl_codegen_glsl_write(pCodegen, pIdentifier->name) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction_ret(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (drmtl_codegen_glsl_write(pCodegen, "return ")) - { - drmtl_type type; - switch (pInstruction->opcode) - { - case drmtl_opcode_retf1: type = drmtl_type_float; break; - case drmtl_opcode_retf2: type = drmtl_type_float2; break; - case drmtl_opcode_retf3: type = drmtl_type_float3; break; - case drmtl_opcode_retf4: type = drmtl_type_float4; break; - case drmtl_opcode_reti1: type = drmtl_type_int; break; - case drmtl_opcode_reti2: type = drmtl_type_int2; break; - case drmtl_opcode_reti3: type = drmtl_type_int3; break; - case drmtl_opcode_reti4: type = drmtl_type_int4; break; - default: return 0; - } - - return drmtl_codegen_glsl_write_instruction_input_initializer(pCodegen, type, pInstruction->ret.inputDesc, &pInstruction->ret.inputX) && drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instruction(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstruction) -{ - assert(pCodegen != NULL); - assert(pInstruction != NULL); - - if (drmtl_codegen_glsl_write_indentation(pCodegen)) - { - switch (pInstruction->opcode) - { - case drmtl_opcode_movf1: - case drmtl_opcode_movf2: - case drmtl_opcode_movf3: - case drmtl_opcode_movf4: - case drmtl_opcode_movi1: - case drmtl_opcode_movi2: - case drmtl_opcode_movi3: - case drmtl_opcode_movi4: - { - return drmtl_codegen_glsl_write_instruction_mov(pCodegen, pInstruction); - } - - - case drmtl_opcode_addf1: - case drmtl_opcode_addf2: - case drmtl_opcode_addf3: - case drmtl_opcode_addf4: - case drmtl_opcode_addi1: - case drmtl_opcode_addi2: - case drmtl_opcode_addi3: - case drmtl_opcode_addi4: - { - return drmtl_codegen_glsl_write_instruction_add(pCodegen, pInstruction); - } - - case drmtl_opcode_subf1: - case drmtl_opcode_subf2: - case drmtl_opcode_subf3: - case drmtl_opcode_subf4: - case drmtl_opcode_subi1: - case drmtl_opcode_subi2: - case drmtl_opcode_subi3: - case drmtl_opcode_subi4: - { - return drmtl_codegen_glsl_write_instruction_sub(pCodegen, pInstruction); - } - - case drmtl_opcode_mulf1: - case drmtl_opcode_mulf2: - case drmtl_opcode_mulf3: - case drmtl_opcode_mulf4: - case drmtl_opcode_muli1: - case drmtl_opcode_muli2: - case drmtl_opcode_muli3: - case drmtl_opcode_muli4: - { - return drmtl_codegen_glsl_write_instruction_mul(pCodegen, pInstruction); - } - - case drmtl_opcode_divf1: - case drmtl_opcode_divf2: - case drmtl_opcode_divf3: - case drmtl_opcode_divf4: - case drmtl_opcode_divi1: - case drmtl_opcode_divi2: - case drmtl_opcode_divi3: - case drmtl_opcode_divi4: - { - return drmtl_codegen_glsl_write_instruction_div(pCodegen, pInstruction); - } - - case drmtl_opcode_powf1: - case drmtl_opcode_powf2: - case drmtl_opcode_powf3: - case drmtl_opcode_powf4: - case drmtl_opcode_powi1: - case drmtl_opcode_powi2: - case drmtl_opcode_powi3: - case drmtl_opcode_powi4: - { - return drmtl_codegen_glsl_write_instruction_pow(pCodegen, pInstruction); - } - - case drmtl_opcode_tex1: - case drmtl_opcode_tex2: - case drmtl_opcode_tex3: - case drmtl_opcode_texcube: - { - return drmtl_codegen_glsl_write_instruction_tex(pCodegen, pInstruction); - } - - - case drmtl_opcode_var: - { - return drmtl_codegen_glsl_write_instruction_var(pCodegen, pInstruction); - } - - case drmtl_opcode_retf1: - case drmtl_opcode_retf2: - case drmtl_opcode_retf3: - case drmtl_opcode_retf4: - case drmtl_opcode_reti1: - case drmtl_opcode_reti2: - case drmtl_opcode_reti3: - case drmtl_opcode_reti4: - { - return drmtl_codegen_glsl_write_instruction_ret(pCodegen, pInstruction); - } - - - default: - { - // Unknown or unsupported opcode. - break; - } - } - } - - return 0; -} - -bool drmtl_codegen_glsl_write_instructions(drmtl_codegen_glsl* pCodegen, drmtl_instruction* pInstructions, unsigned int instructionCount) -{ - assert(pCodegen != NULL); - assert(pInstructions != NULL); - - for (unsigned int iInstruction = 0; iInstruction < instructionCount; ++iInstruction) - { - drmtl_instruction* pInstruction = pInstructions + iInstruction; - assert(pInstruction != NULL); - - if (!drmtl_codegen_glsl_write_instruction(pCodegen, pInstruction)) - { - return 0; - } - } - - return 1; -} - -bool drmtl_codegen_glsl_channel_function_begin(drmtl_codegen_glsl* pCodegen, drmtl_channel_header* pChannelHeader) -{ - assert(pCodegen != NULL); - assert(pChannelHeader != NULL); - - // {\n - bool result = - drmtl_codegen_glsl_write_type(pCodegen, pChannelHeader->channel.type) && - drmtl_codegen_glsl_write(pCodegen, " ") && - drmtl_codegen_glsl_write(pCodegen, pChannelHeader->channel.name) && - drmtl_codegen_glsl_write(pCodegen, "() {\n"); - if (result) - { - pCodegen->indentationLevel += 4; - } - - return result; -} - -bool drmtl_codegen_glsl_channel_function_close(drmtl_codegen_glsl* pCodegen) -{ - assert(pCodegen != NULL); - - if (pCodegen->indentationLevel > 4) { - pCodegen->indentationLevel -= 4; - } else { - pCodegen->indentationLevel = 0; - } - - return drmtl_codegen_glsl_write(pCodegen, "}\n"); -} - -bool drmtl_codegen_glsl_channel(drmtl_material* pMaterial, const char* channelName, char* codeOut, size_t codeOutSizeInBytes, size_t* pBytesWrittenOut) -{ - if (pMaterial != NULL) - { - drmtl_header* pHeader = drmtl_getheader(pMaterial); - if (pHeader != NULL) - { - drmtl_channel_header* pChannelHeader = drmtl_getchannelheaderbyname(pMaterial, channelName); - if (pChannelHeader != NULL) - { - drmtl_codegen_glsl codegen; - codegen.pBufferOut = codeOut; - codegen.bufferOutSizeInBytes = codeOutSizeInBytes; - codegen.runningLength = 0; - codegen.pMaterial = pMaterial; - codegen.pIdentifiers = drmtl_getidentifiers(pMaterial); - codegen.identifierCount = drmtl_getidentifiercount(pMaterial); - codegen.indentationLevel = 0; - - if (drmtl_codegen_glsl_channel_function_begin(&codegen, pChannelHeader)) - { - drmtl_instruction* pInstructions = (drmtl_instruction*)(pChannelHeader + 1); - assert(pInstructions != NULL); - - if (drmtl_codegen_glsl_write_instructions(&codegen, pInstructions, pChannelHeader->instructionCount)) - { - bool result = drmtl_codegen_glsl_channel_function_close(&codegen); - if (result) - { - if (pBytesWrittenOut != NULL) - { - *pBytesWrittenOut = codegen.runningLength + 1; - } - } - - return result; - } - } - } - } - } - - return 0; -} - - - -bool drmtl_codegen_glsl_uniform(drmtl_codegen_glsl* pCodegen, drmtl_input* pInput) -{ - assert(pCodegen != NULL); - assert(pInput != NULL); - - if (pInput->identifierIndex < pCodegen->identifierCount) - { - drmtl_identifier* pIdentifier = pCodegen->pIdentifiers + pInput->identifierIndex; - assert(pIdentifier != NULL); - - // uniform ; - return - drmtl_codegen_glsl_write(pCodegen, "uniform ") && - drmtl_codegen_glsl_write_type(pCodegen, pIdentifier->type) && - drmtl_codegen_glsl_write(pCodegen, " ") && - drmtl_codegen_glsl_write(pCodegen, pIdentifier->name) && - drmtl_codegen_glsl_write(pCodegen, ";\n"); - } - - return 0; -} - -bool drmtl_codegen_glsl_uniforms(drmtl_material* pMaterial, char* codeOut, size_t codeOutSizeInBytes, size_t* pBytesWritteOut) -{ - if (pMaterial != NULL) - { - drmtl_codegen_glsl codegen; - codegen.pBufferOut = codeOut; - codegen.bufferOutSizeInBytes = codeOutSizeInBytes; - codegen.runningLength = 0; - codegen.pMaterial = pMaterial; - codegen.pIdentifiers = drmtl_getidentifiers(pMaterial); - codegen.identifierCount = drmtl_getidentifiercount(pMaterial); - codegen.indentationLevel = 0; - - - unsigned int inputCount = drmtl_getpublicinputcount(pMaterial); - if (inputCount > 0) - { - for (unsigned int iInput = 0; iInput < inputCount; ++iInput) - { - drmtl_input* pInput = drmtl_getpublicinputbyindex(pMaterial, iInput); - assert(pInput != NULL); - - if (!drmtl_codegen_glsl_uniform(&codegen, pInput)) - { - // There was an error writing one of the uniforms. Return false. - return 0; - } - } - } - else - { - // No inputs. Just write an empty string. - drmtl_codegen_glsl_write(&codegen, ""); - } - - if (pBytesWritteOut != NULL) - { - *pBytesWritteOut = codegen.runningLength + 1; - } - - return 1; - } - - return 0; -} - -#if defined(__clang__) - #pragma GCC diagnostic pop -#endif -#endif - -#if defined(__clang__) - #pragma GCC diagnostic pop -#endif -#endif - -/* -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. - -For more information, please refer to -*/ diff --git a/source/engine/thirdparty/dr_libs/old/dr_pcx.h b/source/engine/thirdparty/dr_libs/old/dr_pcx.h deleted file mode 100644 index 04f9adc..0000000 --- a/source/engine/thirdparty/dr_libs/old/dr_pcx.h +++ /dev/null @@ -1,793 +0,0 @@ -// PCX image loader. Public domain. See "unlicense" statement at the end of this file. -// dr_pcx - v0.3.1 - 2018-09-11 -// -// David Reid - mackron@gmail.com - -// USAGE -// -// dr_pcx is a single-file library. To use it, do something like the following in one .c file. -// #define DR_PCX_IMPLEMENTATION -// #include "dr_pcx.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. Do something like -// the following to load and decode an image: -// -// int width; -// int height; -// int components -// drpcx_uint8* pImageData = drpcx_load_file("my_image.pcx", DRPCX_FALSE, &width, &height, &components, 0); -// if (pImageData == NULL) { -// // Failed to load image. -// } -// -// ... -// -// drpcx_free(pImageData); -// -// The boolean parameter (second argument in the above example) is whether or not the image should be flipped upside down. -// -// -// -// OPTIONS -// #define these options before including this file. -// -// #define DR_PCX_NO_STDIO -// Disable drpcx_load_file(). -// -// -// -// QUICK NOTES -// - 2-bpp/4-plane and 4-bpp/1-plane formats have not been tested. - -#ifndef dr_pcx_h -#define dr_pcx_h - -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -typedef signed char drpcx_int8; -typedef unsigned char drpcx_uint8; -typedef signed short drpcx_int16; -typedef unsigned short drpcx_uint16; -typedef signed int drpcx_int32; -typedef unsigned int drpcx_uint32; -typedef signed __int64 drpcx_int64; -typedef unsigned __int64 drpcx_uint64; -#else -#include -typedef int8_t drpcx_int8; -typedef uint8_t drpcx_uint8; -typedef int16_t drpcx_int16; -typedef uint16_t drpcx_uint16; -typedef int32_t drpcx_int32; -typedef uint32_t drpcx_uint32; -typedef int64_t drpcx_int64; -typedef uint64_t drpcx_uint64; -#endif -typedef drpcx_uint8 drpcx_bool8; -typedef drpcx_uint32 drpcx_bool32; -#define DRPCX_TRUE 1 -#define DRPCX_FALSE 0 - -#ifdef __cplusplus -extern "C" { -#endif - -// Callback for when data is read. Return value is the number of bytes actually read. -typedef size_t (* drpcx_read_proc)(void* userData, void* bufferOut, size_t bytesToRead); - - -// Loads a PCX file using the given callbacks. -drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents); - -// Frees memory returned by drpcx_load() and family. -void drpcx_free(void* pReturnValueFromLoad); - - -#ifndef DR_PCX_NO_STDIO -// Loads an PCX file from an actual file. -drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents); -#endif - -// Helper for loading an PCX file from a block of memory. -drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents); - - -#ifdef __cplusplus -} -#endif - -#endif // dr_pcx_h - - -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_PCX_IMPLEMENTATION -#include -#include -#include - -#ifndef DR_PCX_NO_STDIO -#include - -static size_t drpcx__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) -{ - return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData); -} - -drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents) -{ - FILE* pFile; -#ifdef _MSC_VER - if (fopen_s(&pFile, filename, "rb") != 0) { - return NULL; - } -#else - pFile = fopen(filename, "rb"); - if (pFile == NULL) { - return NULL; - } -#endif - - drpcx_uint8* pImageData = drpcx_load(drpcx__on_read_stdio, pFile, flipped, x, y, internalComponents, desiredComponents); - - fclose(pFile); - return pImageData; -} -#endif // DR_PCX_NO_STDIO - - -typedef struct -{ - // A pointer to the beginning of the data. We use a char as the type here for easy offsetting. - const unsigned char* data; - size_t dataSize; - size_t currentReadPos; -} drpcx_memory; - -static size_t drpcx__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) -{ - drpcx_memory* memory = (drpcx_memory*)pUserData; - assert(memory != NULL); - assert(memory->dataSize >= memory->currentReadPos); - - size_t bytesRemaining = memory->dataSize - memory->currentReadPos; - if (bytesToRead > bytesRemaining) { - bytesToRead = bytesRemaining; - } - - if (bytesToRead > 0) { - memcpy(bufferOut, memory->data + memory->currentReadPos, bytesToRead); - memory->currentReadPos += bytesToRead; - } - - return bytesToRead; -} - -drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents) -{ - drpcx_memory memory; - memory.data = (const unsigned char*)data; - memory.dataSize = dataSize; - memory.currentReadPos = 0; - return drpcx_load(drpcx__on_read_memory, &memory, flipped, x, y, internalComponents, desiredComponents); -} - - -typedef struct -{ - drpcx_uint8 header; - drpcx_uint8 version; - drpcx_uint8 encoding; - drpcx_uint8 bpp; - drpcx_uint16 left; - drpcx_uint16 top; - drpcx_uint16 right; - drpcx_uint16 bottom; - drpcx_uint16 hres; - drpcx_uint16 vres; - drpcx_uint8 palette16[48]; - drpcx_uint8 reserved1; - drpcx_uint8 bitPlanes; - drpcx_uint16 bytesPerLine; - drpcx_uint16 paletteType; - drpcx_uint16 screenSizeH; - drpcx_uint16 screenSizeV; - drpcx_uint8 reserved2[54]; -} drpcx_header; - -typedef struct -{ - drpcx_read_proc onRead; - void* pUserData; - drpcx_bool32 flipped; - drpcx_header header; - - drpcx_uint32 width; - drpcx_uint32 height; - drpcx_uint32 components; // 3 = RGB; 4 = RGBA. Only 3 and 4 are supported. - drpcx_uint8* pImageData; -} drpcx; - - -static drpcx_uint8 drpcx__read_byte(drpcx* pPCX) -{ - drpcx_uint8 byte = 0; - pPCX->onRead(pPCX->pUserData, &byte, 1); - - return byte; -} - -static drpcx_uint8* drpcx__row_ptr(drpcx* pPCX, drpcx_uint32 row) -{ - drpcx_uint32 stride = pPCX->width * pPCX->components; - - drpcx_uint8* pRow = pPCX->pImageData; - if (pPCX->flipped) { - pRow += (pPCX->height - row - 1) * stride; - } else { - pRow += row * stride; - } - - return pRow; -} - -static drpcx_uint8 drpcx__rle(drpcx* pPCX, drpcx_uint8* pRLEValueOut) -{ - drpcx_uint8 rleCount; - drpcx_uint8 rleValue; - - rleValue = drpcx__read_byte(pPCX); - if ((rleValue & 0xC0) == 0xC0) { - rleCount = rleValue & 0x3F; - rleValue = drpcx__read_byte(pPCX); - } else { - rleCount = 1; - } - - - *pRLEValueOut = rleValue; - return rleCount; -} - - -drpcx_bool32 drpcx__decode_1bit(drpcx* pPCX) -{ - drpcx_uint8 rleCount = 0; - drpcx_uint8 rleValue = 0; - - switch (pPCX->header.bitPlanes) - { - case 1: - { - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) { - drpcx_uint8 mask = (1 << (7 - bit)); - drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit); - - pRow[0] = paletteIndex * 255; - pRow[1] = paletteIndex * 255; - pRow[2] = paletteIndex * 255; - pRow += 3; - } - } - } - - return DRPCX_TRUE; - - } break; - - case 2: - case 3: - case 4: - { - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) { - drpcx_uint8 mask = (1 << (7 - bit)); - drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit); - - pRow[0] |= ((paletteIndex & 0x01) << c); - pRow += pPCX->components; - } - } - } - - - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->width; ++x) { - drpcx_uint8 paletteIndex = pRow[0]; - for (drpcx_uint32 c = 0; c < pPCX->components; ++c) { - pRow[c] = pPCX->header.palette16[paletteIndex*3 + c]; - } - - pRow += pPCX->components; - } - } - - return DRPCX_TRUE; - } - - default: return DRPCX_FALSE; - } -} - -drpcx_bool32 drpcx__decode_2bit(drpcx* pPCX) -{ - drpcx_uint8 rleCount = 0; - drpcx_uint8 rleValue = 0; - - switch (pPCX->header.bitPlanes) - { - case 1: - { - drpcx_uint8 paletteCGA[48]; - paletteCGA[ 0] = 0x00; paletteCGA[ 1] = 0x00; paletteCGA[ 2] = 0x00; // #000000 - paletteCGA[ 3] = 0x00; paletteCGA[ 4] = 0x00; paletteCGA[ 5] = 0xAA; // #0000AA - paletteCGA[ 6] = 0x00; paletteCGA[ 7] = 0xAA; paletteCGA[ 8] = 0x00; // #00AA00 - paletteCGA[ 9] = 0x00; paletteCGA[10] = 0xAA; paletteCGA[11] = 0xAA; // #00AAAA - paletteCGA[12] = 0xAA; paletteCGA[13] = 0x00; paletteCGA[14] = 0x00; // #AA0000 - paletteCGA[15] = 0xAA; paletteCGA[16] = 0x00; paletteCGA[17] = 0xAA; // #AA00AA - paletteCGA[18] = 0xAA; paletteCGA[19] = 0x55; paletteCGA[20] = 0x00; // #AA5500 - paletteCGA[21] = 0xAA; paletteCGA[22] = 0xAA; paletteCGA[23] = 0xAA; // #AAAAAA - paletteCGA[24] = 0x55; paletteCGA[25] = 0x55; paletteCGA[26] = 0x55; // #555555 - paletteCGA[27] = 0x55; paletteCGA[28] = 0x55; paletteCGA[29] = 0xFF; // #5555FF - paletteCGA[30] = 0x55; paletteCGA[31] = 0xFF; paletteCGA[32] = 0x55; // #55FF55 - paletteCGA[33] = 0x55; paletteCGA[34] = 0xFF; paletteCGA[35] = 0xFF; // #55FFFF - paletteCGA[36] = 0xFF; paletteCGA[37] = 0x55; paletteCGA[38] = 0x55; // #FF5555 - paletteCGA[39] = 0xFF; paletteCGA[40] = 0x55; paletteCGA[41] = 0xFF; // #FF55FF - paletteCGA[42] = 0xFF; paletteCGA[43] = 0xFF; paletteCGA[44] = 0x55; // #FFFF55 - paletteCGA[45] = 0xFF; paletteCGA[46] = 0xFF; paletteCGA[47] = 0xFF; // #FFFFFF - - drpcx_uint8 cgaBGColor = pPCX->header.palette16[0] >> 4; - drpcx_uint8 i = (pPCX->header.palette16[3] & 0x20) >> 5; - drpcx_uint8 p = (pPCX->header.palette16[3] & 0x40) >> 6; - //drpcx_uint8 c = (pPCX->header.palette16[3] & 0x80) >> 7; // Color or monochrome. How is monochrome handled? - - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - for (int bit = 0; bit < 4; ++bit) { - if (x*4 + bit < pPCX->width) { - drpcx_uint8 mask = (3 << ((3 - bit) * 2)); - drpcx_uint8 paletteIndex = (rleValue & mask) >> ((3 - bit) * 2); - - drpcx_uint8 cgaIndex; - if (paletteIndex == 0) { // Background. - cgaIndex = cgaBGColor; - } else { // Foreground - cgaIndex = (((paletteIndex << 1) + p) + (i << 3)); - } - - pRow[0] = paletteCGA[cgaIndex*3 + 0]; - pRow[1] = paletteCGA[cgaIndex*3 + 1]; - pRow[2] = paletteCGA[cgaIndex*3 + 2]; - pRow += 3; - } - } - } - } - - // TODO: According to http://www.fysnet.net/pcxfile.htm, we should use the palette at the end of the file - // instead of the standard CGA palette if the version is equal to 5. With my test files the palette - // at the end of the file does not exist. Research this one. - if (pPCX->header.version == 5) { - drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX); - if (paletteMarker == 0x0C) { - // TODO: Implement Me. - } - } - - return DRPCX_TRUE; - }; - - case 4: - { - // NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me! - // TODO: Test Me. - - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - for (int bitpair = 0; (bitpair < 4) && ((x*4 + bitpair) < pPCX->width); ++bitpair) { - drpcx_uint8 mask = (4 << (3 - bitpair)); - drpcx_uint8 paletteIndex = (rleValue & mask) >> (3 - bitpair); - - pRow[0] |= ((paletteIndex & 0x03) << (c*2)); - pRow += pPCX->components; - } - } - } - - - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->width; ++x) { - drpcx_uint8 paletteIndex = pRow[0]; - for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) { - pRow[c] = pPCX->header.palette16[paletteIndex*3 + c]; - } - - pRow += pPCX->components; - } - } - - return DRPCX_TRUE; - }; - - default: return DRPCX_FALSE; - } -} - -drpcx_bool32 drpcx__decode_4bit(drpcx* pPCX) -{ - // NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me! - // TODO: Test Me. - - if (pPCX->header.bitPlanes > 1) { - return DRPCX_FALSE; - } - - drpcx_uint8 rleCount = 0; - drpcx_uint8 rleValue = 0; - - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - for (int nibble = 0; (nibble < 2) && ((x*2 + nibble) < pPCX->width); ++nibble) - { - drpcx_uint8 mask = (4 << (1 - nibble)); - drpcx_uint8 paletteIndex = (rleValue & mask) >> (1 - nibble); - - pRow[0] |= ((paletteIndex & 0x0F) << (c*4)); - pRow += pPCX->components; - } - } - } - - - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->width; ++x) { - drpcx_uint8 paletteIndex = pRow[0]; - for (drpcx_uint32 c = 0; c < pPCX->components; ++c) { - pRow[c] = pPCX->header.palette16[paletteIndex*3 + c]; - } - - pRow += pPCX->components; - } - } - - return DRPCX_TRUE; -} - -drpcx_bool32 drpcx__decode_8bit(drpcx* pPCX) -{ - drpcx_uint8 rleCount = 0; - drpcx_uint8 rleValue = 0; - drpcx_uint32 stride = pPCX->width * pPCX->components; - - switch (pPCX->header.bitPlanes) - { - case 1: - { - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - if (x < pPCX->width) { - pRow[0] = rleValue; - pRow[1] = rleValue; - pRow[2] = rleValue; - pRow += 3; - } - } - } - - // At this point we can know if we are dealing with a palette or a grayscale image by checking the next byte. If it's equal to 0x0C, we - // need to do a simple palette lookup. - drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX); - if (paletteMarker == 0x0C) { - // A palette is present - we need to do a second pass. - drpcx_uint8 palette256[768]; - if (pPCX->onRead(pPCX->pUserData, palette256, sizeof(palette256)) != sizeof(palette256)) { - return DRPCX_FALSE; - } - - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - drpcx_uint8* pRow = pPCX->pImageData + (y * stride); - for (drpcx_uint32 x = 0; x < pPCX->width; ++x) { - drpcx_uint8 index = pRow[0]; - pRow[0] = palette256[index*3 + 0]; - pRow[1] = palette256[index*3 + 1]; - pRow[2] = palette256[index*3 + 2]; - pRow += 3; - } - } - } - - return DRPCX_TRUE; - } - - case 3: - case 4: - { - for (drpcx_uint32 y = 0; y < pPCX->height; ++y) { - for (drpcx_uint32 c = 0; c < pPCX->components; ++c) { - drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y); - for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) { - if (rleCount == 0) { - rleCount = drpcx__rle(pPCX, &rleValue); - } - rleCount -= 1; - - if (x < pPCX->width) { - pRow[c] = rleValue; - pRow += pPCX->components; - } - } - } - } - - return DRPCX_TRUE; - } - } - - return DRPCX_TRUE; -} - -drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents) -{ - if (onRead == NULL) return NULL; - if (desiredComponents > 4) return NULL; - - drpcx pcx; - pcx.onRead = onRead; - pcx.pUserData = pUserData; - pcx.flipped = flipped; - if (onRead(pUserData, &pcx.header, sizeof(pcx.header)) != sizeof(pcx.header)) { - return NULL; // Failed to read the header. - } - - if (pcx.header.header != 10) { - return NULL; // Not a PCX file. - } - - if (pcx.header.encoding != 1) { - return NULL; // Not supporting non-RLE encoding. Would assume a value of 0 indicates raw, unencoded, but that is apparently never used. - } - - if (pcx.header.bpp != 1 && pcx.header.bpp != 2 && pcx.header.bpp != 4 && pcx.header.bpp != 8) { - return NULL; // Unsupported pixel format. - } - - - if (pcx.header.left > pcx.header.right) { - drpcx_uint16 temp = pcx.header.left; - pcx.header.left = pcx.header.right; - pcx.header.right = temp; - } - if (pcx.header.top > pcx.header.bottom) { - drpcx_uint16 temp = pcx.header.top; - pcx.header.top = pcx.header.bottom; - pcx.header.bottom = temp; - } - - pcx.width = pcx.header.right - pcx.header.left + 1; - pcx.height = pcx.header.bottom - pcx.header.top + 1; - pcx.components = (pcx.header.bpp == 8 && pcx.header.bitPlanes == 4) ? 4 : 3; - - size_t dataSize = pcx.width * pcx.height * pcx.components; - pcx.pImageData = (drpcx_uint8*)calloc(1, dataSize); // <-- Clearing to zero is important! Required for proper decoding. - if (pcx.pImageData == NULL) { - return NULL; // Failed to allocate memory. - } - - drpcx_bool32 result = DRPCX_FALSE; - switch (pcx.header.bpp) - { - case 1: - { - result = drpcx__decode_1bit(&pcx); - } break; - - case 2: - { - result = drpcx__decode_2bit(&pcx); - } break; - - case 4: - { - result = drpcx__decode_4bit(&pcx); - } break; - - case 8: - { - result = drpcx__decode_8bit(&pcx); - } break; - } - - if (!result) { - free(pcx.pImageData); - return NULL; - } - - // There's an annoying amount of branching when loading PCX files so for simplicity I'm doing the component conversion as - // a second pass. - if (desiredComponents == 0) desiredComponents = pcx.components; - if (desiredComponents != (int)pcx.components) { - drpcx_uint8* pNewImageData = (drpcx_uint8*)malloc(pcx.width * pcx.height * desiredComponents); - if (pNewImageData == NULL) { - free(pcx.pImageData); - return NULL; - } - - drpcx_uint8* pSrcData = pcx.pImageData; - drpcx_uint8* pDstData = pNewImageData; - if (desiredComponents < (int)pcx.components) { - // We're reducing the number of components. Just drop the excess. - for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) { - for (int c = 0; c < desiredComponents; ++c) { - pDstData[c] = pSrcData[c]; - } - - pSrcData += pcx.components; - pDstData += desiredComponents; - } - } else { - // We're increasing the number of components. Always ensure the alpha channel is set to 0xFF. - if (pcx.components == 1) { - for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) { - for (int c = 0; c < desiredComponents; ++c) { - pDstData[c] = pSrcData[0]; - } - - pSrcData += pcx.components; - pDstData += desiredComponents; - } - } else if (pcx.components == 2) { - for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) { - pDstData[0] = pSrcData[0]; - pDstData[1] = pSrcData[1]; - pDstData[2] = 0x00; - if (desiredComponents == 4) pDstData[3] = 0xFF; - - pSrcData += pcx.components; - pDstData += desiredComponents; - } - } else { - assert(pcx.components == 3); - assert(desiredComponents == 4); - for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) { - pDstData[0] = pSrcData[0]; - pDstData[1] = pSrcData[1]; - pDstData[2] = pSrcData[2]; - pDstData[3] = 0xFF; - - pSrcData += pcx.components; - pDstData += desiredComponents; - } - } - } - - free(pcx.pImageData); - pcx.pImageData = pNewImageData; - } - - if (x) *x = pcx.width; - if (y) *y = pcx.height; - if (internalComponents) *internalComponents = pcx.components; - return pcx.pImageData; -} - -void drpcx_free(void* pReturnValueFromLoad) -{ - free(pReturnValueFromLoad); -} - -#endif // DR_PCX_IMPLEMENTATION - - -// REVISION HISTORY -// -// v0.3.1 - 2018-09-11 -// - Styling fixes. -// - Fix a typo. -// -// v0.3 - 2018-02-08 -// - API CHANGE: Rename dr_* types to drpcx_*. -// -// v0.2c - 2018-02-07 -// - Fix a crash. -// -// v0.2b - 2018-02-02 -// - Fix compilation error. -// -// v0.2a - 2017-07-16 -// - Change underlying type for booleans to unsigned. -// -// v0.2 - 2016-10-28 -// - API CHANGE: Add a parameter to drpcx_load() and family to control the number of output components. -// - Use custom sized types rather than built-in ones to improve support for older MSVC compilers. -// -// v0.1c - 2016-10-23 -// - A minor change to drpcx_bool8 and drpcx_bool32 types. -// -// v0.1b - 2016-10-11 -// - Use drpcx_bool32 instead of the built-in "bool" type. The reason for this change is that it helps maintain API/ABI consistency -// between C and C++ builds. -// -// v0.1a - 2016-09-18 -// - Change date format to ISO 8601 (YYYY-MM-DD) -// -// v0.1 - 2016-05-04 -// - Initial versioned release. - - -// TODO -// - Test 2-bpp/4-plane and 4-bpp/1-plane formats. - - -/* -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. - -For more information, please refer to -*/ - diff --git a/source/engine/thirdparty/dr_libs/tests/README.md b/source/engine/thirdparty/dr_libs/tests/README.md deleted file mode 100644 index 9a0eb4b..0000000 --- a/source/engine/thirdparty/dr_libs/tests/README.md +++ /dev/null @@ -1,49 +0,0 @@ -Building -======== -Move into this directory and run the build script for the relevant platform. Run from this directory. - - clear && ./build_opus && ./bin/dr_opus_test_0 - -Alternatively you can compile a specific test manually: - - clear && gcc ./opus/dr_opus_test_0 -o ./bin/dr_opus_test_0 && ./bin/dr_opus_test_0 - -Test vectors will be loaded from the "testvectors" folder, relative to this directory. Therefore, you need to run -each test program from this directory: - - ./bin/dr_opus_test_0 - - -Building and Running WAV Tests ------------------------------- -The WAV tests use libsndfile as a benchmark. The tests programs dynamically link to libsndfile at runtime which -means you don't need to link to it at compile time. However, you will need the headers installed in a standard -location. The batch files for the Windows build will allow you to customize the include path. On the Windows build -you will need to drop two versions of libsndfile-1.dll into the bin directory. For the 32-bit build you need to -name it libsndfile-1-x86.dll and for the 64-bit build you need to name it libsndfile-1-x64.dll. - - -Test Vectors -============ -In order to run certain tests you will need to download test vectors for the relevant project and place them into the -"testvectors" folder. - -Opus ----- -- Download both the original and new test vectors from https://opus-codec.org/testvectors/ and place them into - the "testvectors/opus" folder. -- Download the Ogg Opus test vectors from https://wiki.xiph.org/OggOpus/testvectors and place them into the - "testvectors/opus" folder. -- The folder structure should like like the following: - - testvectors - - opus - - opus_testvectors - - opus_newvectors - - oggopus - - failure_cases - - opus_multichannel_examples - -FLAC ----- -- Download the FLAC testbench from https://wiki.hydrogenaud.io/index.php?title=FLAC_decoder_testbench and place - them into the "testvectors/flac/testbench" folder. diff --git a/source/engine/thirdparty/dr_libs/tests/bin/DO_NOT_DELETE.md b/source/engine/thirdparty/dr_libs/tests/bin/DO_NOT_DELETE.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/dr_libs/tests/build_flac_linux.sh b/source/engine/thirdparty/dr_libs/tests/build_flac_linux.sh deleted file mode 100755 index 21297f0..0000000 --- a/source/engine/thirdparty/dr_libs/tests/build_flac_linux.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -gcc ./flac/dr_flac_test_0.c -o ./bin/dr_flac_test_0 -std=c89 -ansi -pedantic -O3 -s -Wall -ldl -gcc ./flac/dr_flac_decoding.c -o ./bin/dr_flac_decoding -std=c89 -ansi -pedantic -Wall -O3 -s -lFLAC -ldl -gcc ./flac/dr_flac_seeking.c -o ./bin/dr_flac_seeking -std=c89 -ansi -pedantic -Wall -O3 -s -lFLAC -ldl diff --git a/source/engine/thirdparty/dr_libs/tests/build_flac_win32.bat b/source/engine/thirdparty/dr_libs/tests/build_flac_win32.bat deleted file mode 100644 index 56c2a67..0000000 --- a/source/engine/thirdparty/dr_libs/tests/build_flac_win32.bat +++ /dev/null @@ -1,37 +0,0 @@ -:: NOTES -:: -:: These tests use libFLAC as a benchmark. Since Windows doesn't have good standard paths for library files, this -:: script will use "flac/include" as an additional search path for headers and "flac/lib/win32" as an additional -:: search path for libraries. You will need to place FLAC headers in the "flac/include/FLAC" directory and libogg -:: headers int the "flac/include/ogg" directory. -:: -:: Examples are linked against "-lFLAC" and "-logg". These need to be placed in a standard directory or "flac/lib/win32". - -@echo off -SET c_compiler=gcc -SET cpp_compiler=g++ - -:: Configure the "arch" option to test different instruction sets. -SET arch= -SET arch=-msse4.1 -::SET arch=-mfpu=neon - -:: libFLAC and libogg are required for benchmarking. -SET libFLAC=-I./flac/include -L./flac/lib/win32 -lFLAC -logg - -:: C options -SET c_options=-std=c89 -ansi - -:: C++ options -SET cpp_options= - -SET options=-Wall -Wpedantic -pedantic -O3 -s -DNDEBUG %arch% %libFLAC% - -SET buildc=%c_compiler% %c_options% -SET buildcpp=%cpp_compiler% %cpp_options% -@echo on - -%buildc% ./flac/dr_flac_test_0.c -o ./bin/dr_flac_test_0.exe %options% -%buildcpp% ./flac/dr_flac_test_0.cpp -o ./bin/dr_flac_test_0_cpp.exe %options% -%buildc% ./flac/dr_flac_decoding.c -o ./bin/dr_flac_decoding.exe %options% -%buildcpp% ./flac/dr_flac_decoding.cpp -o ./bin/dr_flac_decoding_cpp.exe %options% \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/build_mp3_win32.bat b/source/engine/thirdparty/dr_libs/tests/build_mp3_win32.bat deleted file mode 100644 index 2692cff..0000000 --- a/source/engine/thirdparty/dr_libs/tests/build_mp3_win32.bat +++ /dev/null @@ -1,2 +0,0 @@ -gcc ./mp3/dr_mp3_test_0.c -o ./bin/dr_mp3_test_0.exe -std=c89 -ansi -pedantic -Wall -g++ ./mp3/dr_mp3_test_0.cpp -o ./bin/dr_mp3_test_0.exe -pedantic -Wall \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/build_opus_win32.bat b/source/engine/thirdparty/dr_libs/tests/build_opus_win32.bat deleted file mode 100644 index dbb8a85..0000000 --- a/source/engine/thirdparty/dr_libs/tests/build_opus_win32.bat +++ /dev/null @@ -1 +0,0 @@ -gcc ./opus/dr_opus_decoding.c -o ./bin/dr_opus_decoding.exe -std=c89 -ansi -pedantic -Wall -Wextra \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/build_wav_win32.bat b/source/engine/thirdparty/dr_libs/tests/build_wav_win32.bat deleted file mode 100644 index e0f948c..0000000 --- a/source/engine/thirdparty/dr_libs/tests/build_wav_win32.bat +++ /dev/null @@ -1,38 +0,0 @@ -:: NOTES -:: -:: These tests use libsndfile as a benchmark. Since Windows doesn't have good standard paths for library files, this -:: script will use "wav/include" as an additional search path for headers. You will need to place sndfile.h to the -:: "wav/include" directory. Tests will link to libsndfile dynamically at run-time. On the Windows build you'll just -:: need to put a copy of the 32- and 64-bit versions of libsndfile-1.dll into the "bin" directory, with the names -:: libsndfile-1-x86.dll and libsndfile-1-x64.dll respectively. Both versions are required so that both the 32- and -:: 64-bit builds can be tested and benchmarked. - -@echo off - -SET c_compiler=gcc -SET cpp_compiler=g++ - -:: Configure the "arch" option to test different instruction sets. -SET arch= -SET arch=-msse4.1 -::SET arch=-mfpu=neon - -:: libsndfile is required for benchmarking. -SET libsndfile=-I./wav/include - -:: C options -SET c_options=-std=c89 -ansi - -:: C++ options -SET cpp_options= - -SET options=-Wall -Wpedantic -pedantic -O3 -s -DNDEBUG %arch% %libsndfile% - -SET buildc=%c_compiler% %c_options% %options% -SET buildcpp=%cpp_compiler% %cpp_options% %options% -@echo on - -%buildc% ./wav/dr_wav_test_0.c -o ./bin/dr_wav_test_0.exe -%buildcpp% ./wav/dr_wav_test_0.cpp -o ./bin/dr_wav_test_0_cpp.exe -%buildc% ./wav/dr_wav_decoding.c -o ./bin/dr_wav_decoding.exe -%buildcpp% ./wav/dr_wav_decoding.cpp -o ./bin/dr_wav_decoding_cpp.exe \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/common/dr_common.c b/source/engine/thirdparty/dr_libs/tests/common/dr_common.c deleted file mode 100644 index 46b34b8..0000000 --- a/source/engine/thirdparty/dr_libs/tests/common/dr_common.c +++ /dev/null @@ -1,957 +0,0 @@ - -#ifdef _WIN32 -#include -#endif - -#if defined(_MSC_VER) || defined(__DMC__) -#else -#include -#endif - -#include -#include -#include /* So we can seed the random number generator based on time. */ -#include - -#if !defined(_WIN32) -#include -#include -#include -#include -#include -#endif - -#include /* For size_t. */ - -/* Sized types. Prefer built-in types. Fall back to stdint. */ -#ifdef _MSC_VER - #if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wlanguage-extension-token" - #pragma GCC diagnostic ignored "-Wlong-long" - #pragma GCC diagnostic ignored "-Wc++11-long-long" - #endif - typedef signed __int8 dr_int8; - typedef unsigned __int8 dr_uint8; - typedef signed __int16 dr_int16; - typedef unsigned __int16 dr_uint16; - typedef signed __int32 dr_int32; - typedef unsigned __int32 dr_uint32; - typedef signed __int64 dr_int64; - typedef unsigned __int64 dr_uint64; - #if defined(__clang__) - #pragma GCC diagnostic pop - #endif -#else - #define MA_HAS_STDINT - #include - typedef int8_t dr_int8; - typedef uint8_t dr_uint8; - typedef int16_t dr_int16; - typedef uint16_t dr_uint16; - typedef int32_t dr_int32; - typedef uint32_t dr_uint32; - typedef int64_t dr_int64; - typedef uint64_t dr_uint64; -#endif - -#ifdef MA_HAS_STDINT - typedef uintptr_t dr_uintptr; -#else - #if defined(_WIN32) - #if defined(_WIN64) - typedef dr_uint64 dr_uintptr; - #else - typedef dr_uint32 dr_uintptr; - #endif - #elif defined(__GNUC__) - #if defined(__LP64__) - typedef dr_uint64 dr_uintptr; - #else - typedef dr_uint32 dr_uintptr; - #endif - #else - typedef dr_uint64 dr_uintptr; /* Fallback. */ - #endif -#endif - -typedef dr_uint8 dr_bool8; -typedef dr_uint32 dr_bool32; -#define DR_TRUE 1 -#define DR_FALSE 0 - -typedef void* dr_handle; -typedef void* dr_ptr; -typedef void (* dr_proc)(void); - -#if defined(SIZE_MAX) - #define DR_SIZE_MAX SIZE_MAX -#else - #define DR_SIZE_MAX 0xFFFFFFFF -#endif - -/* -Return Values: - 0: Success - 22: EINVAL - 34: ERANGE - -Not using symbolic constants for errors because I want to avoid #including errno.h -*/ -int dr_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - size_t i; - - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstSizeInBytes) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return 34; -} - -int dr_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - size_t maxcount; - size_t i; - - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - maxcount = count; - if (count == ((size_t)-1) || count >= dstSizeInBytes) { /* -1 = _TRUNCATE */ - maxcount = dstSizeInBytes - 1; - } - - for (i = 0; i < maxcount && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (src[i] == '\0' || i == count || count == ((size_t)-1)) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return 34; -} - -int dr_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - char* dstorig; - - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - dstorig = dst; - - while (dstSizeInBytes > 0 && dst[0] != '\0') { - dst += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - return 22; /* Unterminated. */ - } - - - while (dstSizeInBytes > 0 && src[0] != '\0') { - *dst++ = *src++; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes > 0) { - dst[0] = '\0'; - } else { - dstorig[0] = '\0'; - return 34; - } - - return 0; -} - -int dr_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - char* dstorig; - - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - return 22; - } - - dstorig = dst; - - while (dstSizeInBytes > 0 && dst[0] != '\0') { - dst += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - return 22; /* Unterminated. */ - } - - - if (count == ((size_t)-1)) { /* _TRUNCATE */ - count = dstSizeInBytes - 1; - } - - while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) { - *dst++ = *src++; - dstSizeInBytes -= 1; - count -= 1; - } - - if (dstSizeInBytes > 0) { - dst[0] = '\0'; - } else { - dstorig[0] = '\0'; - return 34; - } - - return 0; -} - -/* -String Helpers -*/ -int dr_append_path(char* dst, size_t dstSize, const char* base, const char* other) -{ - int err; - size_t len; - - /* TODO: Return the correct error codes here. */ - if (dst == NULL) { - return -1; - } - if (base == NULL || other == NULL) { - return -1; - } - - err = dr_strcpy_s(dst, dstSize, base); - if (err != 0) { - return err; - } - - len = strlen(dst); - if (len > 0) { - /* Append the slash if required. */ - if (dst[len-1] != '/' && dst[len-1] != '\\') { - err = dr_strcat_s(dst, dstSize, "/"); - if (err != 0) { - dst[0] = '\0'; - return err; - } - - len += 1; /* +1 to the length to account for the slash. */ - } - } - - err = dr_strcat_s(dst, dstSize, other); - if (err != 0) { - dst[0] = '\0'; - return err; - } - - /* Success. */ - return 0; -} - -const char* dr_path_file_name(const char* path) -{ - const char* fileName = path; - - if (path == NULL) { - return NULL; - } - - /* We just loop through the path until we find the last slash. */ - while (path[0] != '\0') { - if (path[0] == '/' || path[0] == '\\') { - fileName = path; - } - - path += 1; - } - - /* At this point the file name is sitting on a slash, so just move forward. */ - while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { - fileName += 1; - } - - return fileName; -} - -const char* dr_extension(const char* path) -{ - const char* extension = path; - const char* lastoccurance = NULL; - - if (path == NULL) { - return NULL; - } - - /* Just find the last '.' and return. */ - while (extension[0] != '\0') { - if (extension[0] == '.') { - extension += 1; - lastoccurance = extension; - } - - extension += 1; - } - - return (lastoccurance != 0) ? lastoccurance : extension; -} - -dr_bool32 dr_extension_equal(const char* path, const char* extension) -{ - const char* ext1; - const char* ext2; - - if (path == NULL || extension == NULL) { - return 0; - } - - ext1 = extension; - ext2 = dr_extension(path); - -#if defined(_MSC_VER) || defined(__DMC__) - return _stricmp(ext1, ext2) == 0; -#else - return strcasecmp(ext1, ext2) == 0; -#endif -} - - - - -/* -File Iterator - -dr_file_iterator state; -dr_file_iterator* pFile = dr_file_iterator_begin("the/folder/path", &state); -while (pFile != NULL) { - // Do something with pFile. - pFile = dr_file_iterator_next(pFile); -} - -Limitations: - - Only supports file paths up to 256 characters. -*/ -typedef struct -{ - char folderPath[256]; - char relativePath[256]; /* Relative to the original folder path. */ - char absolutePath[256]; /* Concatenation of folderPath and relativePath. */ - dr_bool32 isDirectory; -#ifdef _WIN32 - HANDLE hFind; -#else - DIR* dir; -#endif -} dr_file_iterator; - -dr_file_iterator* dr_file_iterator_begin(const char* pFolderPath, dr_file_iterator* pState) -{ -#ifdef _WIN32 - char searchQuery[MAX_PATH]; - unsigned int searchQueryLength; - WIN32_FIND_DATAA ffd; - HANDLE hFind; -#else - DIR* dir; -#endif - - if (pState == NULL) { - return NULL; - } - - memset(pState, 0, sizeof(*pState)); - - if (pFolderPath == NULL) { - return NULL; - } - -#ifdef _WIN32 - dr_strcpy_s(searchQuery, sizeof(searchQuery), pFolderPath); - - searchQueryLength = (unsigned int)strlen(searchQuery); - if (searchQueryLength >= MAX_PATH - 3) { - return NULL; /* Path is too long. */ - } - - searchQuery[searchQueryLength + 0] = '\\'; - searchQuery[searchQueryLength + 1] = '*'; - searchQuery[searchQueryLength + 2] = '\0'; - - hFind = FindFirstFileA(searchQuery, &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - return NULL; /* Failed to begin search. */ - } - - /* Skip past "." and ".." directories. */ - while (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) { - if (!FindNextFileA(hFind, &ffd)) { - FindClose(hFind); - return NULL; /* Couldn't find anything. */ - } - } - - pState->hFind = hFind; - - - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - pState->isDirectory = 1; - } else { - pState->isDirectory = 0; - } - - dr_strcpy_s(pState->relativePath, sizeof(pState->relativePath), ffd.cFileName); -#else - dir = opendir(pFolderPath); - if (dir == NULL) { - return NULL; /* Couldn't find anything. */ - } - - /* Select the first file. */ - for (;;) { - struct dirent* info; - struct stat fileinfo; - char filePath[4096]; - - info = readdir(dir); - if (info == NULL) { - closedir(dir); - return NULL; - } - - if (strcmp(info->d_name, ".") == 0 || strcmp(info->d_name, "..") == 0) { - continue; /* Skip past "." and ".." directories. */ - } - - dr_strcpy_s(pState->relativePath, sizeof(pState->relativePath), info->d_name); - dr_append_path(filePath, sizeof(filePath), pFolderPath, pState->relativePath); - - if (stat(filePath, &fileinfo) != 0) { - continue; - } - - if (S_ISDIR(fileinfo.st_mode)) { - pState->isDirectory = 1; - } else { - pState->isDirectory = 0; - } - - break; - } - - pState->dir = dir; -#endif - - /* Getting here means everything was successful. We can now set some state before returning. */ - dr_strcpy_s(pState->folderPath, sizeof(pState->folderPath), pFolderPath); - dr_append_path(pState->absolutePath, sizeof(pState->absolutePath), pState->folderPath, pState->relativePath); - - return pState; -} - -dr_file_iterator* dr_file_iterator_next(dr_file_iterator* pState) -{ -#ifdef _WIN32 - WIN32_FIND_DATAA ffd; -#endif - - if (pState == NULL) { - return NULL; - } - -#ifdef _WIN32 - if (!FindNextFileA(pState->hFind, &ffd)) { - /* Couldn't find anything else. */ - FindClose(pState->hFind); - pState->hFind = NULL; - return NULL; - } - - /* Found something. */ - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - pState->isDirectory = 1; - } else { - pState->isDirectory = 0; - } - - dr_strcpy_s(pState->relativePath, sizeof(pState->relativePath), ffd.cFileName); -#else - /* Enter a loop here so we can skip past "." and ".." directories. */ - for (;;) { - struct dirent* info; - struct stat fileinfo; - char filePath[4096]; - - info = readdir(pState->dir); - if (info == NULL) { - closedir(pState->dir); - pState->dir = NULL; - return NULL; - } - - if (strcmp(info->d_name, ".") == 0 || strcmp(info->d_name, "..") == 0) { - continue; /* Skip past "." and ".." directories. */ - } - - dr_strcpy_s(pState->relativePath, sizeof(pState->relativePath), info->d_name); - dr_append_path(filePath, sizeof(filePath), pState->folderPath, pState->relativePath); - - /*printf("Done: %s\n", pState->relativePath);*/ - - if (stat(filePath, &fileinfo) != 0) { - continue; - } - - if (S_ISDIR(fileinfo.st_mode)) { - pState->isDirectory = 1; - } else { - pState->isDirectory = 0; - } - - break; - } -#endif - - /* Success */ - dr_append_path(pState->absolutePath, sizeof(pState->absolutePath), pState->folderPath, pState->relativePath); - return pState; -} - -void dr_file_iterator_end(dr_file_iterator* pState) -{ - if (pState == NULL) { - return; - } - -#ifdef _WIN32 - FindClose(pState->hFind); - pState->hFind = NULL; -#else - closedir(pState->dir); - pState->dir = NULL; -#endif -} - - -/* -File Management - -Free file data with free(). -*/ -static int dr_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) -{ -#if defined(_MSC_VER) && _MSC_VER >= 1400 - errno_t err; -#endif - - if (ppFile != NULL) { - *ppFile = NULL; /* Safety. */ - } - - if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { - return -1; /* Invalid args. */ - } - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - err = fopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return err; - } -#else -#if defined(_WIN32) || defined(__APPLE__) - *ppFile = fopen(pFilePath, pOpenMode); -#else - #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) - *ppFile = fopen64(pFilePath, pOpenMode); - #else - *ppFile = fopen(pFilePath, pOpenMode); - #endif -#endif - if (*ppFile == NULL) { - return errno; - } -#endif - - return 0; -} - -void* dr_open_and_read_file_with_extra_data(const char* pFilePath, size_t* pFileSizeOut, size_t extraBytes) -{ - FILE* pFile; - size_t fileSize; - size_t bytesRead; - void* pFileData; - - /* Safety. */ - if (pFileSizeOut) { - *pFileSizeOut = 0; - } - - if (pFilePath == NULL) { - return NULL; - } - - /* TODO: Use 64-bit versions of the FILE APIs. */ - - if (dr_fopen(&pFile, pFilePath, "rb") != 0) { - return NULL; - } - - fseek(pFile, 0, SEEK_END); - fileSize = ftell(pFile); - fseek(pFile, 0, SEEK_SET); - - /* Need to make sure we have enough room for the extra bytes, if any. */ - if (fileSize == DR_SIZE_MAX && extraBytes > 0) { - fclose(pFile); - return NULL; /* File is too big. */ - } - - pFileData = malloc((size_t)fileSize + extraBytes); /* <-- Safe cast due to the check above. */ - if (pFileData == NULL) { - fclose(pFile); - return NULL; /* Failed to allocate memory for the file. Good chance the file is too big. */ - } - - bytesRead = fread(pFileData, 1, (size_t)fileSize, pFile); - if (bytesRead != fileSize) { - free(pFileData); - fclose(pFile); - return NULL; /* Failed to read every byte from the file. */ - } - - fclose(pFile); - - if (pFileSizeOut) { - *pFileSizeOut = (size_t)fileSize; - } - - return pFileData; -} - -void* dr_open_and_read_file(const char* pFilePath, size_t* pFileSizeOut) -{ - return dr_open_and_read_file_with_extra_data(pFilePath, pFileSizeOut, 0); -} - - -dr_bool32 dr_argv_is_set(int argc, char** argv, const char* value) -{ - int iarg; - for (iarg = 0; iarg < argc; ++iarg) { - if (strcmp(argv[iarg], value) == 0) { - return DR_TRUE; - } - } - - return DR_FALSE; -} - - -int dr_vprintf_fixed(int width, const char* const format, va_list args) -{ - int i; - int len; - char buffer[4096]; - - if (width <= 0) { - return -1; /* Width cannot be negative or 0. */ - } - - if ((unsigned int)width > sizeof(buffer)) { - return -1; /* Width is too big. */ - } - - /* We need to print this into a string (truncated). */ -#if (defined(_MSC_VER) && _MSC_VER > 1200) || ((defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) || defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)) - len = vsnprintf(buffer, width+1, format, args); -#else - len = vsprintf(buffer, format, args); - if (len > width) { - len = width; - } - - buffer[len] = '\0'; -#endif - - printf("%s", buffer); - for (i = len; i < width; ++i) { - printf(" "); - } - - - return len; -} - -int dr_printf_fixed(int width, const char* const format, ...) -{ - int result; - - va_list args; - va_start(args, format); - { - result = dr_vprintf_fixed(width, format, args); - } - va_end(args); - - return result; -} - -int dr_vprintf_fixed_with_margin(int width, int margin, const char* const format, va_list args) -{ - int i; - - /* Margin. */ - for (i = 0; i < margin; ++i) { - printf(" "); - } - - return dr_vprintf_fixed(width - margin, format, args); -} - -int dr_printf_fixed_with_margin(int width, int margin, const char* const format, ...) -{ - int result; - - va_list args; - va_start(args, format); - { - result = dr_vprintf_fixed_with_margin(width, margin, format, args); - } - va_end(args); - - return result; -} - - - -#ifdef _WIN32 -static LARGE_INTEGER g_DRTimerFrequency = {{0}}; -double dr_timer_now() -{ - LARGE_INTEGER counter; - - if (g_DRTimerFrequency.QuadPart == 0) { - QueryPerformanceFrequency(&g_DRTimerFrequency); - } - - QueryPerformanceCounter(&counter); - - return counter.QuadPart / (double)g_DRTimerFrequency.QuadPart; -} -#else -#if _POSIX_C_SOURCE >= 199309L - #if defined(CLOCK_MONOTONIC) - #define MA_CLOCK_ID CLOCK_MONOTONIC - #else - #define MA_CLOCK_ID CLOCK_REALTIME - #endif - double dr_timer_now() - { - struct timespec newTime; - clock_gettime(CLOCK_MONOTONIC, &newTime); - - return ((newTime.tv_sec * 1000000000LL) + newTime.tv_nsec) / 1000000000.0; - } -#else - double dr_timer_now() - { - struct timeval newTime; - gettimeofday(&newTime, NULL); - - return ((newTime.tv_sec * 1000000) + newTime.tv_usec) / 1000000.0; - } -#endif -#endif - - -float dr_scale_to_range_f32(float x, float lo, float hi) -{ - return lo + x*(hi-lo); -} - - -#define DR_LCG_M 2147483647 -#define DR_LCG_A 48271 -#define DR_LCG_C 0 -static int g_drLCG; - -void dr_seed(int seed) -{ - g_drLCG = seed; -} - -int dr_rand_s32() -{ - int lcg = g_drLCG; - int r = (DR_LCG_A * lcg + DR_LCG_C) % DR_LCG_M; - g_drLCG = r; - return r; -} - -unsigned int dr_rand_u32() -{ - return (unsigned int)dr_rand_s32(); -} - -dr_uint64 dr_rand_u64() -{ - return ((dr_uint64)dr_rand_u32() << 32) | dr_rand_u32(); -} - -double dr_rand_f64() -{ - return dr_rand_s32() / (double)0x7FFFFFFF; -} - -float dr_rand_f32() -{ - return (float)dr_rand_f64(); -} - -float dr_rand_range_f32(float lo, float hi) -{ - return dr_scale_to_range_f32(dr_rand_f32(), lo, hi); -} - -int dr_rand_range_s32(int lo, int hi) -{ - if (lo == hi) { - return lo; - } - - return lo + dr_rand_u32() / (0xFFFFFFFF / (hi - lo + 1) + 1); -} - -dr_uint64 dr_rand_range_u64(dr_uint64 lo, dr_uint64 hi) -{ - if (lo == hi) { - return lo; - } - - return lo + dr_rand_u64() / ((~(dr_uint64)0) / (hi - lo + 1) + 1); -} - - - -void dr_pcm_s32_to_f32(void* dst, const void* src, dr_uint64 count) -{ - float* dst_f32 = (float*)dst; - const dr_int32* src_s32 = (const dr_int32*)src; - - dr_uint64 i; - for (i = 0; i < count; i += 1) { - double x = src_s32[i]; - -#if 0 - x = x + 2147483648.0; - x = x * 0.0000000004656612873077392578125; - x = x - 1; -#else - x = x / 2147483648.0; -#endif - - dst_f32[i] = (float)x; - } -} - -void dr_pcm_s32_to_s16(void* dst, const void* src, dr_uint64 count) -{ - dr_int16* dst_s16 = (dr_int16*)dst; - const dr_int32* src_s32 = (const dr_int32*)src; - - dr_uint64 i; - for (i = 0; i < count; i += 1) { - dr_int32 x = src_s32[i]; - x = x >> 16; - dst_s16[i] = (dr_int16)x; - } -} - - - - -dr_handle dr_dlopen(const char* filename) -{ - dr_handle handle; - -#ifdef _WIN32 - handle = (dr_handle)LoadLibraryA(filename); -#else - handle = (dr_handle)dlopen(filename, RTLD_NOW); -#endif - - return handle; -} - -void dr_dlclose(dr_handle handle) -{ -#ifdef _WIN32 - FreeLibrary((HMODULE)handle); -#else - dlclose((void*)handle); -#endif -} - -dr_proc dr_dlsym(dr_handle handle, const char* symbol) -{ - dr_proc proc; - -#ifdef _WIN32 - proc = (dr_proc)GetProcAddress((HMODULE)handle, symbol); -#else -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" -#endif - proc = (dr_proc)dlsym((void*)handle, symbol); -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) - #pragma GCC diagnostic pop -#endif -#endif - - return proc; -} diff --git a/source/engine/thirdparty/dr_libs/tests/external/miniaudio b/source/engine/thirdparty/dr_libs/tests/external/miniaudio deleted file mode 160000 index d1a166c..0000000 --- a/source/engine/thirdparty/dr_libs/tests/external/miniaudio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d1a166c83ab445b1c14bc83d37c84e18d172e5f5 diff --git a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_common.c b/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_common.c deleted file mode 100644 index 45342b9..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_common.c +++ /dev/null @@ -1,332 +0,0 @@ -#define DR_FLAC_IMPLEMENTATION -#include "../../dr_flac.h" - -/* libFLAC has a warning in their header. *sigh*. */ -#if defined(__GNUC__) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" - #if defined(__clang__) - #pragma GCC diagnostic ignored "-Wc99-extensions" - #endif -#endif -#include -#if defined(__GNUC__) - #pragma GCC diagnostic pop -#endif - -#include "../common/dr_common.c" - - -/* -The libflac object is used to make it easier to compare things against the reference implementation. I don't think -libFLAC's API is all that easy to use or intuitive so I'm wrapping it. This is deliberately simple. It decodes the -entire file into memory upon initialization. -*/ -typedef struct -{ - drflac_int32* pPCMFrames; /* Interleaved. */ - drflac_uint64 pcmFrameCount; - drflac_uint64 pcmFrameCap; /* The capacity of the pPCMFrames buffer in PCM frames. */ - drflac_uint32 channels; - drflac_uint32 sampleRate; - drflac_uint64 currentPCMFrame; /* The index of the PCM frame the decoder is currently sitting on. */ - double decodeTimeInSeconds; /* The total amount of time it took to decode the file. This is used for profiling. */ - drflac_uint8* pFileData; - size_t fileSizeInBytes; - size_t fileReadPos; -} libflac; - -static FLAC__StreamDecoderReadStatus libflac__read_callback(const FLAC__StreamDecoder *pStreamDecoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - libflac* pDecoder = (libflac*)client_data; - size_t bytesToRead = *bytes; - size_t bytesRemaining = pDecoder->fileSizeInBytes - pDecoder->fileReadPos; - - (void)pStreamDecoder; - - if (bytesToRead > bytesRemaining) { - bytesToRead = bytesRemaining; - } - - if (bytesToRead > 0) { - memcpy(buffer, pDecoder->pFileData + pDecoder->fileReadPos, bytesToRead); - pDecoder->fileReadPos += bytesToRead; - } - - *bytes = bytesToRead; - return (bytesToRead == 0 && bytesRemaining == 0) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; -} - -static FLAC__StreamDecoderWriteStatus libflac__write_callback(const FLAC__StreamDecoder *pStreamDecoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - libflac* pDecoder = (libflac*)client_data; - drflac_uint32 pcmFramesInFLACFrame; - drflac_int32* pNextSampleInNewFrame; - drflac_uint32 i, j; - - (void)pStreamDecoder; - - pcmFramesInFLACFrame = frame->header.blocksize; - - /* Make sure there's room in the buffer. */ - if ((pDecoder->pcmFrameCount + pcmFramesInFLACFrame) > pDecoder->pcmFrameCap) { - drflac_int32* pNewPCMFrames; - - pDecoder->pcmFrameCap *= 2; - if (pDecoder->pcmFrameCap < (pDecoder->pcmFrameCount + pcmFramesInFLACFrame)) { - pDecoder->pcmFrameCap = (pDecoder->pcmFrameCount + pcmFramesInFLACFrame); - } - - pNewPCMFrames = (drflac_int32*)realloc(pDecoder->pPCMFrames, (size_t)(pDecoder->pcmFrameCap * pDecoder->channels * sizeof(drflac_int32))); - if (pNewPCMFrames == NULL) { - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - - pDecoder->pPCMFrames = pNewPCMFrames; - } - - /* Make sure the decoded samples are interleaved. */ - pNextSampleInNewFrame = pDecoder->pPCMFrames + (pDecoder->pcmFrameCount * pDecoder->channels); - for (i = 0; i < pcmFramesInFLACFrame; i += 1) { - for (j = 0; j < pDecoder->channels; ++j) { - *pNextSampleInNewFrame++ = buffer[j][i] << (32 - frame->header.bits_per_sample); - } - } - - pDecoder->pcmFrameCount += pcmFramesInFLACFrame; - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -static FLAC__StreamDecoderLengthStatus libflac__length_callback(const FLAC__StreamDecoder *pStreamDecoder, FLAC__uint64 *stream_length, void *client_data) -{ - libflac* pDecoder = (libflac*)client_data; - - (void)pStreamDecoder; - - *stream_length = pDecoder->fileSizeInBytes; - return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; -} - -static void libflac__metadata_callback(const FLAC__StreamDecoder *pStreamDecoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - libflac* pDecoder = (libflac*)client_data; - - (void)pStreamDecoder; - - /* Here is where we initialize the buffer for the decoded data. */ - if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { - pDecoder->pcmFrameCount = 0; /* Always set this to 0. Don't be tempted to set it to metadata->data.stream_info.total_samples. It's increment in libflac__write_callback. */ - pDecoder->channels = metadata->data.stream_info.channels; - pDecoder->sampleRate = metadata->data.stream_info.sample_rate; - - /* Allocate an initial block of memory if we know the total size. */ - if (metadata->data.stream_info.total_samples > 0) { - pDecoder->pcmFrameCap = metadata->data.stream_info.total_samples; - pDecoder->pPCMFrames = (drflac_int32*)malloc((size_t)(pDecoder->pcmFrameCap * pDecoder->channels * sizeof(drflac_int32))); - if (pDecoder->pPCMFrames != NULL) { - DRFLAC_ZERO_MEMORY(pDecoder->pPCMFrames, (size_t)(pDecoder->pcmFrameCap * pDecoder->channels * sizeof(drflac_int32))); - } - } - } -} - -static void libflac__error_callback(const FLAC__StreamDecoder *pStreamDecoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - (void)pStreamDecoder; - (void)status; - (void)client_data; -} - -/* -Initializes a libflac object. - -This will perform a full decode of the file using libFLAC. The time it takes to decode the file will be stored in decodeTimeInSeconds -for the purpose of profiling. The decoding process will load the entire file into memory before calling into libFLAC. This way profiling -will exclude any IO time. -*/ -drflac_result libflac_init_file(const char* pFilePath, libflac* pDecoder) -{ - FLAC__StreamDecoder* pStreamDecoder; - FLAC__bool libflacResult; - FLAC__StreamDecoderInitStatus libflacStatus; - double decodeTimeBeg; - double decodeTimeEnd; - - DRFLAC_ZERO_MEMORY(pDecoder, sizeof(*pDecoder)); - - pDecoder->pFileData = (drflac_uint8*)dr_open_and_read_file(pFilePath, &pDecoder->fileSizeInBytes); - if (pDecoder->pFileData == NULL) { - return DRFLAC_ERROR; /* Failed to open the file. */ - } - - - /* Initialize the libFLAC decoder. */ - pStreamDecoder = FLAC__stream_decoder_new(); - if (pDecoder == NULL) { - return DRFLAC_ERROR; /* Failed to create a new stream decoder. Out of memory. */ - } - - if (dr_extension_equal(pFilePath, "ogg") || dr_extension_equal(pFilePath, "oga") || dr_extension_equal(pFilePath, "ogv")) { - libflacStatus = FLAC__stream_decoder_init_ogg_stream(pStreamDecoder, libflac__read_callback, NULL, NULL, libflac__length_callback, NULL, libflac__write_callback, libflac__metadata_callback, libflac__error_callback, pDecoder); - } else { - libflacStatus = FLAC__stream_decoder_init_stream(pStreamDecoder, libflac__read_callback, NULL, NULL, libflac__length_callback, NULL, libflac__write_callback, libflac__metadata_callback, libflac__error_callback, pDecoder); - } - - if (libflacStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - FLAC__stream_decoder_delete(pStreamDecoder); - free(pDecoder->pFileData); - return DRFLAC_ERROR; /* Failed to initialize the stream. */ - } - - /* Read past the metadata first. This will fire the libflac__metadata_callback which will do a bit of initialization for us. */ - libflacResult = FLAC__stream_decoder_process_until_end_of_metadata(pStreamDecoder); - if (libflacResult == DRFLAC_FALSE) { - FLAC__stream_decoder_delete(pStreamDecoder); - free(pDecoder->pFileData); - return DRFLAC_ERROR; /* Failed to read metadata from the FLAC stream. */ - } - - /* Now we can just decode the entire file. */ - decodeTimeBeg = dr_timer_now(); - libflacResult = FLAC__stream_decoder_process_until_end_of_stream(pStreamDecoder); - decodeTimeEnd = dr_timer_now(); - - pDecoder->decodeTimeInSeconds = decodeTimeEnd - decodeTimeBeg; - - /* We're done with the libFLAC decoder. */ - FLAC__stream_decoder_delete(pStreamDecoder); - pStreamDecoder = NULL; - - - /* Free the file data. */ - free(pDecoder->pFileData); - pDecoder->pFileData = NULL; - pDecoder->fileSizeInBytes = 0; - pDecoder->fileReadPos = 0; - - if (libflacResult == DRFLAC_FALSE) { - return DRFLAC_ERROR; /* Some error ocurred while decoding. */ - } - - return DRFLAC_SUCCESS; -} - -void libflac_uninit(libflac* pDecoder) -{ - if (pDecoder == NULL) { - return; - } - - free(pDecoder->pPCMFrames); -} - -drflac_uint64 libflac_read_pcm_frames_s32(libflac* pDecoder, drflac_uint64 framesToRead, drflac_int32* pBufferOut) -{ - drflac_uint64 pcmFramesRemaining; - - if (pDecoder == NULL) { - return 0; - } - - pcmFramesRemaining = pDecoder->pcmFrameCount - pDecoder->currentPCMFrame; - if (framesToRead > pcmFramesRemaining) { - framesToRead = pcmFramesRemaining; - } - - if (framesToRead == 0) { - return 0; - } - - DRFLAC_COPY_MEMORY(pBufferOut, pDecoder->pPCMFrames + (pDecoder->currentPCMFrame * pDecoder->channels), (size_t)(framesToRead * pDecoder->channels * sizeof(drflac_int32))); - pDecoder->currentPCMFrame += framesToRead; - - return framesToRead; -} - -drflac_uint64 libflac_read_pcm_frames_f32(libflac* pDecoder, drflac_uint64 framesToRead, float* pBufferOut) -{ - drflac_uint64 pcmFramesRemaining; - - if (pDecoder == NULL) { - return 0; - } - - pcmFramesRemaining = pDecoder->pcmFrameCount - pDecoder->currentPCMFrame; - if (framesToRead > pcmFramesRemaining) { - framesToRead = pcmFramesRemaining; - } - - if (framesToRead == 0) { - return 0; - } - - /* s32 to f32 */ - dr_pcm_s32_to_f32(pBufferOut, pDecoder->pPCMFrames + (pDecoder->currentPCMFrame * pDecoder->channels), framesToRead * pDecoder->channels); - pDecoder->currentPCMFrame += framesToRead; - - return framesToRead; -} - -drflac_uint64 libflac_read_pcm_frames_s16(libflac* pDecoder, drflac_uint64 framesToRead, drflac_int16* pBufferOut) -{ - drflac_uint64 pcmFramesRemaining; - - if (pDecoder == NULL) { - return 0; - } - - pcmFramesRemaining = pDecoder->pcmFrameCount - pDecoder->currentPCMFrame; - if (framesToRead > pcmFramesRemaining) { - framesToRead = pcmFramesRemaining; - } - - if (framesToRead == 0) { - return 0; - } - - /* s32 to f32 */ - dr_pcm_s32_to_s16(pBufferOut, pDecoder->pPCMFrames + (pDecoder->currentPCMFrame * pDecoder->channels), framesToRead * pDecoder->channels); - pDecoder->currentPCMFrame += framesToRead; - - return framesToRead; -} - -drflac_bool32 libflac_seek_to_pcm_frame(libflac* pDecoder, drflac_uint64 targetPCMFrameIndex) -{ - if (pDecoder == NULL) { - return DRFLAC_FALSE; - } - - if (targetPCMFrameIndex > pDecoder->pcmFrameCount) { - return DRFLAC_FALSE; /* Trying to seek too far forward. */ - } - - pDecoder->currentPCMFrame = targetPCMFrameIndex; - - return DRFLAC_TRUE; -} - - -/* Helper for printing CPU caps from dr_flac. */ -void print_cpu_caps() -{ -#if defined(DRFLAC_64BIT) - printf("64 Bit\n"); -#else - printf("32 Bit\n"); -#endif - - drflac__init_cpu_caps(); - -#if defined(DRFLAC_X86) || defined(DRFLAC_X64) - #if defined(DRFLAC_X64) - printf("Architecture: x64\n"); - #else - printf("Architecture: x86\n"); - #endif - printf("Has SSE2: %s\n", drflac_has_sse2() ? "YES" : "NO"); - printf("Has SSE4.1: %s\n", drflac_has_sse41() ? "YES" : "NO"); - printf("Has LZCNT: %s\n", drflac__is_lzcnt_supported() ? "YES" : "NO"); -#endif -} diff --git a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_decoding.c b/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_decoding.c deleted file mode 100644 index fbaf413..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_decoding.c +++ /dev/null @@ -1,825 +0,0 @@ -/*#define DR_FLAC_NO_CRC*/ -/*#define DR_FLAC_NO_SIMD*/ -/*#define DR_FLAC_BUFFER_SIZE 4096*/ -#include "dr_flac_common.c" - -#define FILE_NAME_WIDTH 40 -#define NUMBER_WIDTH 10 -#define TABLE_MARGIN 2 - -#define DEFAULT_SOURCE_DIR "testvectors/flac/testbench" - -drflac_result decode_test__read_and_compare_pcm_frames_s32(libflac* pLibFlac, drflac* pFlac, drflac_uint64 pcmFrameCount, drflac_int32* pPCMFrames_libflac, drflac_int32* pPCMFrames_drflac) -{ - drflac_uint64 pcmFrameCount_libflac; - drflac_uint64 pcmFrameCount_drflac; - drflac_uint64 iPCMFrame; - - /* To test decoding we just read a number of PCM frames from each decoder and compare. */ - pcmFrameCount_libflac = libflac_read_pcm_frames_s32(pLibFlac, pcmFrameCount, pPCMFrames_libflac); - pcmFrameCount_drflac = drflac_read_pcm_frames_s32(pFlac, pcmFrameCount, pPCMFrames_drflac); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libflac != pcmFrameCount_drflac) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libFLAC=%d, dr_flac=%d", (int)pcmFrameCount, (int)pcmFrameCount_libflac, (int)pcmFrameCount_drflac); - return DRFLAC_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRFLAC_ASSERT(pcmFrameCount_libflac == pcmFrameCount_drflac); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libflac; iPCMFrame += 1) { - drflac_int32* pPCMFrame_libflac = pPCMFrames_libflac + (iPCMFrame * pLibFlac->channels); - drflac_int32* pPCMFrame_drflac = pPCMFrames_drflac + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if (pPCMFrame_libflac[iChannel] != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d\n", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - /* Done. */ - return DRFLAC_SUCCESS; -} - -drflac_result decode_test__read_and_compare_pcm_frame_chunks_s32(libflac* pLibFlac, drflac* pFlac, drflac_uint64 pcmFrameChunkSize) -{ - drflac_result result = DRFLAC_SUCCESS; - drflac_uint64 iPCMFrame; - drflac_int32* pPCMFrames_libflac; - drflac_int32* pPCMFrames_drflac; - - /* Make sure the decoder's are seeked back to the start first. */ - drflac_seek_to_pcm_frame(pFlac, 0); - libflac_seek_to_pcm_frame(pLibFlac, 0); - - pPCMFrames_libflac = (drflac_int32*)malloc((size_t)(pcmFrameChunkSize * pLibFlac->channels * sizeof(drflac_int32))); - if (pPCMFrames_libflac == NULL) { - printf(" [libFLAC] Out of memory"); - return DRFLAC_ERROR; - } - - pPCMFrames_drflac = (drflac_int32*)malloc((size_t)(pcmFrameChunkSize * pLibFlac->channels * sizeof(drflac_int32))); - if (pPCMFrames_drflac == NULL) { - free(pPCMFrames_libflac); - printf(" [dr_flac] Out of memory"); - return DRFLAC_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pLibFlac->pcmFrameCount; iPCMFrame += pcmFrameChunkSize) { - result = decode_test__read_and_compare_pcm_frames_s32(pLibFlac, pFlac, pcmFrameChunkSize, pPCMFrames_libflac, pPCMFrames_drflac); - if (result != DRFLAC_SUCCESS) { - break; - } - } - - free(pPCMFrames_libflac); - free(pPCMFrames_drflac); - - return result; -} - - -drflac_result decode_test__read_and_compare_pcm_frames_f32(libflac* pLibFlac, drflac* pFlac, drflac_uint64 pcmFrameCount, float* pPCMFrames_libflac, float* pPCMFrames_drflac) -{ - drflac_uint64 pcmFrameCount_libflac; - drflac_uint64 pcmFrameCount_drflac; - drflac_uint64 iPCMFrame; - - /* To test decoding we just read a number of PCM frames from each decoder and compare. */ - pcmFrameCount_libflac = libflac_read_pcm_frames_f32(pLibFlac, pcmFrameCount, pPCMFrames_libflac); - pcmFrameCount_drflac = drflac_read_pcm_frames_f32(pFlac, pcmFrameCount, pPCMFrames_drflac); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libflac != pcmFrameCount_drflac) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libFLAC=%d, dr_flac=%d", (int)pcmFrameCount, (int)pLibFlac->currentPCMFrame, (int)pFlac->currentPCMFrame); - return DRFLAC_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRFLAC_ASSERT(pcmFrameCount_libflac == pcmFrameCount_drflac); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libflac; iPCMFrame += 1) { - float* pPCMFrame_libflac = pPCMFrames_libflac + (iPCMFrame * pLibFlac->channels); - float* pPCMFrame_drflac = pPCMFrames_drflac + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if (pPCMFrame_libflac[iChannel] != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - /* Done. */ - return DRFLAC_SUCCESS; -} - -drflac_result decode_test__read_and_compare_pcm_frame_chunks_f32(libflac* pLibFlac, drflac* pFlac, drflac_uint64 pcmFrameChunkSize) -{ - drflac_result result = DRFLAC_SUCCESS; - drflac_uint64 iPCMFrame; - float* pPCMFrames_libflac; - float* pPCMFrames_drflac; - - /* Make sure the decoder's are seeked back to the start first. */ - drflac_seek_to_pcm_frame(pFlac, 0); - libflac_seek_to_pcm_frame(pLibFlac, 0); - - pPCMFrames_libflac = (float*)malloc((size_t)(pcmFrameChunkSize * pLibFlac->channels * sizeof(float))); - if (pPCMFrames_libflac == NULL) { - printf(" [libFLAC] Out of memory"); - return DRFLAC_ERROR; - } - - pPCMFrames_drflac = (float*)malloc((size_t)(pcmFrameChunkSize * pLibFlac->channels * sizeof(float))); - if (pPCMFrames_drflac == NULL) { - free(pPCMFrames_libflac); - printf(" [dr_flac] Out of memory"); - return DRFLAC_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pLibFlac->pcmFrameCount; iPCMFrame += pcmFrameChunkSize) { - result = decode_test__read_and_compare_pcm_frames_f32(pLibFlac, pFlac, pcmFrameChunkSize, pPCMFrames_libflac, pPCMFrames_drflac); - if (result != DRFLAC_SUCCESS) { - break; - } - } - - free(pPCMFrames_libflac); - free(pPCMFrames_drflac); - - return result; -} - - -drflac_result decode_test__read_and_compare_pcm_frames_s16(libflac* pLibFlac, drflac* pFlac, drflac_uint64 pcmFrameCount, drflac_int16* pPCMFrames_libflac, drflac_int16* pPCMFrames_drflac) -{ - drflac_uint64 pcmFrameCount_libflac; - drflac_uint64 pcmFrameCount_drflac; - drflac_uint64 iPCMFrame; - - /* To test decoding we just read a number of PCM frames from each decoder and compare. */ - pcmFrameCount_libflac = libflac_read_pcm_frames_s16(pLibFlac, pcmFrameCount, pPCMFrames_libflac); - pcmFrameCount_drflac = drflac_read_pcm_frames_s16(pFlac, pcmFrameCount, pPCMFrames_drflac); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libflac != pcmFrameCount_drflac) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libFLAC=%d, dr_flac=%d", (int)pcmFrameCount, (int)pLibFlac->currentPCMFrame, (int)pFlac->currentPCMFrame); - return DRFLAC_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRFLAC_ASSERT(pcmFrameCount_libflac == pcmFrameCount_drflac); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libflac; iPCMFrame += 1) { - drflac_int16* pPCMFrame_libflac = pPCMFrames_libflac + (iPCMFrame * pLibFlac->channels); - drflac_int16* pPCMFrame_drflac = pPCMFrames_drflac + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if (pPCMFrame_libflac[iChannel] != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - /* Done. */ - return DRFLAC_SUCCESS; -} - -drflac_result decode_test__read_and_compare_pcm_frame_chunks_s16(libflac* pLibFlac, drflac* pFlac, drflac_uint64 pcmFrameChunkSize) -{ - drflac_result result = DRFLAC_SUCCESS; - drflac_uint64 iPCMFrame; - drflac_int16* pPCMFrames_libflac; - drflac_int16* pPCMFrames_drflac; - - /* Make sure the decoder's are seeked back to the start first. */ - drflac_seek_to_pcm_frame(pFlac, 0); - libflac_seek_to_pcm_frame(pLibFlac, 0); - - pPCMFrames_libflac = (drflac_int16*)malloc((size_t)(pcmFrameChunkSize * pLibFlac->channels * sizeof(drflac_int16))); - if (pPCMFrames_libflac == NULL) { - printf(" [libFLAC] Out of memory"); - return DRFLAC_ERROR; - } - - pPCMFrames_drflac = (drflac_int16*)malloc((size_t)(pcmFrameChunkSize * pLibFlac->channels * sizeof(drflac_int16))); - if (pPCMFrames_drflac == NULL) { - free(pPCMFrames_libflac); - printf(" [dr_flac] Out of memory"); - return DRFLAC_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pLibFlac->pcmFrameCount; iPCMFrame += pcmFrameChunkSize) { - result = decode_test__read_and_compare_pcm_frames_s16(pLibFlac, pFlac, pcmFrameChunkSize, pPCMFrames_libflac, pPCMFrames_drflac); - if (result != DRFLAC_SUCCESS) { - break; - } - } - - free(pPCMFrames_libflac); - free(pPCMFrames_drflac); - - return result; -} - - - -drflac_result decode_test_file_s32(libflac* pLibFlac, drflac* pFlac) -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Start with reading the entire file in one go. */ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s32(pLibFlac, pFlac, pLibFlac->pcmFrameCount); - } - - /* Now try with reading one PCM frame at a time.*/ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s32(pLibFlac, pFlac, 1); - } - - /* Now test FLAC frame boundaries. */ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s32(pLibFlac, pFlac, (pFlac->maxBlockSizeInPCMFrames > 0) ? pFlac->maxBlockSizeInPCMFrames : 4096); - } - - return result; -} - -drflac_result decode_test_file_f32(libflac* pLibFlac, drflac* pFlac) -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Start with reading the entire file in one go. */ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_f32(pLibFlac, pFlac, pLibFlac->pcmFrameCount); - } - - /* Now try with reading one PCM frame at a time.*/ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_f32(pLibFlac, pFlac, 1); - } - - /* Now test FLAC frame boundaries. */ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_f32(pLibFlac, pFlac, (pFlac->maxBlockSizeInPCMFrames > 0) ? pFlac->maxBlockSizeInPCMFrames : 4096); - } - - return result; -} - -drflac_result decode_test_file_s16(libflac* pLibFlac, drflac* pFlac) -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Start with reading the entire file in one go. */ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s16(pLibFlac, pFlac, pLibFlac->pcmFrameCount); - } - - /* Now try with reading one PCM frame at a time.*/ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s16(pLibFlac, pFlac, 1); - } - - /* Now test FLAC frame boundaries. */ - if (result == DRFLAC_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s16(pLibFlac, pFlac, (pFlac->maxBlockSizeInPCMFrames > 0) ? pFlac->maxBlockSizeInPCMFrames : 4096); - } - - return result; -} - -static void on_meta(void* pUserData, drflac_metadata* pMetadata) -{ - (void)pUserData; - - switch (pMetadata->type) - { - case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: - { - /* - This section is here just to make it easy to test cuesheets. It's not designed to integrate cleanly with the output of this program - so I'm just selectively enabling and disabling this section as required. - */ - #if 0 - drflac_cuesheet_track_iterator i; - drflac_cuesheet_track track; - - printf("Cuesheet Found. Track Count = %d\n", (int)pMetadata->data.cuesheet.trackCount); - - drflac_init_cuesheet_track_iterator(&i, pMetadata->data.cuesheet.trackCount, pMetadata->data.cuesheet.pTrackData); - while (drflac_next_cuesheet_track(&i, &track)) { - drflac_uint32 iTrackIndex; - - printf("Cuesheet Track %d. Index Count = %d:\n", track.trackNumber, track.indexCount); - for (iTrackIndex = 0; iTrackIndex < track.indexCount; iTrackIndex += 1) { - printf(" Index %d - Offset %llu\n", iTrackIndex, track.pIndexPoints[iTrackIndex].offset); - } - } - #endif - } break; - } -} - -drflac_result decode_test_file(const char* pFilePath) -{ - /* To test seeking we just seek to our target PCM frame and then decode whatever is remaining and compare it against libFLAC. */ - drflac_result result; - libflac libflac; - drflac* pFlac; - - dr_printf_fixed_with_margin(FILE_NAME_WIDTH, TABLE_MARGIN, "%s", dr_path_file_name(pFilePath)); - - /* First load the decoder from libFLAC. */ - result = libflac_init_file(pFilePath, &libflac); - if (result != DRFLAC_SUCCESS) { - printf(" Failed to open via libFLAC."); - return result; - } - - /* Now load from dr_flac. */ - pFlac = drflac_open_file_with_metadata(pFilePath, on_meta, NULL, NULL); - if (pFlac == NULL) { - printf(" Failed to open via dr_flac."); - libflac_uninit(&libflac); - return DRFLAC_ERROR; /* Failed to load dr_flac decoder. */ - } - - /* At this point we should have both libFLAC and dr_flac decoders open. We can now perform identical operations on each of them and compare. */ - result = decode_test_file_s32(&libflac, pFlac); - if (result != DRFLAC_SUCCESS) { - drflac_close(pFlac); - libflac_uninit(&libflac); - return result; - } - - result = decode_test_file_f32(&libflac, pFlac); - if (result != DRFLAC_SUCCESS) { - drflac_close(pFlac); - libflac_uninit(&libflac); - return result; - } - - result = decode_test_file_s16(&libflac, pFlac); - if (result != DRFLAC_SUCCESS) { - drflac_close(pFlac); - libflac_uninit(&libflac); - return result; - } - - - /* We're done with our decoders. */ - drflac_close(pFlac); - libflac_uninit(&libflac); - - if (result == DRFLAC_SUCCESS) { - printf(" Passed"); - } - - return result; -} - -drflac_result decode_test_directory(const char* pDirectoryPath) -{ - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - - dr_printf_fixed(FILE_NAME_WIDTH, "%s", pDirectoryPath); - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "RESULT"); - printf("\n"); - - pFile = dr_file_iterator_begin(pDirectoryPath, &iteratorState); - while (pFile != NULL) { - drflac_result result; - - /* Skip directories for now, but we may want to look at doing recursive file iteration. */ - if (!pFile->isDirectory) { - result = decode_test_file(pFile->absolutePath); - (void)result; - - printf("\n"); - } - - pFile = dr_file_iterator_next(pFile); - } - - return DRFLAC_SUCCESS; -} - -drflac_result decode_test() -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Directories. */ - { - result = decode_test_directory(DEFAULT_SOURCE_DIR); - (void)result; - } - - return result; -} - - - -drflac_result open_and_read_test_file_s32(libflac* pLibFlac, const char* pFilePath) -{ - drflac_int32* pPCMFrames; - drflac_uint64 pcmFrameCount; - drflac_uint32 channels; - drflac_uint32 sampleRate; - drflac_uint64 iPCMFrame; - - pPCMFrames = drflac_open_file_and_read_pcm_frames_s32(pFilePath, &channels, &sampleRate, &pcmFrameCount, NULL); - if (pPCMFrames == NULL) { - printf(" drflac_open_and_read failed."); - return DRFLAC_ERROR; /* Error decoding */ - } - - if (pcmFrameCount != pLibFlac->pcmFrameCount) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libFLAC=%d, dr_flac=%d", (int)pcmFrameCount, (int)pLibFlac->currentPCMFrame, (int)pcmFrameCount); - drflac_free(pPCMFrames, NULL); - return DRFLAC_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pLibFlac->pcmFrameCount; iPCMFrame += 1) { - drflac_int32* pPCMFrame_libflac = pLibFlac->pPCMFrames + (iPCMFrame * pLibFlac->channels); - drflac_int32* pPCMFrame_drflac = pPCMFrames + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if (pPCMFrame_libflac[iChannel] != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - drflac_free(pPCMFrames, NULL); - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - drflac_free(pPCMFrames, NULL); - return DRFLAC_SUCCESS; -} - -drflac_result open_and_read_test_file_f32(libflac* pLibFlac, const char* pFilePath) -{ - float* pPCMFrames; - drflac_uint64 pcmFrameCount; - drflac_uint32 channels; - drflac_uint32 sampleRate; - drflac_uint64 iPCMFrame; - - pPCMFrames = drflac_open_file_and_read_pcm_frames_f32(pFilePath, &channels, &sampleRate, &pcmFrameCount, NULL); - if (pPCMFrames == NULL) { - printf(" drflac_open_and_read failed."); - return DRFLAC_ERROR; /* Error decoding */ - } - - if (pcmFrameCount != pLibFlac->pcmFrameCount) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libFLAC=%d, dr_flac=%d", (int)pcmFrameCount, (int)pLibFlac->currentPCMFrame, (int)pcmFrameCount); - drflac_free(pPCMFrames, NULL); - return DRFLAC_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pLibFlac->pcmFrameCount; iPCMFrame += 1) { - drflac_int32* pPCMFrame_libflac = pLibFlac->pPCMFrames + (iPCMFrame * pLibFlac->channels); - float* pPCMFrame_drflac = pPCMFrames + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if ((pPCMFrame_libflac[iChannel] / 2147483648.0) != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - drflac_free(pPCMFrames, NULL); - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - drflac_free(pPCMFrames, NULL); - return DRFLAC_SUCCESS; -} - -drflac_result open_and_read_test_file_s16(libflac* pLibFlac, const char* pFilePath) -{ - drflac_int16* pPCMFrames; - drflac_uint64 pcmFrameCount; - drflac_uint32 channels; - drflac_uint32 sampleRate; - drflac_uint64 iPCMFrame; - - pPCMFrames = drflac_open_file_and_read_pcm_frames_s16(pFilePath, &channels, &sampleRate, &pcmFrameCount, NULL); - if (pPCMFrames == NULL) { - printf(" drflac_open_and_read failed."); - return DRFLAC_ERROR; /* Error decoding */ - } - - if (pcmFrameCount != pLibFlac->pcmFrameCount) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libFLAC=%d, dr_flac=%d", (int)pcmFrameCount, (int)pLibFlac->currentPCMFrame, (int)pcmFrameCount); - drflac_free(pPCMFrames, NULL); - return DRFLAC_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pLibFlac->pcmFrameCount; iPCMFrame += 1) { - drflac_int32* pPCMFrame_libflac = pLibFlac->pPCMFrames + (iPCMFrame * pLibFlac->channels); - drflac_int16* pPCMFrame_drflac = pPCMFrames + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if ((pPCMFrame_libflac[iChannel] >> 16) != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - drflac_free(pPCMFrames, NULL); - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - drflac_free(pPCMFrames, NULL); - return DRFLAC_SUCCESS; -} - -drflac_result open_and_read_test_file(const char* pFilePath) -{ - drflac_result result; - libflac libflac; - - dr_printf_fixed_with_margin(FILE_NAME_WIDTH, TABLE_MARGIN, "%s", dr_path_file_name(pFilePath)); - - /* First load the decoder from libFLAC. */ - result = libflac_init_file(pFilePath, &libflac); - if (result != DRFLAC_SUCCESS) { - printf(" Failed to open via libFLAC."); - return result; - } - - result = open_and_read_test_file_s32(&libflac, pFilePath); - if (result != DRFLAC_SUCCESS) { - return result; - } - - open_and_read_test_file_f32(&libflac, pFilePath); - if (result != DRFLAC_SUCCESS) { - return result; - } - - open_and_read_test_file_s16(&libflac, pFilePath); - if (result != DRFLAC_SUCCESS) { - return result; - } - - libflac_uninit(&libflac); - - if (result == DRFLAC_SUCCESS) { - printf(" Passed"); - } - - return result; -} - -drflac_result open_and_read_test_directory(const char* pDirectoryPath) -{ - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - - dr_printf_fixed(FILE_NAME_WIDTH, "%s", pDirectoryPath); - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "RESULT"); - printf("\n"); - - pFile = dr_file_iterator_begin(pDirectoryPath, &iteratorState); - while (pFile != NULL) { - drflac_result result; - - /* Skip directories for now, but we may want to look at doing recursive file iteration. */ - if (!pFile->isDirectory) { - result = open_and_read_test_file(pFile->absolutePath); - (void)result; - - printf("\n"); - } - - pFile = dr_file_iterator_next(pFile); - } - - return DRFLAC_SUCCESS; -} - -drflac_result open_and_read_test() -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Directories. */ - { - result = open_and_read_test_directory(DEFAULT_SOURCE_DIR); - (void)result; - } - - return result; -} - - - -drflac_result decode_profiling_file(const char* pFilePath) -{ - drflac_result result; - libflac libflac; - drflac* pFlac; - drflac_int32* pTempBuffer; - double decodeTimeBeg; - double decodeTimeEnd; - double drflacDecodeTimeInSeconds; - void* pFileData; - size_t fileSizeInBytes; - - dr_printf_fixed_with_margin(FILE_NAME_WIDTH, 2, "%s", dr_path_file_name(pFilePath)); - - /* libFLAC */ - result = libflac_init_file(pFilePath, &libflac); - if (result != DRFLAC_SUCCESS) { - printf(" [libFLAC] Failed to load file"); - return result; - } - - /* dr_flac */ - pFileData = dr_open_and_read_file(pFilePath, &fileSizeInBytes); - if (pFileData == NULL) { - printf(" Failed to load file"); - return DRFLAC_ERROR; /* Failed to open the file. */ - } - - pFlac = drflac_open_memory(pFileData, fileSizeInBytes, NULL); - if (pFlac == NULL) { - free(pFileData); - printf(" [dr_flac] Failed to load file."); - return DRFLAC_ERROR; - } - - /* libFLAC decode time. */ - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "%.2fms", libflac.decodeTimeInSeconds*1000); - - /* dr_flac decode time. */ - pTempBuffer = (drflac_int32*)malloc((size_t)(libflac.pcmFrameCount * libflac.channels * sizeof(drflac_int32))); - if (pTempBuffer == NULL) { - libflac_uninit(&libflac); - drflac_close(pFlac); - free(pFileData); - printf(" Out of memory."); - return DRFLAC_ERROR; /* Out of memory. */ - } - - DRFLAC_ZERO_MEMORY(pTempBuffer, (size_t)(libflac.pcmFrameCount * libflac.channels * sizeof(drflac_int32))); - - decodeTimeBeg = dr_timer_now(); - drflac_read_pcm_frames_s32(pFlac, libflac.pcmFrameCount, pTempBuffer); - decodeTimeEnd = dr_timer_now(); - - free(pTempBuffer); - free(pFileData); - - drflacDecodeTimeInSeconds = decodeTimeEnd - decodeTimeBeg; - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "%.2fms", drflacDecodeTimeInSeconds*1000); - - /* Difference. */ - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "%d%%", (int)(drflacDecodeTimeInSeconds/libflac.decodeTimeInSeconds * 100)); - - libflac_uninit(&libflac); - drflac_close(pFlac); - - return DRFLAC_SUCCESS; -} - -drflac_result decode_profiling_directory(const char* pDirectoryPath) -{ - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - drflac_bool32 foundError = DRFLAC_FALSE; - - dr_printf_fixed(FILE_NAME_WIDTH, "%s", pDirectoryPath); - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "libFLAC"); - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "dr_flac"); - printf("\n"); - - pFile = dr_file_iterator_begin(pDirectoryPath, &iteratorState); - while (pFile != NULL) { - drflac_result result; - - /* Skip directories for now, but we may want to look at doing recursive file iteration. */ - if (!pFile->isDirectory) { - result = decode_profiling_file(pFile->absolutePath); - if (result != DRFLAC_SUCCESS) { - foundError = DRFLAC_TRUE; - } - - printf("\n"); - } - - pFile = dr_file_iterator_next(pFile); - } - - return (foundError) ? DRFLAC_ERROR : DRFLAC_SUCCESS; -} - -drflac_result decode_profiling() -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Directories. */ - { - result = decode_profiling_directory(DEFAULT_SOURCE_DIR); - } - - return result; -} - - -int main(int argc, char** argv) -{ - drflac_result result = DRFLAC_SUCCESS; - drflac_bool32 doTesting = DRFLAC_TRUE; - drflac_bool32 doProfiling = DRFLAC_TRUE; - - /* This program has two main parts. The first is just a normal functionality test. The second is a profiling of the different seeking methods. */ - if (dr_argv_is_set(argc, argv, "--onlyprofile")) { - doTesting = DRFLAC_FALSE; - } - - print_cpu_caps(); - - /* Exhaustive seek test. */ - if (doTesting) { - printf("=======================================================================\n"); - printf("DECODE TESTING\n"); - printf("=======================================================================\n"); - result = decode_test(); - if (result != DRFLAC_SUCCESS) { - return (int)result; /* Don't continue if an error occurs during testing. */ - } - printf("\n"); - - printf("=======================================================================\n"); - printf("OPEN-AND-READ TESTING - drflac_open_*_and_read_pcm_frames_*()\n"); - printf("=======================================================================\n"); - result = open_and_read_test(); - if (result != DRFLAC_SUCCESS) { - return (int)result; /* Don't continue if an error occurs during testing. */ - } - printf("\n"); - } else { - printf("=======================================================================\n"); - printf("WARNING: Correctness Tests Disabled\n"); - printf("=======================================================================\n"); - } - - /* Profiling. */ - if (doProfiling) { - printf("=======================================================================\n"); - printf("DECODE PROFILING (LOWER IS BETTER)\n"); - printf("=======================================================================\n"); - result = decode_profiling(); - printf("\n"); - } - - /*getchar();*/ - return (int)result; -} diff --git a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_decoding.cpp b/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_decoding.cpp deleted file mode 100644 index 48d966c..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_decoding.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "dr_flac_decoding.c" diff --git a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_seeking.c b/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_seeking.c deleted file mode 100644 index 70494d6..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_seeking.c +++ /dev/null @@ -1,483 +0,0 @@ -/*#define DR_FLAC_NO_CRC*/ -#include "dr_flac_common.c" - -#define PROFILING_NAME_WIDTH 40 -#define PROFILING_NUMBER_WIDTH 10 -#define PROFILING_NUMBER_MARGIN 2 - -typedef struct -{ - double totalSeconds_BruteForce; - double totalSeconds_BinarySearch; - double totalSeconds_SeekTable; -} profiling_state; - -void profiling_state_init(profiling_state* pProfiling) -{ - DRFLAC_ZERO_MEMORY(pProfiling, sizeof(*pProfiling)); -} - -profiling_state profiling_state_sum(const profiling_state* pA, const profiling_state* pB) -{ - profiling_state result; - result.totalSeconds_BruteForce = pA->totalSeconds_BruteForce + pB->totalSeconds_BruteForce; - result.totalSeconds_BinarySearch = pA->totalSeconds_BinarySearch + pB->totalSeconds_BinarySearch; - result.totalSeconds_SeekTable = pA->totalSeconds_SeekTable + pB->totalSeconds_SeekTable; - - return result; -} - - -drflac_result seek_test_pcm_frame(libflac* pLibFlac, drflac* pFlac, drflac_uint64 targetPCMFrameIndex) -{ - drflac_bool32 seekResult; - drflac_uint64 pcmFrameCount_libflac; - drflac_uint64 pcmFrameCount_drflac; - drflac_int32* pPCMFrames_libflac; - drflac_int32* pPCMFrames_drflac; - drflac_uint64 iPCMFrame; - - if (pFlac->_noSeekTableSeek == DRFLAC_FALSE && pFlac->_noBinarySearchSeek == DRFLAC_TRUE && pFlac->_noBruteForceSeek == DRFLAC_TRUE) { - if (pFlac->seekpointCount == 0) { - printf(" No seek table"); - return DRFLAC_ERROR; - } - } - - /* - To test seeking we just seek to the PCM frame, and then decode the rest of the file. If the PCM frames we read - differs between the two implementations there's something wrong with one of them (probably dr_flac). - */ - seekResult = libflac_seek_to_pcm_frame(pLibFlac, targetPCMFrameIndex); - if (seekResult == DRFLAC_FALSE) { - printf(" [libFLAC] Failed to seek to PCM frame @ %d", (int)targetPCMFrameIndex); - return DRFLAC_ERROR; - } - - seekResult = drflac_seek_to_pcm_frame(pFlac, targetPCMFrameIndex); - if (seekResult == DRFLAC_FALSE) { - printf(" [dr_flac] Failed to seek to PCM frame @ %d", (int)targetPCMFrameIndex); - return DRFLAC_ERROR; - } - - if (pLibFlac->currentPCMFrame != pFlac->currentPCMFrame) { - printf(" Current PCM frame inconsistent @ %d: libFLAC=%d, dr_flac=%d", (int)targetPCMFrameIndex, (int)pLibFlac->currentPCMFrame, (int)pFlac->currentPCMFrame); - return DRFLAC_ERROR; - } - - /* - Now we decode the rest of the file and compare the samples. Note that we try reading the _entire_ file, not just the leftovers, to ensure we - haven't seeked too short. - */ - pPCMFrames_libflac = (drflac_int32*)malloc((size_t)(pLibFlac->pcmFrameCount * pLibFlac->channels * sizeof(drflac_int32))); - if (pPCMFrames_libflac == NULL) { - printf(" [libFLAC] Out of memory"); - return DRFLAC_ERROR; - } - pcmFrameCount_libflac = libflac_read_pcm_frames_s32(pLibFlac, pLibFlac->pcmFrameCount, pPCMFrames_libflac); - - pPCMFrames_drflac = (drflac_int32*)malloc((size_t)(pLibFlac->pcmFrameCount * pLibFlac->channels * sizeof(drflac_int32))); - if (pPCMFrames_drflac == NULL) { - free(pPCMFrames_libflac); - printf(" [dr_flac] Out of memory"); - return DRFLAC_ERROR; - } - pcmFrameCount_drflac = drflac_read_pcm_frames_s32(pFlac, pLibFlac->pcmFrameCount, pPCMFrames_drflac); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libflac != pcmFrameCount_drflac) { - free(pPCMFrames_drflac); - free(pPCMFrames_libflac); - printf(" Decoded frame counts differ @ %d: libFLAC=%d, dr_flac=%d", (int)targetPCMFrameIndex, (int)pLibFlac->currentPCMFrame, (int)pFlac->currentPCMFrame); - return DRFLAC_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRFLAC_ASSERT(pcmFrameCount_libflac == pcmFrameCount_drflac); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libflac; iPCMFrame += 1) { - drflac_int32* pPCMFrame_libflac = pPCMFrames_libflac + (iPCMFrame * pLibFlac->channels); - drflac_int32* pPCMFrame_drflac = pPCMFrames_drflac + (iPCMFrame * pLibFlac->channels); - drflac_uint32 iChannel; - drflac_bool32 hasError = DRFLAC_FALSE; - - for (iChannel = 0; iChannel < pLibFlac->channels; iChannel += 1) { - if (pPCMFrame_libflac[iChannel] != pPCMFrame_drflac[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: targetPCMFrameIndex=%d", (int)iPCMFrame, iChannel, (int)targetPCMFrameIndex); - hasError = DRFLAC_TRUE; - break; - } - } - - if (hasError) { - free(pPCMFrames_drflac); - free(pPCMFrames_libflac); - return DRFLAC_ERROR; /* Decoded frames do not match. */ - } - } - - - /* Done. */ - free(pPCMFrames_drflac); - free(pPCMFrames_libflac); - - return DRFLAC_SUCCESS; -} - -drflac_result seek_test_file(const char* pFilePath) -{ - /* To test seeking we just seek to our target PCM frame and then decode whatever is remaining and compare it against libFLAC. */ - drflac_result result; - libflac libflac; - drflac* pFlac; - drflac_uint32 iteration; - drflac_uint32 totalIterationCount = 10; - - dr_printf_fixed_with_margin(PROFILING_NAME_WIDTH, PROFILING_NUMBER_MARGIN, "%s", dr_path_file_name(pFilePath)); - - /* First load the decoder from libFLAC. */ - result = libflac_init_file(pFilePath, &libflac); - if (result != DRFLAC_SUCCESS) { - printf(" Failed to open via libFLAC."); - return result; - } - - /* Now load from dr_flac. */ - pFlac = drflac_open_file(pFilePath, NULL); - if (pFlac == NULL) { - printf(" Failed to open via dr_flac."); - libflac_uninit(&libflac); - return DRFLAC_ERROR; /* Failed to load dr_flac decoder. */ - } - - /* Use these to use specific seeking methods. Set all to false to use the normal prioritization (seek table, then binary search, then brute force). */ - pFlac->_noSeekTableSeek = DRFLAC_FALSE; - pFlac->_noBinarySearchSeek = DRFLAC_FALSE; - pFlac->_noBruteForceSeek = DRFLAC_FALSE; - - /* At this point we should have both libFLAC and dr_flac decoders open. We can now perform identical operations on each of them and compare. */ - - /* Start with the basics: Seek to the very end, and then the very start. */ - if (result == DRFLAC_SUCCESS) { - result = seek_test_pcm_frame(&libflac, pFlac, libflac.pcmFrameCount); - } - if (result == DRFLAC_SUCCESS) { - result = seek_test_pcm_frame(&libflac, pFlac, 0); - } - - /* Now we'll try seeking to random locations. */ - dr_seed(1234); - - iteration = 0; - while (result == DRFLAC_SUCCESS && iteration < totalIterationCount) { - dr_uint64 targetPCMFrame = dr_rand_range_u64(0, libflac.pcmFrameCount); - if (targetPCMFrame > libflac.pcmFrameCount) { - DRFLAC_ASSERT(DRFLAC_FALSE); /* Should never hit this, but if we do it means our random number generation routine is wrong. */ - } - - result = seek_test_pcm_frame(&libflac, pFlac, targetPCMFrame); - iteration += 1; - } - - /* We're done with our decoders. */ - drflac_close(pFlac); - libflac_uninit(&libflac); - - if (result == DRFLAC_SUCCESS) { - printf(" Passed"); - } - - return result; -} - -drflac_result seek_test_directory(const char* pDirectoryPath) -{ - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - - dr_printf_fixed(PROFILING_NAME_WIDTH, "%s", pDirectoryPath); - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "RESULT"); - printf("\n"); - - pFile = dr_file_iterator_begin(pDirectoryPath, &iteratorState); - while (pFile != NULL) { - drflac_result result; - - /* Skip directories for now, but we may want to look at doing recursive file iteration. */ - if (!pFile->isDirectory) { - result = seek_test_file(pFile->absolutePath); - (void)result; - - printf("\n"); - } - - pFile = dr_file_iterator_next(pFile); - } - - return DRFLAC_SUCCESS; -} - -drflac_result seek_test() -{ - drflac_result result = DRFLAC_SUCCESS; - - /* Directories. */ - { - result = seek_test_directory("testvectors/flac/tests"); - (void)result; - } - - return result; -} - - -drflac_result seek_profiling_drflac_and_close(drflac* pFlac, double* pProcessingTime) -{ - drflac_result result = DRFLAC_SUCCESS; - int i; - - if (pFlac == NULL) { - result = DRFLAC_INVALID_ARGS; - goto done; - } - - if (pFlac->totalPCMFrameCount == 0) { - result = DRFLAC_INVALID_ARGS; - goto done; - } - - if (pProcessingTime != NULL) { - *pProcessingTime = 0; - } - - /* Seek back to the start to keep everything normalized. */ - drflac_seek_to_pcm_frame(pFlac, 0); - - /* Random seek points based on a seed. */ - dr_seed(1234); - /*dr_seed(4321);*/ - for (i = 0; i < 100; ++i) { - double startTime; - double endTime; - dr_uint64 targetPCMFrame = dr_rand_range_u64(0, pFlac->totalPCMFrameCount); - - startTime = dr_timer_now(); - { - drflac_seek_to_pcm_frame(pFlac, targetPCMFrame); - } - endTime = dr_timer_now(); - - if (pProcessingTime != NULL) { - *pProcessingTime += (endTime - startTime); - } - } - -done: - drflac_close(pFlac); - return result; -} - -drflac_result seek_profiling_file__seek_table(const char* pFilePath, double* pProcessingTime) -{ - drflac* pFlac; - - if (pFilePath == NULL) { - return DRFLAC_INVALID_ARGS; - } - - pFlac = drflac_open_file(pFilePath, NULL); - if (pFlac == NULL) { - return DRFLAC_ERROR; - } - - pFlac->_noSeekTableSeek = DRFLAC_FALSE; - pFlac->_noBinarySearchSeek = DRFLAC_TRUE; - pFlac->_noBruteForceSeek = DRFLAC_TRUE; - - return seek_profiling_drflac_and_close(pFlac, pProcessingTime); -} - -drflac_result seek_profiling_file__binary_search(const char* pFilePath, double* pProcessingTime) -{ - drflac* pFlac; - - if (pFilePath == NULL) { - return DRFLAC_INVALID_ARGS; - } - - pFlac = drflac_open_file(pFilePath, NULL); - if (pFlac == NULL) { - return DRFLAC_ERROR; - } - - pFlac->_noSeekTableSeek = DRFLAC_TRUE; - pFlac->_noBinarySearchSeek = DRFLAC_FALSE; - pFlac->_noBruteForceSeek = DRFLAC_TRUE; - - return seek_profiling_drflac_and_close(pFlac, pProcessingTime); -} - -drflac_result seek_profiling_file__brute_force(const char* pFilePath, double* pProcessingTime) -{ - drflac* pFlac; - - if (pFilePath == NULL) { - return DRFLAC_INVALID_ARGS; - } - - pFlac = drflac_open_file(pFilePath, NULL); - if (pFlac == NULL) { - return DRFLAC_ERROR; - } - - pFlac->_noSeekTableSeek = DRFLAC_TRUE; - pFlac->_noBinarySearchSeek = DRFLAC_TRUE; - pFlac->_noBruteForceSeek = DRFLAC_FALSE; - - return seek_profiling_drflac_and_close(pFlac, pProcessingTime); -} - -drflac_result seek_profiling_file(const char* pFilePath, profiling_state* pProfiling) -{ - drflac_result result; - - profiling_state_init(pProfiling); - - /* - There are different seeking modes, and each one is profiled so that we can compare the results: - - Brute Force - - Binary Search - - Seek Table - - In order to keep the total run time fair, we can only include files with a seek table. - */ - dr_printf_fixed_with_margin(PROFILING_NAME_WIDTH, 2, "%s", dr_path_file_name(pFilePath)); - - /* Start off with the seek table version. If this fails we don't bother continuing. */ -#if 1 - result = seek_profiling_file__seek_table(pFilePath, &pProfiling->totalSeconds_SeekTable); - if (result != DRFLAC_SUCCESS) { - return result; - } - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "%f", pProfiling->totalSeconds_SeekTable); -#else - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, ""); -#endif - -#if 1 - result = seek_profiling_file__binary_search(pFilePath, &pProfiling->totalSeconds_BinarySearch); - if (result != DRFLAC_SUCCESS) { - return result; - } - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "%f", pProfiling->totalSeconds_BinarySearch); -#else - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, ""); -#endif - -#if 1 - result = seek_profiling_file__brute_force(pFilePath, &pProfiling->totalSeconds_BruteForce); - if (result != DRFLAC_SUCCESS) { - return result; - } - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "%f", pProfiling->totalSeconds_BruteForce); -#else - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, ""); -#endif - - return DRFLAC_SUCCESS; -} - -drflac_result seek_profiling_directory(const char* pDirectoryPath, profiling_state* pProfiling) -{ - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - - profiling_state_init(pProfiling); - - dr_printf_fixed(PROFILING_NAME_WIDTH, "%s", pDirectoryPath); - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "S/Table"); - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "Bin Srch"); - dr_printf_fixed_with_margin(PROFILING_NUMBER_WIDTH, PROFILING_NUMBER_MARGIN, "B/Force"); - printf("\n"); - - pFile = dr_file_iterator_begin(pDirectoryPath, &iteratorState); - while (pFile != NULL) { - drflac_result result; - profiling_state fileProfiling; - - /* Skip directories for now, but we may want to look at doing recursive file iteration. */ - if (!pFile->isDirectory) { - result = seek_profiling_file(pFile->absolutePath, &fileProfiling); - if (result == DRFLAC_SUCCESS) { - *pProfiling = profiling_state_sum(pProfiling, &fileProfiling); - } - - printf("\n"); - } - - pFile = dr_file_iterator_next(pFile); - } - - return DRFLAC_SUCCESS; -} - -drflac_result seek_profiling() -{ - drflac_result result = DRFLAC_SUCCESS; - profiling_state globalProfiling; - - profiling_state_init(&globalProfiling); - - /* Directories. */ - { - profiling_state directoryProfiling; - - result = seek_profiling_directory("testvectors/flac/tests", &directoryProfiling); - if (result == DRFLAC_SUCCESS) { - globalProfiling = profiling_state_sum(&globalProfiling, &directoryProfiling); - } - } - - return result; -} - - -int main(int argc, char** argv) -{ - drflac_result result = DRFLAC_SUCCESS; - drflac_bool32 doTesting = DRFLAC_TRUE; - drflac_bool32 doProfiling = DRFLAC_TRUE; - - /* This program has two main parts. The first is just a normal functionality test. The second is a profiling of the different seeking methods. */ - if (dr_argv_is_set(argc, argv, "--onlyprofile")) { - doTesting = DRFLAC_FALSE; - } - - /* Exhaustive seek test. */ - if (doTesting) { - printf("=======================================================================\n"); - printf("SEEK TESTING\n"); - printf("=======================================================================\n"); - result = seek_test(); - if (result != DRFLAC_SUCCESS) { - return (int)result; /* Don't continue if an error occurs during testing. */ - } - printf("\n"); - } else { - printf("=======================================================================\n"); - printf("WARNING: Correctness Tests Disabled\n"); - printf("=======================================================================\n"); - } - - /* Profiling. */ - if (doProfiling) { - printf("=======================================================================\n"); - printf("SEEK PROFILING\n"); - printf("=======================================================================\n"); - result = seek_profiling(); - printf("\n"); - } - - /*getchar();*/ - return (int)result; -} diff --git a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_test_0.c b/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_test_0.c deleted file mode 100644 index ffc28c8..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_test_0.c +++ /dev/null @@ -1,11 +0,0 @@ -#define DR_FLAC_IMPLEMENTATION -#include "../../dr_flac.h" - -#include "../common/dr_common.c" - -int main(int argc, char** argv) -{ - (void)argc; - (void)argv; - return 0; -} diff --git a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_test_0.cpp b/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_test_0.cpp deleted file mode 100644 index ce77013..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/dr_flac_test_0.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "dr_flac_test_0.c" diff --git a/source/engine/thirdparty/dr_libs/tests/flac/fuzz_dr_flac.c b/source/engine/thirdparty/dr_libs/tests/flac/fuzz_dr_flac.c deleted file mode 100644 index f4b6274..0000000 --- a/source/engine/thirdparty/dr_libs/tests/flac/fuzz_dr_flac.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Fuzz tester for dr_flac.h - * - * compile with - * clang -g -O1 -fsanitize=fuzzer,address -o fuzz_dr_flac fuzz_dr_flac.c - * - * and run ./fuzz_dr_flac to run fuzz testing - * - * Other sanitizers are possible, for example - * -fsanitize=fuzzer,memory - * -fsanitize=fuzzer,undefined - * - * For more options, run ./fuzz_dr_flac -help=1 - * - * If a problem is found, the problematic input is saved and can be - * rerun (with for example a debugger) with - * - * ./fuzz_dr_flac file - * - */ - -#include - -#define DR_FLAC_IMPLEMENTATION -#define DR_FLAC_NO_CRC -#define DR_FLAC_NO_STDIO -#include "../../dr_flac.h" - -#define MIN(a,b) (((a)<(b))?(a):(b)) - -uint8_t fuzz_flacstream[4096] = {0}; -size_t fuzz_flacstream_position; -size_t fuzz_flacstream_length; - -static size_t read_fuzz_flacstream(void* pUserData, void* bufferOut, size_t bytesToRead) -{ - size_t readsize = MIN(bytesToRead, fuzz_flacstream_length-fuzz_flacstream_position); - if (readsize > 0) { - memcpy(bufferOut, fuzz_flacstream+fuzz_flacstream_position, readsize); - fuzz_flacstream_position += readsize; - return readsize; - } else { - return 0; - } -} - -static drflac_bool32 seek_fuzz_flacstream(void* pUserData, int offset, drflac_seek_origin origin) -{ - if ((int)fuzz_flacstream_position+offset < 0 || (int)fuzz_flacstream_position+offset > fuzz_flacstream_length) { - return 1; - } else { - fuzz_flacstream_position = (int)fuzz_flacstream_position+offset; - return 0; - } -} - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - if (size > 2) { - drflac * drflac_fuzzer; - drflac_int32 drflac_fuzzer_out[2048] = {0}; /* 256 samples over 8 channels */ - drflac_container container = data[0] & 1 ? drflac_container_native : drflac_container_ogg; - - memcpy(fuzz_flacstream, data, (size-1)<4096?(size-1):4096); - - fuzz_flacstream_position = 0; - fuzz_flacstream_length = size-1; - - drflac_fuzzer = drflac_open_relaxed(read_fuzz_flacstream, seek_fuzz_flacstream, container, NULL, NULL); - - while (drflac_read_pcm_frames_s32(drflac_fuzzer, 256, drflac_fuzzer_out)); - - drflac_close(drflac_fuzzer); - } - return 0; -} diff --git a/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_common.c b/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_common.c deleted file mode 100644 index 813e9df..0000000 --- a/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_common.c +++ /dev/null @@ -1,4 +0,0 @@ -#define DR_MP3_IMPLEMENTATION -#include "../../dr_mp3.h" - -#include "../common/dr_common.c" diff --git a/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_playback.c b/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_playback.c deleted file mode 100644 index 17953a3..0000000 --- a/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_playback.c +++ /dev/null @@ -1,161 +0,0 @@ -#include "dr_mp3_common.c" - -#define MA_NO_DECODING -#define MA_NO_ENCODING -#define MINIAUDIO_IMPLEMENTATION -#include "../external/miniaudio/miniaudio.h" - -void data_callback(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) -{ - drmp3* pMP3; - - pMP3 = (drmp3*)pDevice->pUserData; - DRMP3_ASSERT(pMP3 != NULL); - - if (pDevice->playback.format == ma_format_f32) { - drmp3_read_pcm_frames_f32(pMP3, frameCount, pFramesOut); - } else if (pDevice->playback.format == ma_format_s16) { - drmp3_read_pcm_frames_s16(pMP3, frameCount, pFramesOut); - } else { - DRMP3_ASSERT(DRMP3_FALSE); /* Should never get here. */ - } - - (void)pFramesIn; -} - -int do_decoding_validation(const char* pFilePath) -{ - int result = 0; - drmp3 mp3Memory; - drmp3 mp3File; - size_t dataSize; - void* pData; - - /* - When opening from a memory buffer, dr_mp3 will take a different path for decoding which is optimized to reduce data movement. Since it's - running on a separate path, we need to ensure it's returning consistent results with the other code path which will be used when decoding - from a file. - */ - - /* Initialize the memory decoder. */ - pData = dr_open_and_read_file(pFilePath, &dataSize); - if (pData == NULL) { - printf("Failed to open file \"%s\"", pFilePath); - return -1; - } - - if (!drmp3_init_memory(&mp3Memory, pData, dataSize, NULL)) { - free(pData); - printf("Failed to init MP3 decoder \"%s\"", pFilePath); - return -1; - } - - - /* Initialize the file decoder. */ - if (!drmp3_init_file(&mp3File, pFilePath, NULL)) { - drmp3_uninit(&mp3Memory); - free(pData); - printf("Failed to open file \"%s\"", pFilePath); - return -1; - } - - DRMP3_ASSERT(mp3Memory.channels == mp3File.channels); - - - /* Compare. */ - for (;;) { - drmp3_uint64 iSample; - drmp3_uint64 pcmFrameCountMemory; - drmp3_uint64 pcmFrameCountFile; - drmp3_int16 pcmFramesMemory[4096]; - drmp3_int16 pcmFramesFile[4096]; - - pcmFrameCountMemory = drmp3_read_pcm_frames_s16(&mp3Memory, DRMP3_COUNTOF(pcmFramesMemory) / mp3Memory.channels, pcmFramesMemory); - pcmFrameCountFile = drmp3_read_pcm_frames_s16(&mp3File, DRMP3_COUNTOF(pcmFramesFile) / mp3File.channels, pcmFramesFile); - - /* Check the frame count first. */ - if (pcmFrameCountMemory != pcmFrameCountFile) { - printf("Frame counts differ: memory = %d; file = %d\n", (int)pcmFrameCountMemory, (int)pcmFrameCountFile); - result = -1; - break; - } - - /* Check individual frames. */ - DRMP3_ASSERT(pcmFrameCountMemory == pcmFrameCountFile); - for (iSample = 0; iSample < pcmFrameCountMemory * mp3Memory.channels; iSample += 1) { - if (pcmFramesMemory[iSample] != pcmFramesFile[iSample]) { - printf("Samples differ: memory = %d; file = %d\n", (int)pcmFramesMemory[iSample], (int)pcmFramesFile[iSample]); - result = -1; - break; - } - } - - /* We've reached the end if we didn't return any PCM frames. */ - if (pcmFrameCountMemory == 0 || pcmFrameCountFile == 0) { - break; - } - } - - - drmp3_uninit(&mp3File); - drmp3_uninit(&mp3Memory); - free(pData); - return result; -} - -int main(int argc, char** argv) -{ - drmp3 mp3; - ma_result resultMA; - ma_device_config deviceConfig; - ma_device device; - const char* pInputFilePath; - - if (argc < 2) { - printf("No input file.\n"); - return -1; - } - - pInputFilePath = argv[1]; - - /* Quick validation test first. */ - if (do_decoding_validation(pInputFilePath) != 0) { - return -1; - } - - - if (!drmp3_init_file(&mp3, pInputFilePath, NULL)) { - printf("Failed to open file \"%s\"", pInputFilePath); - return -1; - } - - deviceConfig = ma_device_config_init(ma_device_type_playback); - deviceConfig.playback.format = ma_format_s16; - deviceConfig.playback.channels = mp3.channels; - deviceConfig.sampleRate = mp3.sampleRate; - deviceConfig.dataCallback = data_callback; - deviceConfig.pUserData = &mp3; - resultMA = ma_device_init(NULL, &deviceConfig, &device); - if (resultMA != MA_SUCCESS) { - drmp3_uninit(&mp3); - printf("Failed to initialize playback device: %s.\n", ma_result_description(resultMA)); - return -1; - } - - resultMA = ma_device_start(&device); - if (resultMA != MA_SUCCESS) { - ma_device_uninit(&device); - drmp3_uninit(&mp3); - printf("Failed to start playback device: %s.\n", ma_result_description(resultMA)); - return -1; - } - - printf("Press Enter to quit..."); - getchar(); - - /* We're done. */ - ma_device_uninit(&device); - drmp3_uninit(&mp3); - - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_test_0.c b/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_test_0.c deleted file mode 100644 index db14b7b..0000000 --- a/source/engine/thirdparty/dr_libs/tests/mp3/dr_mp3_test_0.c +++ /dev/null @@ -1,12 +0,0 @@ -#define DR_MP3_IMPLEMENTATION -#include "../../dr_mp3.h" - -#include "../common/dr_common.c" - -int main(int argc, char** argv) -{ - (void)argc; - (void)argv; - return 0; -} - diff --git a/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_decoding.c b/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_decoding.c deleted file mode 100644 index 76c5c60..0000000 --- a/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_decoding.c +++ /dev/null @@ -1,205 +0,0 @@ -/*#define DR_OPUS_DEBUGGING*/ - -#define DR_OPUS_IMPLEMENTATION -#include "../../wip/dr_opus.h" -#include "../common/dr_common.c" - -const char* dropus_mode_to_string(dropus_mode mode) /* Move this into dr_opus.h? */ -{ - switch (mode) - { - case dropus_mode_silk: return "SILK"; - case dropus_mode_celt: return "CELT"; - case dropus_mode_hybrid: return "Hybrid"; - default: break; - } - - return "Unknown"; -} - -#include - -/* Forward declare our debugging entry point if necessary. */ -#ifdef DR_OPUS_DEBUGGING -int main_debugging(int argc, char** argv); -#endif - -dropus_result test_standard_vector(const char* pFilePath) -{ - dropus_result result; - dropus_stream stream; - void* pFileData; - size_t fileSize; - const dropus_uint8* pRunningData8; - size_t runningPos; - dropus_uint32 iPacket = 0; /* For error reporting. */ - - - /* Load the entire file into memory first. */ - pFileData = dr_open_and_read_file(pFilePath, &fileSize); - if (pFileData == NULL) { - return DROPUS_ERROR; /* File not found. */ - } - - /* Now initialize the stream in preparation for decoding packets. */ - result = dropus_stream_init(&stream); - if (result != DROPUS_SUCCESS) { - free(pFileData); - return result; - } - - /* - Here is where we scan the test vector. The way the file is structured is quite simple. It is made up of a list of Opus packets, each - of which include an 8 byte header where the first 4 bytes is the size in bytes of the Opus packet (little endian) and the next 4 bytes - contain the 32-bit range state which we'll use for validation. - */ - pRunningData8 = (const dropus_uint8*)pFileData; - runningPos = 0; - - /* For each packet... */ - while (runningPos < fileSize) { - dropus_result decodeResult; - dropus_uint32 packetSize; - dropus_uint32 rangeState; - - memcpy(&packetSize, pRunningData8 + 0, 4); - memcpy(&rangeState, pRunningData8 + 4, 4); - - packetSize = dropus__be2host_32(packetSize); - rangeState = dropus__be2host_32(rangeState); - - pRunningData8 += 8; - runningPos += 8; - - /* Safety. Break if we've run out of data. */ - if ((runningPos + packetSize) > fileSize) { - printf("WARNING: Ran out of data before the end of the file.\n"); - break; - } - - decodeResult = dropus_stream_decode_packet(&stream, pRunningData8, packetSize); - if (decodeResult != DROPUS_SUCCESS) { - result = DROPUS_ERROR; - printf("Failed to decode packet %d\n", iPacket); - } - - printf("Opus Packet %d: Mode=%s\n", iPacket, dropus_mode_to_string(dropus_toc_mode(stream.packet.toc))); - - pRunningData8 += packetSize; - runningPos += packetSize; - iPacket += 1; - } - - free(pFileData); - return result; -} - -dropus_result test_standard_vectors_folder(const char* pFolderPath) -{ - dropus_bool32 foundError = DROPUS_FALSE; - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - - pFile = dr_file_iterator_begin(pFolderPath, &iteratorState); - while (pFile != NULL) { - /* Only look at files with the extension "bit". */ - if (dr_extension_equal(pFile->relativePath, "bit")) { - if (test_standard_vector(pFile->absolutePath) != DROPUS_SUCCESS) { - foundError = DROPUS_TRUE; - } - } - - pFile = dr_file_iterator_next(pFile); - } - - if (foundError) { - return DROPUS_ERROR; - } else { - return DROPUS_SUCCESS; - } -} - -dropus_result test_standard_vectors() -{ - dropus_bool32 foundError = DROPUS_FALSE; - - /* Two groups of standard test vectors. The original vectors and the "new" vectors. */ - - /* Original vectors. */ - if (test_standard_vectors_folder("testvectors/opus/opus_testvectors") != DROPUS_SUCCESS) { - foundError = DROPUS_TRUE; - } - - /* New vectors. */ - if (test_standard_vectors_folder("testvectors/opus/opus_newvectors") != DROPUS_SUCCESS) { - foundError = DROPUS_TRUE; - } - - if (foundError) { - return DROPUS_ERROR; - } else { - return DROPUS_SUCCESS; - } -} - -dropus_result test_ogg_vectors() -{ - dropus_result result; - - /* Ogg Opus test vectors are in the "oggopus" folder. */ - result = DROPUS_SUCCESS; - - return result; -} - -int main(int argc, char** argv) -{ - dropus_result result; - - /* Do debugging stuff first. */ -#ifdef DR_OPUS_DEBUGGING - main_debugging(argc, argv); -#endif - - result = test_standard_vector("testvectors/opus/opus_testvectors/testvector02.bit"); - if (result != DROPUS_SUCCESS) { - /*return (int)result;*/ - } - - /* Test standard vectors first. */ - result = test_standard_vectors(); - if (result != DROPUS_SUCCESS) { - /*return (int)result;*/ - } - - /* Ogg Opus. */ - result = test_ogg_vectors(); - if (result != DROPUS_SUCCESS) { - /*return (int)result;*/ - } - - (void)argc; - (void)argv; - return 0; -} - -#ifdef DR_OPUS_DEBUGGING -int main_debugging(int argc, char** argv) -{ - dr_file_iterator iterator; - dr_file_iterator* pFile = dr_file_iterator_begin("testvectors/opus/oggopus", &iterator); - while (pFile != NULL) { - if (pFile->isDirectory) { - printf("DIRECTORY: %s : %s\n", pFile->relativePath, pFile->absolutePath); - } else { - printf("FILE: %s : %s\n", pFile->relativePath, pFile->absolutePath); - } - - pFile = dr_file_iterator_next(pFile); - } - - (void)argc; - (void)argv; - return 0; -} -#endif diff --git a/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_test_0.c b/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_test_0.c deleted file mode 100644 index 0e073b7..0000000 --- a/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_test_0.c +++ /dev/null @@ -1,9 +0,0 @@ -#define DR_OPUS_IMPLEMENTATION -#include "../../wip/dr_opus.h" - -int main(int argc, char** argv) -{ - (void)argc; - (void)argv; - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_test_0.cpp b/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_test_0.cpp deleted file mode 100644 index 97401ce..0000000 --- a/source/engine/thirdparty/dr_libs/tests/opus/dr_opus_test_0.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "dr_opus_test_0.c" diff --git a/source/engine/thirdparty/dr_libs/tests/testvectors/DO_NOT_DELETE.md b/source/engine/thirdparty/dr_libs/tests/testvectors/DO_NOT_DELETE.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/dr_libs/tests/testvectors/flac/DO_NOT_DELETE.md b/source/engine/thirdparty/dr_libs/tests/testvectors/flac/DO_NOT_DELETE.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/dr_libs/tests/testvectors/mp3/DO_NOT_DELETE.md b/source/engine/thirdparty/dr_libs/tests/testvectors/mp3/DO_NOT_DELETE.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/dr_libs/tests/testvectors/opus/DO_NOT_DELETE.md b/source/engine/thirdparty/dr_libs/tests/testvectors/opus/DO_NOT_DELETE.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/dr_libs/tests/testvectors/wav/DO_NOT_DELETE.md b/source/engine/thirdparty/dr_libs/tests/testvectors/wav/DO_NOT_DELETE.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_common.c b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_common.c deleted file mode 100644 index 165b4ad..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_common.c +++ /dev/null @@ -1,326 +0,0 @@ -#define DR_WAV_IMPLEMENTATION -#include "../../dr_wav.h" -#include -#include "../common/dr_common.c" - -dr_handle g_libsndfile = NULL; - -typedef SNDFILE* (* pfn_sf_open_virtual)(SF_VIRTUAL_IO* sfvirtual, int mode, SF_INFO* sfinfo, void* user_data); -typedef int (* pfn_sf_close) (SNDFILE* sndfile); -typedef sf_count_t (* pfn_sf_readf_short) (SNDFILE *sndfile, short *ptr, sf_count_t frames); -typedef sf_count_t (* pfn_sf_readf_int) (SNDFILE *sndfile, int *ptr, sf_count_t frames); -typedef sf_count_t (* pfn_sf_readf_float) (SNDFILE *sndfile, float *ptr, sf_count_t frames); -typedef sf_count_t (* pfn_sf_readf_double)(SNDFILE *sndfile, double *ptr, sf_count_t frames); -typedef sf_count_t (* pfn_sf_seek) (SNDFILE *sndfile, sf_count_t frames, int whence); - -pfn_sf_open_virtual libsndfile__sf_open_virtual; -pfn_sf_close libsndfile__sf_close; -pfn_sf_readf_short libsndfile__sf_readf_short; -pfn_sf_readf_int libsndfile__sf_readf_int; -pfn_sf_readf_float libsndfile__sf_readf_float; -pfn_sf_readf_double libsndfile__sf_readf_double; -pfn_sf_seek libsndfile__sf_seek; - -drwav_result libsndfile_init_api() -{ - unsigned int i; - const char* pFileNames[] = { -#if defined(_WIN32) - #if defined(_WIN64) - "libsndfile-1-x64.dll", - #else - "libsndfile-1-x86.dll", - #endif - "libsndfile-1.dll" -#else - "libsndfile-1.so", - "libsndfile.so.1" -#endif - }; - - if (g_libsndfile != NULL) { - return DRWAV_INVALID_OPERATION; /* Already initialized. */ - } - - for (i = 0; i < sizeof(pFileNames)/sizeof(pFileNames[0]); i += 1) { - g_libsndfile = dr_dlopen(pFileNames[i]); - if (g_libsndfile != NULL) { - break; - } - } - - if (g_libsndfile == NULL) { - return DRWAV_ERROR; /* Unable to load libsndfile-1.so/dll. */ - } - - libsndfile__sf_open_virtual = (pfn_sf_open_virtual)dr_dlsym(g_libsndfile, "sf_open_virtual"); - libsndfile__sf_close = (pfn_sf_close) dr_dlsym(g_libsndfile, "sf_close"); - libsndfile__sf_readf_short = (pfn_sf_readf_short) dr_dlsym(g_libsndfile, "sf_readf_short"); - libsndfile__sf_readf_int = (pfn_sf_readf_int) dr_dlsym(g_libsndfile, "sf_readf_int"); - libsndfile__sf_readf_float = (pfn_sf_readf_float) dr_dlsym(g_libsndfile, "sf_readf_float"); - libsndfile__sf_readf_double = (pfn_sf_readf_double)dr_dlsym(g_libsndfile, "sf_readf_double"); - libsndfile__sf_seek = (pfn_sf_seek) dr_dlsym(g_libsndfile, "sf_seek"); - - return DRWAV_SUCCESS; -} - -void libsndfile_uninit_api() -{ - if (g_libsndfile == NULL) { - return; /* Invalid operation. Not initialized. */ - } - - dr_dlclose(g_libsndfile); - g_libsndfile = NULL; -} - -typedef struct -{ - SNDFILE* pHandle; - SF_INFO info; - drwav_uint8* pFileData; - size_t fileSizeInBytes; - size_t fileReadPos; -} libsndfile; - -sf_count_t libsndfile__on_filelen(void *user_data) -{ - libsndfile* pSndFile = (libsndfile*)user_data; - return (sf_count_t)pSndFile->fileSizeInBytes; -} - -sf_count_t libsndfile__on_seek(sf_count_t offset, int whence, void *user_data) -{ - libsndfile* pSndFile = (libsndfile*)user_data; - - switch (whence) - { - case SF_SEEK_SET: - { - pSndFile->fileReadPos = (size_t)offset; - } break; - case SF_SEEK_CUR: - { - pSndFile->fileReadPos += (size_t)offset; - } break; - case SF_SEEK_END: - { - pSndFile->fileReadPos = pSndFile->fileSizeInBytes - (size_t)offset; - } break; - } - - return (sf_count_t)pSndFile->fileReadPos; -} - -sf_count_t libsndfile__on_read(void *ptr, sf_count_t count, void *user_data) -{ - libsndfile* pSndFile = (libsndfile*)user_data; - - DRWAV_COPY_MEMORY(ptr, pSndFile->pFileData + pSndFile->fileReadPos, (size_t)count); - pSndFile->fileReadPos += (size_t)count; - - return count; -} - -sf_count_t libsndfile__on_write(const void *ptr, sf_count_t count, void *user_data) -{ - /* We're not doing anything with writing. */ - (void)ptr; - (void)count; - (void)user_data; - return 0; -} - -sf_count_t libsndfile__on_tell(void *user_data) -{ - libsndfile* pSndFile = (libsndfile*)user_data; - return (sf_count_t)pSndFile->fileReadPos; -} - -drwav_result libsndfile_init_file(const char* pFilePath, libsndfile* pSndFile) -{ - SF_VIRTUAL_IO callbacks; - - if (pFilePath == NULL || pSndFile == NULL) { - return DRWAV_INVALID_ARGS; - } - - DRWAV_ZERO_MEMORY(pSndFile, sizeof(*pSndFile)); - - /* We use libsndfile's virtual IO technique because we want to load from memory to make speed benchmarking fairer. */ - pSndFile->pFileData = (drwav_uint8*)dr_open_and_read_file(pFilePath, &pSndFile->fileSizeInBytes); - if (pSndFile->pFileData == NULL) { - return DRWAV_ERROR; /* Failed to open the file. */ - } - - DRWAV_ZERO_MEMORY(&callbacks, sizeof(callbacks)); - callbacks.get_filelen = libsndfile__on_filelen; - callbacks.seek = libsndfile__on_seek; - callbacks.read = libsndfile__on_read; - callbacks.write = libsndfile__on_write; - callbacks.tell = libsndfile__on_tell; - - pSndFile->pHandle = libsndfile__sf_open_virtual(&callbacks, SFM_READ, &pSndFile->info, pSndFile); - if (pSndFile->pHandle == NULL) { - free(pSndFile->pFileData); - return DRWAV_ERROR; - } - - return DRWAV_SUCCESS; -} - -void libsndfile_uninit(libsndfile* pSndFile) -{ - if (pSndFile == NULL) { - return; - } - - libsndfile__sf_close(pSndFile->pHandle); - free(pSndFile->pFileData); -} - -drwav_uint64 libsndfile_read_pcm_frames_s16(libsndfile* pSndFile, drwav_uint64 framesToRead, drwav_int16* pBufferOut) -{ - if (pSndFile == NULL || pBufferOut == NULL) { - return 0; - } - - /* Unfortunately it looks like libsndfile does not return correct integral values when the source file is floating point. */ - if ((pSndFile->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) { - /* Read as float and convert. */ - drwav_uint64 totalFramesRead = 0; - while (totalFramesRead < framesToRead) { - float temp[4096]; - drwav_uint64 framesRemaining = framesToRead - totalFramesRead; - drwav_uint64 framesReadThisIteration; - drwav_uint64 framesToReadThisIteration = sizeof(temp)/sizeof(temp[0]) / pSndFile->info.channels; - if (framesToReadThisIteration > framesRemaining) { - framesToReadThisIteration = framesRemaining; - } - - framesReadThisIteration = libsndfile__sf_readf_float(pSndFile->pHandle, temp, (sf_count_t)framesToReadThisIteration); - - drwav_f32_to_s16(pBufferOut, temp, (size_t)(framesReadThisIteration*pSndFile->info.channels)); - - totalFramesRead += framesReadThisIteration; - pBufferOut += framesReadThisIteration*pSndFile->info.channels; - - /* If we read less frames than we requested we've reached the end of the file. */ - if (framesReadThisIteration < framesToReadThisIteration) { - break; - } - } - - return totalFramesRead; - } else if ((pSndFile->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE) { - /* Read as double and convert. */ - drwav_uint64 totalFramesRead = 0; - while (totalFramesRead < framesToRead) { - double temp[4096]; - drwav_uint64 framesRemaining = framesToRead - totalFramesRead; - drwav_uint64 framesReadThisIteration; - drwav_uint64 framesToReadThisIteration = sizeof(temp)/sizeof(temp[0]) / pSndFile->info.channels; - if (framesToReadThisIteration > framesRemaining) { - framesToReadThisIteration = framesRemaining; - } - - framesReadThisIteration = libsndfile__sf_readf_double(pSndFile->pHandle, temp, (sf_count_t)framesToReadThisIteration); - - drwav_f64_to_s16(pBufferOut, temp, (size_t)(framesReadThisIteration*pSndFile->info.channels)); - - totalFramesRead += framesReadThisIteration; - pBufferOut += framesReadThisIteration*pSndFile->info.channels; - - /* If we read less frames than we requested we've reached the end of the file. */ - if (framesReadThisIteration < framesToReadThisIteration) { - break; - } - } - - return totalFramesRead; - } else { - return libsndfile__sf_readf_short(pSndFile->pHandle, pBufferOut, framesToRead); - } -} - -drwav_uint64 libsndfile_read_pcm_frames_f32(libsndfile* pSndFile, drwav_uint64 framesToRead, float* pBufferOut) -{ - if (pSndFile == NULL || pBufferOut == NULL) { - return 0; - } - - return libsndfile__sf_readf_float(pSndFile->pHandle, pBufferOut, framesToRead); -} - -drwav_uint64 libsndfile_read_pcm_frames_s32(libsndfile* pSndFile, drwav_uint64 framesToRead, drwav_int32* pBufferOut) -{ - if (pSndFile == NULL || pBufferOut == NULL) { - return 0; - } - - /* Unfortunately it looks like libsndfile does not return correct integral values when the source file is floating point. */ - if ((pSndFile->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) { - /* Read floats and convert. */ - drwav_uint64 totalFramesRead = 0; - while (totalFramesRead < framesToRead) { - float temp[4096]; - drwav_uint64 framesRemaining = framesToRead - totalFramesRead; - drwav_uint64 framesReadThisIteration; - drwav_uint64 framesToReadThisIteration = sizeof(temp)/sizeof(temp[0]) / pSndFile->info.channels; - if (framesToReadThisIteration > framesRemaining) { - framesToReadThisIteration = framesRemaining; - } - - framesReadThisIteration = libsndfile__sf_readf_float(pSndFile->pHandle, temp, (sf_count_t)framesToReadThisIteration); - - drwav_f32_to_s32(pBufferOut, temp, (size_t)(framesReadThisIteration*pSndFile->info.channels)); - - totalFramesRead += framesReadThisIteration; - pBufferOut += framesReadThisIteration*pSndFile->info.channels; - - /* If we read less frames than we requested we've reached the end of the file. */ - if (framesReadThisIteration < framesToReadThisIteration) { - break; - } - } - - return totalFramesRead; - } else if ((pSndFile->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE) { - /* Read doubles and convert. */ - drwav_uint64 totalFramesRead = 0; - while (totalFramesRead < framesToRead) { - double temp[4096]; - drwav_uint64 framesRemaining = framesToRead - totalFramesRead; - drwav_uint64 framesReadThisIteration; - drwav_uint64 framesToReadThisIteration = sizeof(temp)/sizeof(temp[0]) / pSndFile->info.channels; - if (framesToReadThisIteration > framesRemaining) { - framesToReadThisIteration = framesRemaining; - } - - framesReadThisIteration = libsndfile__sf_readf_double(pSndFile->pHandle, temp, (sf_count_t)framesToReadThisIteration); - - drwav_f64_to_s32(pBufferOut, temp, (size_t)(framesReadThisIteration*pSndFile->info.channels)); - - totalFramesRead += framesReadThisIteration; - pBufferOut += framesReadThisIteration*pSndFile->info.channels; - - /* If we read less frames than we requested we've reached the end of the file. */ - if (framesReadThisIteration < framesToReadThisIteration) { - break; - } - } - - return totalFramesRead; - } else { - return libsndfile__sf_readf_int(pSndFile->pHandle, pBufferOut, framesToRead); - } -} - -drwav_bool32 libsndfile_seek_to_pcm_frame(libsndfile* pSndFile, drwav_uint64 targetPCMFrameIndex) -{ - if (pSndFile == NULL) { - return DRWAV_FALSE; - } - - return libsndfile__sf_seek(pSndFile->pHandle, (sf_count_t)targetPCMFrameIndex, SF_SEEK_SET) == (sf_count_t)targetPCMFrameIndex; -} diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_decoding.c b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_decoding.c deleted file mode 100644 index bf9decb..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_decoding.c +++ /dev/null @@ -1,446 +0,0 @@ -#define DR_WAV_LIBSNDFILE_COMPAT -#include "dr_wav_common.c" - -#define FILE_NAME_WIDTH 40 -#define NUMBER_WIDTH 10 -#define TABLE_MARGIN 2 - -#define DEFAULT_SOURCE_DIR "testvectors/wav/tests" - - -drwav_result decode_test__read_and_compare_pcm_frames_s32(libsndfile* pSndFile, drwav* pWav, drwav_uint64 pcmFrameCount, drwav_int32* pPCMFrames_libsndfile, drwav_int32* pPCMFrames_drwav) -{ - drwav_uint64 pcmFrameCount_libsndfile; - drwav_uint64 pcmFrameCount_drwav; - drwav_uint64 iPCMFrame; - - /* To test decoding we just read a number of PCM frames from each decoder and compare. */ - pcmFrameCount_libsndfile = libsndfile_read_pcm_frames_s32(pSndFile, pcmFrameCount, pPCMFrames_libsndfile); - pcmFrameCount_drwav = drwav_read_pcm_frames_s32(pWav, pcmFrameCount, pPCMFrames_drwav); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libsndfile != pcmFrameCount_drwav) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libsndfile=%d, dr_wav=%d", (int)pcmFrameCount, (int)pcmFrameCount_libsndfile, (int)pcmFrameCount_drwav); - return DRWAV_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRWAV_ASSERT(pcmFrameCount_libsndfile == pcmFrameCount_drwav); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libsndfile; iPCMFrame += 1) { - drwav_int32* pPCMFrame_libsndfile = pPCMFrames_libsndfile + (iPCMFrame * pWav->channels); - drwav_int32* pPCMFrame_drwav = pPCMFrames_drwav + (iPCMFrame * pWav->channels); - drwav_uint32 iChannel; - drwav_bool32 hasError = DRWAV_FALSE; - - for (iChannel = 0; iChannel < pWav->channels; iChannel += 1) { - if (pPCMFrame_libsndfile[iChannel] != pPCMFrame_drwav[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRWAV_TRUE; - break; - } - } - - if (hasError) { - return DRWAV_ERROR; /* Decoded frames do not match. */ - } - } - - /* Done. */ - return DRWAV_SUCCESS; -} - -drwav_result decode_test__read_and_compare_pcm_frame_chunks_s32(libsndfile* pSndFile, drwav* pWav, drwav_uint64 pcmFrameChunkSize) -{ - drwav_result result = DRWAV_SUCCESS; - drwav_uint64 iPCMFrame; - drwav_int32* pPCMFrames_libsndfile; - drwav_int32* pPCMFrames_drwav; - - /* Make sure the decoder's are seeked back to the start first. */ - drwav_seek_to_pcm_frame(pWav, 0); - libsndfile_seek_to_pcm_frame(pSndFile, 0); - - pPCMFrames_libsndfile = (drwav_int32*)malloc((size_t)(pcmFrameChunkSize * pWav->channels * sizeof(drwav_int32))); - if (pPCMFrames_libsndfile == NULL) { - printf(" [libsndfile] Out of memory"); - return DRWAV_ERROR; - } - - pPCMFrames_drwav = (drwav_int32*)malloc((size_t)(pcmFrameChunkSize * pWav->channels * sizeof(drwav_int32))); - if (pPCMFrames_drwav == NULL) { - free(pPCMFrames_libsndfile); - printf(" [dr_wav] Out of memory"); - return DRWAV_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pWav->totalPCMFrameCount; iPCMFrame += pcmFrameChunkSize) { - result = decode_test__read_and_compare_pcm_frames_s32(pSndFile, pWav, pcmFrameChunkSize, pPCMFrames_libsndfile, pPCMFrames_drwav); - if (result != DRWAV_SUCCESS) { - break; - } - } - - free(pPCMFrames_libsndfile); - free(pPCMFrames_drwav); - - return result; -} - - -drwav_result decode_test__read_and_compare_pcm_frames_f32(libsndfile* pSndFile, drwav* pWav, drwav_uint64 pcmFrameCount, float* pPCMFrames_libsndfile, float* pPCMFrames_drwav) -{ - drwav_uint64 pcmFrameCount_libsndfile; - drwav_uint64 pcmFrameCount_drwav; - drwav_uint64 iPCMFrame; - - /* To test decoding we just read a number of PCM frames from each decoder and compare. */ - pcmFrameCount_libsndfile = libsndfile_read_pcm_frames_f32(pSndFile, pcmFrameCount, pPCMFrames_libsndfile); - pcmFrameCount_drwav = drwav_read_pcm_frames_f32(pWav, pcmFrameCount, pPCMFrames_drwav); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libsndfile != pcmFrameCount_drwav) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libsndfile=%d, dr_wav=%d", (int)pcmFrameCount, (int)pcmFrameCount_libsndfile, (int)pcmFrameCount_drwav); - return DRWAV_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRWAV_ASSERT(pcmFrameCount_libsndfile == pcmFrameCount_drwav); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libsndfile; iPCMFrame += 1) { - float* pPCMFrame_libsndfile = pPCMFrames_libsndfile + (iPCMFrame * pWav->channels); - float* pPCMFrame_drwav = pPCMFrames_drwav + (iPCMFrame * pWav->channels); - drwav_uint32 iChannel; - drwav_bool32 hasError = DRWAV_FALSE; - - for (iChannel = 0; iChannel < pWav->channels; iChannel += 1) { - if (pPCMFrame_libsndfile[iChannel] != pPCMFrame_drwav[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRWAV_TRUE; - break; - } - } - - if (hasError) { - return DRWAV_ERROR; /* Decoded frames do not match. */ - } - } - - /* Done. */ - return DRWAV_SUCCESS; -} - -drwav_result decode_test__read_and_compare_pcm_frame_chunks_f32(libsndfile* pSndFile, drwav* pWav, drwav_uint64 pcmFrameChunkSize) -{ - drwav_result result = DRWAV_SUCCESS; - drwav_uint64 iPCMFrame; - float* pPCMFrames_libsndfile; - float* pPCMFrames_drwav; - - /* Make sure the decoder's are seeked back to the start first. */ - drwav_seek_to_pcm_frame(pWav, 0); - libsndfile_seek_to_pcm_frame(pSndFile, 0); - - pPCMFrames_libsndfile = (float*)malloc((size_t)(pcmFrameChunkSize * pWav->channels * sizeof(float))); - if (pPCMFrames_libsndfile == NULL) { - printf(" [libsndfile] Out of memory"); - return DRWAV_ERROR; - } - - pPCMFrames_drwav = (float*)malloc((size_t)(pcmFrameChunkSize * pWav->channels * sizeof(float))); - if (pPCMFrames_drwav == NULL) { - free(pPCMFrames_libsndfile); - printf(" [dr_wav] Out of memory"); - return DRWAV_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pWav->totalPCMFrameCount; iPCMFrame += pcmFrameChunkSize) { - result = decode_test__read_and_compare_pcm_frames_f32(pSndFile, pWav, pcmFrameChunkSize, pPCMFrames_libsndfile, pPCMFrames_drwav); - if (result != DRWAV_SUCCESS) { - break; - } - } - - free(pPCMFrames_libsndfile); - free(pPCMFrames_drwav); - - return result; -} - - -drwav_result decode_test__read_and_compare_pcm_frames_s16(libsndfile* pSndFile, drwav* pWav, drwav_uint64 pcmFrameCount, drwav_int16* pPCMFrames_libsndfile, drwav_int16* pPCMFrames_drwav) -{ - drwav_uint64 pcmFrameCount_libsndfile; - drwav_uint64 pcmFrameCount_drwav; - drwav_uint64 iPCMFrame; - - /* To test decoding we just read a number of PCM frames from each decoder and compare. */ - pcmFrameCount_libsndfile = libsndfile_read_pcm_frames_s16(pSndFile, pcmFrameCount, pPCMFrames_libsndfile); - pcmFrameCount_drwav = drwav_read_pcm_frames_s16(pWav, pcmFrameCount, pPCMFrames_drwav); - - /* The total number of frames we decoded need to match. */ - if (pcmFrameCount_libsndfile != pcmFrameCount_drwav) { - printf(" Decoded frame counts differ: pcmFrameCount=%d, libsndfile=%d, dr_wav=%d", (int)pcmFrameCount, (int)pcmFrameCount_libsndfile, (int)pcmFrameCount_drwav); - return DRWAV_ERROR; - } - - /* Each of the decoded PCM frames need to match. */ - DRWAV_ASSERT(pcmFrameCount_libsndfile == pcmFrameCount_drwav); - - for (iPCMFrame = 0; iPCMFrame < pcmFrameCount_libsndfile; iPCMFrame += 1) { - drwav_int16* pPCMFrame_libsndfile = pPCMFrames_libsndfile + (iPCMFrame * pWav->channels); - drwav_int16* pPCMFrame_drwav = pPCMFrames_drwav + (iPCMFrame * pWav->channels); - drwav_uint32 iChannel; - drwav_bool32 hasError = DRWAV_FALSE; - - for (iChannel = 0; iChannel < pWav->channels; iChannel += 1) { - if (pPCMFrame_libsndfile[iChannel] != pPCMFrame_drwav[iChannel]) { - printf(" PCM Frame @ %d[%d] does not match: pcmFrameCount=%d", (int)iPCMFrame, iChannel, (int)pcmFrameCount); - hasError = DRWAV_TRUE; - break; - } - } - - if (hasError) { - return DRWAV_ERROR; /* Decoded frames do not match. */ - } - } - - /* Done. */ - return DRWAV_SUCCESS; -} - -drwav_result decode_test__read_and_compare_pcm_frame_chunks_s16(libsndfile* pSndFile, drwav* pWav, drwav_uint64 pcmFrameChunkSize) -{ - drwav_result result = DRWAV_SUCCESS; - drwav_uint64 iPCMFrame; - drwav_int16* pPCMFrames_libsndfile; - drwav_int16* pPCMFrames_drwav; - - /* Make sure the decoder's are seeked back to the start first. */ - drwav_seek_to_pcm_frame(pWav, 0); - libsndfile_seek_to_pcm_frame(pSndFile, 0); - - pPCMFrames_libsndfile = (drwav_int16*)malloc((size_t)(pcmFrameChunkSize * pWav->channels * sizeof(drwav_int16))); - if (pPCMFrames_libsndfile == NULL) { - printf(" [libsndfile] Out of memory"); - return DRWAV_ERROR; - } - - pPCMFrames_drwav = (drwav_int16*)malloc((size_t)(pcmFrameChunkSize * pWav->channels * sizeof(drwav_int16))); - if (pPCMFrames_drwav == NULL) { - free(pPCMFrames_libsndfile); - printf(" [dr_wav] Out of memory"); - return DRWAV_ERROR; - } - - for (iPCMFrame = 0; iPCMFrame < pWav->totalPCMFrameCount; iPCMFrame += pcmFrameChunkSize) { - result = decode_test__read_and_compare_pcm_frames_s16(pSndFile, pWav, pcmFrameChunkSize, pPCMFrames_libsndfile, pPCMFrames_drwav); - if (result != DRWAV_SUCCESS) { - break; - } - } - - free(pPCMFrames_libsndfile); - free(pPCMFrames_drwav); - - return result; -} - - -drwav_result decode_test_file_s32(libsndfile* pSndFile, drwav* pWav) -{ - drwav_result result = DRWAV_SUCCESS; - - /* Start with reading the entire file in one go. */ - if (result == DRWAV_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s32(pSndFile, pWav, pWav->totalPCMFrameCount); - } - - /* Now try with reading one PCM frame at a time.*/ - if (result == DRWAV_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s32(pSndFile, pWav, 1); - } - - return result; -} - -drwav_result decode_test_file_f32(libsndfile* pSndFile, drwav* pWav) -{ - drwav_result result = DRWAV_SUCCESS; - - /* Start with reading the entire file in one go. */ - if (result == DRWAV_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_f32(pSndFile, pWav, pWav->totalPCMFrameCount); - } - - /* Now try with reading one PCM frame at a time.*/ - if (result == DRWAV_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_f32(pSndFile, pWav, 1); - } - - return result; -} - -drwav_result decode_test_file_s16(libsndfile* pSndFile, drwav* pWav) -{ - drwav_result result = DRWAV_SUCCESS; - - /* Start with reading the entire file in one go. */ - if (result == DRWAV_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s16(pSndFile, pWav, pWav->totalPCMFrameCount); - } - - /* Now try with reading one PCM frame at a time.*/ - if (result == DRWAV_SUCCESS) { - result = decode_test__read_and_compare_pcm_frame_chunks_s16(pSndFile, pWav, 1); - } - - return result; -} - -drwav_result decode_test_file(const char* pFilePath) -{ - /* To test seeking we just seek to our target PCM frame and then decode whatever is remaining and compare it against libsndfile. */ - drwav_result result; - libsndfile libsndfile; - drwav wav; - - dr_printf_fixed_with_margin(FILE_NAME_WIDTH, TABLE_MARGIN, "%s", dr_path_file_name(pFilePath)); - - /* First load the decoder from libsndfile. */ - result = libsndfile_init_file(pFilePath, &libsndfile); - if (result != DRWAV_SUCCESS) { - printf(" Failed to open via libsndfile."); - return result; - } - - /* Now load from dr_wav. */ - if (!drwav_init_file_with_metadata(&wav, pFilePath, 0, NULL)) { - printf(" Failed to open via dr_wav."); - libsndfile_uninit(&libsndfile); - return DRWAV_ERROR; /* Failed to load dr_wav decoder. */ - } - - /* At this point we should have both libsndfile and dr_wav decoders open. We can now perform identical operations on each of them and compare. */ - result = decode_test_file_s32(&libsndfile, &wav); - if (result != DRWAV_SUCCESS) { - drwav_uninit(&wav); - libsndfile_uninit(&libsndfile); - return result; - } - - result = decode_test_file_f32(&libsndfile, &wav); - if (result != DRWAV_SUCCESS) { - drwav_uninit(&wav); - libsndfile_uninit(&libsndfile); - return result; - } - - result = decode_test_file_s16(&libsndfile, &wav); - if (result != DRWAV_SUCCESS) { - drwav_uninit(&wav); - libsndfile_uninit(&libsndfile); - return result; - } - - - /* We're done with our decoders. */ - drwav_uninit(&wav); - libsndfile_uninit(&libsndfile); - - if (result == DRWAV_SUCCESS) { - printf(" Passed"); - } - - return result; -} - -drwav_result decode_test_directory(const char* pDirectoryPath) -{ - dr_file_iterator iteratorState; - dr_file_iterator* pFile; - - dr_printf_fixed(FILE_NAME_WIDTH, "%s", pDirectoryPath); - dr_printf_fixed_with_margin(NUMBER_WIDTH, TABLE_MARGIN, "RESULT"); - printf("\n"); - - pFile = dr_file_iterator_begin(pDirectoryPath, &iteratorState); - while (pFile != NULL) { - drwav_result result; - - /* Skip directories for now, but we may want to look at doing recursive file iteration. */ - if (!pFile->isDirectory) { - result = decode_test_file(pFile->absolutePath); - (void)result; - - printf("\n"); - } - - pFile = dr_file_iterator_next(pFile); - } - - return DRWAV_SUCCESS; -} - -drwav_result decode_test() -{ - drwav_result result = DRWAV_SUCCESS; - - /* Directories. */ - { - result = decode_test_directory(DEFAULT_SOURCE_DIR); - (void)result; - } - - return result; -} - -drwav_result decode_profiling() -{ - return DRWAV_SUCCESS; -} - -int main(int argc, char** argv) -{ - drwav_result result = DRWAV_SUCCESS; - drwav_bool32 doTesting = DRWAV_TRUE; - drwav_bool32 doProfiling = DRWAV_TRUE; - - if (dr_argv_is_set(argc, argv, "--onlyprofile")) { - doTesting = DRWAV_FALSE; - } - - if (libsndfile_init_api() != DRWAV_SUCCESS) { - printf("Failed to initialize libsndfile API."); - return -1; - } - - if (doTesting) { - printf("=======================================================================\n"); - printf("DECODE TESTING\n"); - printf("=======================================================================\n"); - result = decode_test(); - if (result != DRWAV_SUCCESS) { - goto done; /* Don't continue if an error occurs during testing. */ - } - printf("\n"); - } else { - printf("=======================================================================\n"); - printf("WARNING: Correctness Tests Disabled\n"); - printf("=======================================================================\n"); - } - - /* Profiling. */ - if (doProfiling) { - printf("=======================================================================\n"); - printf("DECODE PROFILING (LOWER IS BETTER)\n"); - printf("=======================================================================\n"); - result = decode_profiling(); - printf("\n"); - } - -done: - libsndfile_uninit_api(); - return (int)result; -} diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_decoding.cpp b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_decoding.cpp deleted file mode 100644 index a66ae71..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_decoding.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "dr_wav_decoding.c" diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_encoding.c b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_encoding.c deleted file mode 100644 index 8506632..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_encoding.c +++ /dev/null @@ -1,68 +0,0 @@ -#define DR_WAV_IMPLEMENTATION -#include "../../dr_wav.h" -#include - -void generate_sine_wave(float* pOutput, drwav_uint64 frameCount, drwav_uint32 channels, drwav_uint32 sampleRate, float frequency, float* t) -{ - float x = *t; - float a = 1.0f / sampleRate; - drwav_uint64 iFrame; - drwav_uint32 iChannel; - - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - float s = (float)(sin(3.1415965*2 * x * frequency) * 0.25); - for (iChannel = 0; iChannel < channels; iChannel += 1) { - pOutput[iFrame*channels + iChannel] = s; - } - - x += a; - } - - *t = x; -} - -int main(int argc, char** argv) -{ - drwav_data_format format; - drwav wav; - float t = 0; - float tempFrames[4096]; - drwav_uint64 totalFramesToWrite; - drwav_uint64 totalFramesWritten = 0; - - - if (argc < 2) { - printf("No output file specified.\n"); - return -1; - } - - format.container = drwav_container_riff; - format.format = DR_WAVE_FORMAT_IEEE_FLOAT; - format.channels = 2; - format.sampleRate = 44100; - format.bitsPerSample = 32; - if (!drwav_init_file_write(&wav, argv[1], &format, NULL)) { - printf("Failed to open file.\n"); - return -1; - } - - totalFramesToWrite = format.sampleRate * 1; - totalFramesWritten = 0; - - while (totalFramesToWrite > totalFramesWritten) { - drwav_uint64 framesRemaining = totalFramesToWrite - totalFramesWritten; - drwav_uint64 framesToWriteNow = drwav_countof(tempFrames) / format.channels; - if (framesToWriteNow > framesRemaining) { - framesToWriteNow = framesRemaining; - } - - generate_sine_wave(tempFrames, framesToWriteNow, format.channels, format.sampleRate, 400, &t); - drwav_write_pcm_frames(&wav, framesToWriteNow, tempFrames); - - totalFramesWritten += framesToWriteNow; - } - - drwav_uninit(&wav); - - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_playback.c b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_playback.c deleted file mode 100644 index 4410b85..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_playback.c +++ /dev/null @@ -1,70 +0,0 @@ -#define MA_NO_DECODING -#define MA_NO_ENCODING -#define MA_IMPLEMENTATION -#include "../../../miniaudio/miniaudio.h" - -#define DR_WAV_IMPLEMENTATION -#include "../../dr_wav.h" -#include "../common/dr_common.c" - -drwav g_wav; - -void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) -{ - /* Assuming format is always s16 for now. */ - if (pDevice->playback.format == ma_format_s16) { - drwav_read_pcm_frames_s16(&g_wav, frameCount, (drwav_int16*)pOutput); - } else if (pDevice->playback.format == ma_format_f32) { - drwav_read_pcm_frames_f32(&g_wav, frameCount, (float*)pOutput); - } else { - /* Unsupported format. */ - } - - (void)pInput; -} - -int main(int argc, char** argv) -{ - ma_result result; - ma_device device; - ma_device_config deviceConfig; - - if (argc < 2) { - printf("No input file specified."); - return -1; - } - - if (!drwav_init_file_with_metadata(&g_wav, argv[1], 0, NULL)) { - printf("Failed to load file: %s", argv[1]); - return -1; - } - - deviceConfig = ma_device_config_init(ma_device_type_playback); - deviceConfig.playback.format = ma_format_s16; - deviceConfig.playback.channels = g_wav.channels; - deviceConfig.sampleRate = g_wav.sampleRate; - deviceConfig.dataCallback = data_callback; - - result = ma_device_init(NULL, &deviceConfig, &device); - if (result != MA_SUCCESS) { - printf("Failed to initialize playback device."); - drwav_uninit(&g_wav); - return -1; - } - - result = ma_device_start(&device); - if (result != MA_SUCCESS) { - printf("Failed to start playback device."); - ma_device_uninit(&device); - drwav_uninit(&g_wav); - return -1; - } - - printf("Press Enter to quit..."); - getchar(); - - ma_device_uninit(&device); - drwav_uninit(&g_wav); - - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_playback.cpp b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_playback.cpp deleted file mode 100644 index 0127e1a..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_playback.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "dr_wav_playback.c" diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_test_0.c b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_test_0.c deleted file mode 100644 index 7f6a88b..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_test_0.c +++ /dev/null @@ -1,11 +0,0 @@ -#define DR_WAV_IMPLEMENTATION -#include "../../dr_wav.h" - -#include "../common/dr_common.c" - -int main(int argc, char** argv) -{ - (void)argc; - (void)argv; - return 0; -} diff --git a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_test_0.cpp b/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_test_0.cpp deleted file mode 100644 index f446b65..0000000 --- a/source/engine/thirdparty/dr_libs/tests/wav/dr_wav_test_0.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "dr_wav_test_0.c" diff --git a/source/engine/thirdparty/dr_libs/wip/dr_opus.h b/source/engine/thirdparty/dr_libs/wip/dr_opus.h deleted file mode 100644 index f399886..0000000 --- a/source/engine/thirdparty/dr_libs/wip/dr_opus.h +++ /dev/null @@ -1,2565 +0,0 @@ -/* -Opus audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_opus - v0.0.0 (Unreleased) - xxxx-xx-xx - -David Reid - mackron@gmail.com -*/ - -/* ====== WORK-IN-PROGRESSS ====== */ - -#ifndef dr_opus_h -#define dr_opus_h - -#include /* For size_t. */ - -/* Sized types. Prefer built-in types. Fall back to stdint. */ -#ifdef _MSC_VER - #if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wlanguage-extension-token" - #pragma GCC diagnostic ignored "-Wlong-long" - #pragma GCC diagnostic ignored "-Wc++11-long-long" - #endif - typedef signed __int8 dropus_int8; - typedef unsigned __int8 dropus_uint8; - typedef signed __int16 dropus_int16; - typedef unsigned __int16 dropus_uint16; - typedef signed __int32 dropus_int32; - typedef unsigned __int32 dropus_uint32; - typedef signed __int64 dropus_int64; - typedef unsigned __int64 dropus_uint64; - #if defined(__clang__) - #pragma GCC diagnostic pop - #endif - - #if defined(_WIN32) - #if defined(_WIN64) - typedef dropus_uint64 dropus_uintptr; - #else - typedef dropus_uint32 dropus_uintptr; - #endif - #elif defined(__GNUC__) - #if defined(__LP64__) - typedef dropus_uint64 dropus_uintptr; - #else - typedef dropus_uint32 dropus_uintptr; - #endif - #else - typedef dropus_uint64 dropus_uintptr; /* Fallback. */ - #endif -#else - #include - typedef int8_t dropus_int8; - typedef uint8_t dropus_uint8; - typedef int16_t dropus_int16; - typedef uint16_t dropus_uint16; - typedef int32_t dropus_int32; - typedef uint32_t dropus_uint32; - typedef int64_t dropus_int64; - typedef uint64_t dropus_uint64; - typedef uintptr_t dropus_uintptr; -#endif -typedef dropus_uint8 dropus_bool8; -typedef dropus_uint32 dropus_bool32; -#define DROPUS_TRUE 1 -#define DROPUS_FALSE 0 - -typedef void* dropus_handle; -typedef void* dropus_ptr; -typedef void (* dropus_proc)(void); - -#ifndef NULL -#define NULL 0 -#endif - -#if defined(SIZE_MAX) - #define DROPUS_SIZE_MAX SIZE_MAX -#else - #define DROPUS_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ -#endif - -#ifdef _MSC_VER - #define DROPUS_INLINE __forceinline -#elif defined(__GNUC__) - /* - I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when - the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some - case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the - command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue - I am using "__inline__" only when we're compiling in strict ANSI mode. - */ - #if defined(__STRICT_ANSI__) - #define DROPUS_INLINE __inline__ __attribute__((always_inline)) - #else - #define DROPUS_INLINE inline __attribute__((always_inline)) - #endif -#else - #define DROPUS_INLINE -#endif - -#if !defined(DROPUS_API) - #if defined(DROPUS_DLL) - #if defined(_WIN32) - #define DROPUS_DLL_IMPORT __declspec(dllimport) - #define DROPUS_DLL_EXPORT __declspec(dllexport) - #define DROPUS_DLL_PRIVATE static - #else - #if defined(__GNUC__) && __GNUC__ >= 4 - #define DROPUS_DLL_IMPORT __attribute__((visibility("default"))) - #define DROPUS_DLL_EXPORT __attribute__((visibility("default"))) - #define DROPUS_DLL_PRIVATE __attribute__((visibility("hidden"))) - #else - #define DROPUS_DLL_IMPORT - #define DROPUS_DLL_EXPORT - #define DROPUS_DLL_PRIVATE static - #endif - #endif - - #if defined(DR_OPUS_IMPLEMENTATION) || defined(DROPUS_IMPLEMENTATION) - #define DROPUS_API DROPUS_DLL_EXPORT - #else - #define DROPUS_API DROPUS_DLL_IMPORT - #endif - #define DROPUS_PRIVATE DROPUS_DLL_PRIVATE - #else - #define DROPUS_API extern - #define DROPUS_PRIVATE static - #endif -#endif - -typedef int dropus_result; -#define DROPUS_SUCCESS 0 -#define DROPUS_ERROR -1 /* A generic error. */ -#define DROPUS_INVALID_ARGS -2 -#define DROPUS_INVALID_OPERATION -3 -#define DROPUS_OUT_OF_MEMORY -4 -#define DROPUS_OUT_OF_RANGE -5 -#define DROPUS_ACCESS_DENIED -6 -#define DROPUS_DOES_NOT_EXIST -7 -#define DROPUS_ALREADY_EXISTS -8 -#define DROPUS_TOO_MANY_OPEN_FILES -9 -#define DROPUS_INVALID_FILE -10 -#define DROPUS_TOO_BIG -11 -#define DROPUS_PATH_TOO_LONG -12 -#define DROPUS_NAME_TOO_LONG -13 -#define DROPUS_NOT_DIRECTORY -14 -#define DROPUS_IS_DIRECTORY -15 -#define DROPUS_DIRECTORY_NOT_EMPTY -16 -#define DROPUS_END_OF_FILE -17 -#define DROPUS_NO_SPACE -18 -#define DROPUS_BUSY -19 -#define DROPUS_IO_ERROR -20 -#define DROPUS_INTERRUPT -21 -#define DROPUS_UNAVAILABLE -22 -#define DROPUS_ALREADY_IN_USE -23 -#define DROPUS_BAD_ADDRESS -24 -#define DROPUS_BAD_SEEK -25 -#define DROPUS_BAD_PIPE -26 -#define DROPUS_DEADLOCK -27 -#define DROPUS_TOO_MANY_LINKS -28 -#define DROPUS_NOT_IMPLEMENTED -29 -#define DROPUS_NO_MESSAGE -30 -#define DROPUS_BAD_MESSAGE -31 -#define DROPUS_NO_DATA_AVAILABLE -32 -#define DROPUS_INVALID_DATA -33 -#define DROPUS_TIMEOUT -34 -#define DROPUS_NO_NETWORK -35 -#define DROPUS_NOT_UNIQUE -36 -#define DROPUS_NOT_SOCKET -37 -#define DROPUS_NO_ADDRESS -38 -#define DROPUS_BAD_PROTOCOL -39 -#define DROPUS_PROTOCOL_UNAVAILABLE -40 -#define DROPUS_PROTOCOL_NOT_SUPPORTED -41 -#define DROPUS_PROTOCOL_FAMILY_NOT_SUPPORTED -42 -#define DROPUS_ADDRESS_FAMILY_NOT_SUPPORTED -43 -#define DROPUS_SOCKET_NOT_SUPPORTED -44 -#define DROPUS_CONNECTION_RESET -45 -#define DROPUS_ALREADY_CONNECTED -46 -#define DROPUS_NOT_CONNECTED -47 -#define DROPUS_CONNECTION_REFUSED -48 -#define DROPUS_NO_HOST -49 -#define DROPUS_IN_PROGRESS -50 -#define DROPUS_CANCELLED -51 -#define DROPUS_MEMORY_ALREADY_MAPPED -52 -#define DROPUS_AT_END -53 -#define DROPUS_CRC_MISMATCH -100 -#define DROPUS_BAD_DATA -101 - -/*********************************************************************************************************************************************************** - -Low-Level Opus Stream API - -This API is where the low-level decoding takes place. In order to use this, you must know the packet structure of the Opus stream. This is usually the job of -encapsulations such as Ogg and Matroska. - -************************************************************************************************************************************************************/ -#define DROPUS_MAX_OPUS_FRAMES_PER_PACKET 48 /* RFC 6716 - Section 3.2.5 */ -#define DROPUS_MAX_PCM_FRAMES_PER_PACKET 6144 /* RFC 6716 - Section 3.2.5. Maximum of 120ms. Maximum rate is 48kHz. 6144 = 120*48. */ - -typedef enum -{ - dropus_mode_silk, - dropus_mode_celt, - dropus_mode_hybrid -} dropus_mode; - -typedef struct -{ - dropus_uint16 sizeInBytes; -} dropus_stream_frame; - -typedef struct -{ - dropus_uint8 toc; /* TOC byte. RFC 6716 - Section 3.1 */ - dropus_stream_frame frames[DROPUS_MAX_OPUS_FRAMES_PER_PACKET]; -} dropus_stream_packet; - -typedef struct -{ - dropus_stream_packet packet; /* The current packet. */ - struct - { - dropus_int32 w0_Q13_prev; /* Previous stereo weights. */ - dropus_int32 w1_Q13_prev; - } silk; -} dropus_stream; - -/* -Initializes a new low-level Opus stream object. -*/ -DROPUS_API dropus_result dropus_stream_init(dropus_stream* pOpusStream); - -/* -Decodes a packet from raw compressed data. -*/ -DROPUS_API dropus_result dropus_stream_decode_packet(dropus_stream* pOpusStream, const void* pData, size_t dataSize); - - - -/*********************************************************************************************************************************************************** - -High-Level Opus Decoding API - -************************************************************************************************************************************************************/ -typedef enum -{ - dropus_seek_origin_start, - dropus_seek_origin_current -} dropus_seek_origin; - -typedef size_t (* dropus_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -typedef dropus_bool32 (* dropus_seek_proc)(void* pUserData, int offset, dropus_seek_origin origin); - -typedef struct -{ - void* pUserData; - void* (* onMalloc)(size_t sz, void* pUserData); - void* (* onRealloc)(void* p, size_t sz, void* pUserData); - void (* onFree)(void* p, void* pUserData); -} dropus_allocation_callbacks; - -typedef struct -{ - dropus_read_proc onRead; - dropus_seek_proc onSeek; - void* pUserData; - dropus_allocation_callbacks allocationCallbacks; - void* pFile; /* Only used for decoders that were opened against a file. */ - struct - { - const dropus_uint8* pData; - size_t dataSize; - size_t currentReadPos; - } memory; /* Only used for decoders that were opened against a block of memory. */ -} dropus; - -/* -Initializes a pre-allocated decoder object from callbacks. -*/ -DROPUS_API dropus_result dropus_init(dropus* pOpus, dropus_read_proc onRead, dropus_seek_proc onSeek, void* pUserData, const dropus_allocation_callbacks* pAllocationCallbacks); - -#ifndef DR_OPUS_NO_STDIO -/* -Initializes a pre-allocated decoder object from a file. - -This keeps hold of the file handle throughout the lifetime of the decoder and closes it in dropus_uninit(). -*/ -DROPUS_API dropus_result dropus_init_file(dropus* pOpus, const char* pFilePath, const dropus_allocation_callbacks* pAllocationCallbacks); -DROPUS_API dropus_result dropus_init_file_w(dropus* pOpus, const wchar_t* pFilePath, const dropus_allocation_callbacks* pAllocationCallbacks); -#endif - -/* -Initializes a pre-allocated decoder object from a block of memory. - -This does not make a copy of the memory. -*/ -DROPUS_API dropus_result dropus_init_memory(dropus* pOpus, const void* pData, size_t dataSize, const dropus_allocation_callbacks* pAllocationCallbacks); - -/* -Uninitializes an Opus decoder. -*/ -DROPUS_API void dropus_uninit(dropus* pOpus); - - - -/************************************************************************************************************************************************************ - -Utilities - -************************************************************************************************************************************************************/ -/* -Retrieves a human readable description of the given result code. -*/ -DROPUS_API const char* dropus_result_description(dropus_result result); - -/* -Allocates memory from callbacks. - - -Parameters ----------- -sz (in) - The size of the allocation in bytes. - -pAllocationCallbacks (in, optional) - A pointer to the `dropus_allocation_callbacks` object containing pointers to the allocation routines. - - -Return Value ------------- -A pointer to the allocated block of memory. NULL if an error occurs. - - -Remarks -------- -`pAllocationCallbacks` can be NULL, in which case DROPUS_MALLOC() will be used. Otherwise, if `pAllocationCallbacks` is not null, either `onMalloc` or -`onRealloc` must be set. If `onMalloc` is NULL, it will fall back to `onRealloc`. If both `onMalloc` and `onRealloc` are NULL, NULL will be returned. -*/ -DROPUS_API void* dropus_malloc(size_t sz, const dropus_allocation_callbacks* pAllocationCallbacks); - -/* -Reallocates memory from callbacks. - - -Parameters ----------- -p (in) - A pointer to the memory being reallocated. - -sz (in) - The size of the allocation in bytes. - -pAllocationCallbacks (in, optional) - A pointer to the `dropus_allocation_callbacks` object containing pointers to the allocation routines. - - -Return Value ------------- -A pointer to the allocated block of memory. NULL if an error occurs. - - -Remarks -------- -`pAllocationCallbacks` can be NULL, in which case DROPUS_REALLOC() will be used. If `onRealloc` is NULL, this will fail and NULL will be returned. -*/ -DROPUS_API void* dropus_realloc(void* p, size_t sz, const dropus_allocation_callbacks* pAllocationCallbacks); - -/* -Frees memory allocated by `dropus_malloc()` or `dropus_realloc()`. - - -Parameters ----------- -p (in) - A pointer to the memory being freed. - - -Remarks -------- -`pAllocationCallbacks` can be NULL in which case DROPUS_FREE() will be used. If `onFree` is NULL, this will be a no-op. -*/ -DROPUS_API void dropus_free(void* p, const dropus_allocation_callbacks* pAllocationCallbacks); - - -#endif /* dr_opus_h */ - -/************************************************************************************************************************************************************ - ************************************************************************************************************************************************************ - - IMPLEMENTATION - - ************************************************************************************************************************************************************ - ************************************************************************************************************************************************************/ -#if defined(DR_OPUS_IMPLEMENTATION) || defined(DROPUS_IMPLEMENTATION) -#include -#include -#ifndef DR_OPUS_NO_STDIO -#include -#include /* For wcslen(), wcsrtombs() */ -#endif - -/* CPU Architecture. */ -#if defined(__x86_64__) || defined(_M_X64) - #define DROPUS_X64 -#elif defined(__i386) || defined(_M_IX86) - #define DROPUS_X86 -#elif defined(__arm__) || defined(_M_ARM) - #define DROPUS_ARM -#endif - -/* Compile-time CPU feature support. */ -#if !defined(DR_OPUS_NO_SIMD) && (defined(DROPUS_X86) || defined(DROPUS_X64)) - #if defined(_MSC_VER) && !defined(__clang__) - #if _MSC_VER >= 1400 - #include - static DROPUS_INLINE void dropus__cpuid(int info[4], int fid) - { - __cpuid(info, fid); - } - #else - #define DROPUS_NO_CPUID - #endif - #else - #if defined(__GNUC__) || defined(__clang__) - static DROPUS_INLINE void dropus__cpuid(int info[4], int fid) - { - /* - It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the - specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for - supporting different assembly dialects. - - What's basically happening is that we're saving and restoring the ebx register manually. - */ - #if defined(DROPUS_X86) && defined(__PIC__) - __asm__ __volatile__ ( - "xchg{l} {%%}ebx, %k1;" - "cpuid;" - "xchg{l} {%%}ebx, %k1;" - : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) - ); - #else - __asm__ __volatile__ ( - "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) - ); - #endif - } - #else - #define DROPUS_NO_CPUID - #endif - #endif -#else - #define DROPUS_NO_CPUID -#endif - - -#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DROPUS_X86) || defined(DROPUS_X64)) - #define DROPUS_HAS_LZCNT_INTRINSIC -#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) - #define DROPUS_HAS_LZCNT_INTRINSIC -#elif defined(__clang__) - #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) - #define DROPUS_HAS_LZCNT_INTRINSIC - #endif -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - #define DROPUS_HAS_BYTESWAP16_INTRINSIC - #define DROPUS_HAS_BYTESWAP32_INTRINSIC - #define DROPUS_HAS_BYTESWAP64_INTRINSIC -#elif defined(__clang__) - #if __has_builtin(__builtin_bswap16) - #define DROPUS_HAS_BYTESWAP16_INTRINSIC - #endif - #if __has_builtin(__builtin_bswap32) - #define DROPUS_HAS_BYTESWAP32_INTRINSIC - #endif - #if __has_builtin(__builtin_bswap64) - #define DROPUS_HAS_BYTESWAP64_INTRINSIC - #endif -#elif defined(__GNUC__) - #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define DROPUS_HAS_BYTESWAP32_INTRINSIC - #define DROPUS_HAS_BYTESWAP64_INTRINSIC - #endif - #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #define DROPUS_HAS_BYTESWAP16_INTRINSIC - #endif -#endif - - -#ifndef DROPUS_ASSERT -#include -#define DROPUS_ASSERT(expression) assert(expression) -#endif -#ifndef DROPUS_MALLOC -#define DROPUS_MALLOC(sz) malloc((sz)) -#endif -#ifndef DROPUS_REALLOC -#define DROPUS_REALLOC(p, sz) realloc((p), (sz)) -#endif -#ifndef DROPUS_FREE -#define DROPUS_FREE(p) free((p)) -#endif -#ifndef DROPUS_COPY_MEMORY -#define DROPUS_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) -#endif -#ifndef DROPUS_ZERO_MEMORY -#define DROPUS_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) -#endif -#ifndef DROPUS_ZERO_OBJECT -#define DROPUS_ZERO_OBJECT(p) DROPUS_ZERO_MEMORY((p), sizeof(*(p))) -#endif - -#ifndef DROPUS_MIN -#define DROPUS_MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif -#ifndef DROPUS_MAX -#define DROPUS_MAX(x, y) (((x) > (y)) ? (x) : (y)) -#endif -#ifndef DROPUS_COUNTOF -#define DROPUS_COUNTOF(p) (sizeof(p) / sizeof((p)[0])) -#endif - - -/*********************************** -Endian Management -************************************/ -static DROPUS_INLINE dropus_bool32 dropus__is_little_endian() -{ -#if defined(DROPUS_X86) || defined(DROPUS_X64) - return DROPUS_TRUE; -#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN - return DROPUS_TRUE; -#else - int n = 1; - return (*(char*)&n) == 1; -#endif -} - -static DROPUS_INLINE dropus_uint16 dropus__swap_endian_uint16(dropus_uint16 n) -{ -#ifdef DROPUS_HAS_BYTESWAP16_INTRINSIC - #if defined(_MSC_VER) - return _byteswap_ushort(n); - #elif defined(__GNUC__) || defined(__clang__) - return __builtin_bswap16(n); - #else - #error "This compiler does not support the byte swap intrinsic." - #endif -#else - return ((n & 0xFF00) >> 8) | - ((n & 0x00FF) << 8); -#endif -} - -static DROPUS_INLINE dropus_uint32 dropus__swap_endian_uint32(dropus_uint32 n) -{ -#ifdef DROPUS_HAS_BYTESWAP32_INTRINSIC - #if defined(_MSC_VER) - return _byteswap_ulong(n); - #elif defined(__GNUC__) || defined(__clang__) - return __builtin_bswap32(n); - #else - #error "This compiler does not support the byte swap intrinsic." - #endif -#else - return ((n & 0xFF000000) >> 24) | - ((n & 0x00FF0000) >> 8) | - ((n & 0x0000FF00) << 8) | - ((n & 0x000000FF) << 24); -#endif -} - -static DROPUS_INLINE dropus_uint64 dropus__swap_endian_uint64(dropus_uint64 n) -{ -#ifdef DROPUS_HAS_BYTESWAP64_INTRINSIC - #if defined(_MSC_VER) - return _byteswap_uint64(n); - #elif defined(__GNUC__) || defined(__clang__) - return __builtin_bswap64(n); - #else - #error "This compiler does not support the byte swap intrinsic." - #endif -#else - return ((n & (dropus_uint64)0xFF00000000000000) >> 56) | - ((n & (dropus_uint64)0x00FF000000000000) >> 40) | - ((n & (dropus_uint64)0x0000FF0000000000) >> 24) | - ((n & (dropus_uint64)0x000000FF00000000) >> 8) | - ((n & (dropus_uint64)0x00000000FF000000) << 8) | - ((n & (dropus_uint64)0x0000000000FF0000) << 24) | - ((n & (dropus_uint64)0x000000000000FF00) << 40) | - ((n & (dropus_uint64)0x00000000000000FF) << 56); -#endif -} - - -static DROPUS_INLINE dropus_uint16 dropus__be2host_16(dropus_uint16 n) -{ - if (dropus__is_little_endian()) { - return dropus__swap_endian_uint16(n); - } - - return n; -} - -static DROPUS_INLINE dropus_uint32 dropus__be2host_32(dropus_uint32 n) -{ - if (dropus__is_little_endian()) { - return dropus__swap_endian_uint32(n); - } - - return n; -} - -static DROPUS_INLINE dropus_uint64 dropus__be2host_64(dropus_uint64 n) -{ - if (dropus__is_little_endian()) { - return dropus__swap_endian_uint64(n); - } - - return n; -} - - -static DROPUS_INLINE dropus_uint16 dropus__le2host_16(dropus_uint16 n) -{ - if (!dropus__is_little_endian()) { - return dropus__swap_endian_uint16(n); - } - - return n; -} - -static DROPUS_INLINE dropus_uint32 dropus__le2host_32(dropus_uint32 n) -{ - if (!dropus__is_little_endian()) { - return dropus__swap_endian_uint32(n); - } - - return n; -} - -static DROPUS_INLINE dropus_uint64 dropus__le2host_64(dropus_uint64 n) -{ - if (!dropus__is_little_endian()) { - return dropus__swap_endian_uint64(n); - } - - return n; -} - - -/*********************************************************************************************************************************************************** - -Low-Level Opus Stream API - -************************************************************************************************************************************************************/ -#define DROPUS_MAX_FRAME_SIZE_IN_BYTES 1275 /* RFC 6716 - Section 3.4 [R2] */ -#define DROPUS_MAX_PACKET_SIZE_IN_BYTES DROPUS_MAX_FRAME_SIZE_IN_BYTES*DROPUS_MAX_OPUS_FRAMES_PER_PACKET - -/*********************************** -RFC 6716 - Section 3.1 The TOC Byte -************************************/ -static DROPUS_INLINE dropus_uint8 dropus_toc_config(dropus_uint8 toc) -{ - return (toc & 0xF8) >> 3; -} - -static DROPUS_INLINE dropus_uint8 dropus_toc_s(dropus_uint8 toc) -{ - return (toc & 0x04) >> 2; -} - -static DROPUS_INLINE dropus_uint8 dropus_toc_c(dropus_uint8 toc) -{ - return (toc & 0x03); -} - -static DROPUS_INLINE dropus_mode dropus_toc_config_mode(dropus_uint8 config) -{ - /* Table 2 in RFC 6716 */ - static dropus_mode modes[32] = { - dropus_mode_silk, dropus_mode_silk, dropus_mode_silk, dropus_mode_silk, /* 0...3 */ - dropus_mode_silk, dropus_mode_silk, dropus_mode_silk, dropus_mode_silk, /* 4...7 */ - dropus_mode_silk, dropus_mode_silk, dropus_mode_silk, dropus_mode_silk, /* 8...11 */ - dropus_mode_hybrid, dropus_mode_hybrid, /* 12...13 */ - dropus_mode_hybrid, dropus_mode_hybrid, /* 14...15 */ - dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, /* 16...19 */ - dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, /* 20...23 */ - dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, /* 24...27 */ - dropus_mode_celt, dropus_mode_celt, dropus_mode_celt, dropus_mode_celt /* 28...31 */ - }; - - DROPUS_ASSERT(config < 32); - return modes[config]; -} - -static DROPUS_INLINE dropus_mode dropus_toc_mode(dropus_uint8 toc) -{ - return dropus_toc_config_mode(dropus_toc_config(toc)); -} - -static DROPUS_INLINE dropus_uint32 dropus_toc_config_sample_rate(dropus_uint8 config) -{ - /* Table 2 with Table 1 in RFC 6716 */ - static dropus_uint32 rates[32] = { - 8000, 8000, 8000, 8000, /* 0...3 */ - 12000, 12000, 12000, 12000, /* 4...7 */ - 16000, 16000, 16000, 16000, /* 8...11 */ - 24000, 24000, /* 12...13 */ - 48000, 48000, /* 14...15 */ - 8000, 8000, 8000, 8000, /* 16...19 */ - 16000, 16000, 16000, 16000, /* 20...23 */ - 24000, 24000, 24000, 24000, /* 24...27 */ - 48000, 48000, 48000, 48000 /* 28...31 */ - }; - - DROPUS_ASSERT(config < 32); - return rates[config]; -} - -static DROPUS_INLINE dropus_uint32 dropus_toc_sample_rate(dropus_uint8 toc) -{ - return dropus_toc_config_sample_rate(dropus_toc_config(toc)); -} - -static DROPUS_INLINE dropus_uint32 dropus_toc_sample_rate_ms(dropus_uint8 toc) -{ - return dropus_toc_sample_rate(toc) / 1000; -} - -static DROPUS_INLINE dropus_uint32 dropus_toc_config_frame_size_in_pcm_frames(dropus_uint8 config) -{ - /* Table 2 with Table 1 in RFC 6716 */ - static dropus_uint32 sizes[32] = { - 80, 160, 320, 480, /* 0...3 */ - 120, 240, 480, 720, /* 4...7 */ - 160, 320, 640, 960, /* 8...11 */ - 240, 480, /* 12...13 */ - 480, 960, /* 14...15 */ - 20, 40, 80, 160, /* 16...19 */ - 40, 80, 160, 320, /* 20...23 */ - 60, 120, 240, 480, /* 24...27 */ - 120, 240, 480, 960 /* 28...31 */ - }; - - DROPUS_ASSERT(config < 32); - return sizes[config]; -} - -static DROPUS_INLINE dropus_uint32 dropus_toc_frame_size_in_pcm_frames(dropus_uint8 toc) -{ - return dropus_toc_config_frame_size_in_pcm_frames(dropus_toc_config(toc)); -} - -static DROPUS_INLINE dropus_uint8 dropus_toc_config_silk_frame_count(dropus_uint8 config) -{ - /* Table 2 in RFC 6716 */ - static dropus_uint8 counts[32] = { - 1, 1, 2, 3, /* 0...3 */ - 1, 1, 2, 3, /* 4...7 */ - 1, 1, 2, 3, /* 8...11 */ - 1, 1, /* 12...13 */ - 1, 1, /* 14...15 */ - 0, 0, 0, 0, /* 16...19 */ /* Here down is CELT-only. */ - 0, 0, 0, 0, /* 20...23 */ - 0, 0, 0, 0, /* 24...27 */ - 0, 0, 0, 0 /* 28...31 */ - }; - - DROPUS_ASSERT(config < 32); - return counts[config]; -} - -static DROPUS_INLINE dropus_uint8 dropus_toc_silk_frame_count(dropus_uint8 toc) -{ - return dropus_toc_config_silk_frame_count(dropus_toc_config(toc)); -} - -static DROPUS_INLINE dropus_int32 dropus_Q13(dropus_uint16 index) -{ - /* Table 7 in RFC 6716 */ - static dropus_int32 Q13[16] = { - -13732, -10050, -8266, -7526, - -6500, -5000, -2950, -820, - 820, 2950, 5000, 6500, - 7526, 8266, 10050, 13732 - }; - - DROPUS_ASSERT(index < DROPUS_COUNTOF(Q13)); - return Q13[index]; -} - - -typedef struct -{ - const dropus_uint8* pData; - dropus_uint16 dataSize; - dropus_uint16 readPointer; - dropus_uint8 b0; - dropus_uint32 rng; /* RFC 6716 - Section 4.1 - Both val and rng are 32-bit unsigned integer values. */ - dropus_uint32 val; /* ^^^ */ -} dropus_range_decoder; - -static DROPUS_INLINE void dropus_range_decoder_normalize(dropus_range_decoder* pRangeDecoder) -{ - dropus_uint8 sym; - dropus_uint8 b1; - - DROPUS_ASSERT(pRangeDecoder != NULL); - - while (pRangeDecoder->rng <= 0x800000) { - pRangeDecoder->rng = (pRangeDecoder->rng << 8); /* RFC 6716 - Section 4.1.2.1 - First, it sets rng to (rng<<8). */ - - /* RFC 6716 - Section 4.1.2.1 - If no more input bytes remain, it uses zero bits instead. */ - if (pRangeDecoder->dataSize > pRangeDecoder->readPointer) { - b1 = pRangeDecoder->pData[pRangeDecoder->readPointer++]; - } else { - b1 = 0; - } - - /* RFC 6716 - Section 4.1.2.1 - ... using the leftover bit buffered from the previous byte as the high bit and the top 7 bits of the byte just read as the other 7 bits of sym. */ - sym = ((pRangeDecoder->b0 & 0x01) << 7) | (b1 >> 7); - - /* RFC 6716 - Section 4.1.2.1 - The remaining bit in the byte just read is buffered for use in the next iteration. */ - pRangeDecoder->b0 = (b1 & 0x01); - - /* val */ - pRangeDecoder->val = ((pRangeDecoder->val << 8) + (255 - sym)) & 0x7FFFFFFF; - } - - DROPUS_ASSERT(pRangeDecoder->rng > 0x800000); -} - -static DROPUS_INLINE void dropus_range_decoder_init(const dropus_uint8* pData, dropus_uint16 dataSize, dropus_range_decoder* pRangeDecoder) -{ - DROPUS_ASSERT(pRangeDecoder != NULL); - - pRangeDecoder->pData = pData; - pRangeDecoder->dataSize = dataSize; - pRangeDecoder->readPointer = 0; - - pRangeDecoder->b0 = 0; /* RFC 6716 - Section 4.1.1 - Let b0 be an 8-bit unsigned integer containing first input byte (or containing zero if there are no bytes in this Opus frame). */ - if (dataSize > 0) { - pRangeDecoder->b0 = pData[pRangeDecoder->readPointer++]; - } - - pRangeDecoder->rng = 128; /* RFC 6716 - Section 4.1.1 - The decoder initializes rng to 128 ... */ - pRangeDecoder->val = 127 - (pRangeDecoder->b0 >> 1); /* ... and initializes val to (127 - (b0>>1)) ...*/ - - /* - It saves the remaining bit, (b0&1), for use in the renormalization - procedure described in Section 4.1.2.1, which the decoder invokes - immediately after initialization to read additional bits and - establish the invariant that rng > 2**23. - */ - dropus_range_decoder_normalize(pRangeDecoder); -} - -static DROPUS_INLINE dropus_uint16 dropus_range_decoder_fs(dropus_range_decoder* pRangeDecoder, dropus_uint16 ft) -{ - /* Implements RFC 6716 - Section 4.1.2 (first step) */ - - DROPUS_ASSERT(pRangeDecoder != NULL); - /*DROPUS_ASSERT(ft <= 65535);*/ /* RFC 6716 - Section 4.1 */ /* Always true due to range limit of `ft`. */ - - return (dropus_uint16)(ft - DROPUS_MIN((pRangeDecoder->val / (pRangeDecoder->rng/ft)) + 1, ft)); -} - -static DROPUS_INLINE dropus_uint16 dropus_range_decoder_k(dropus_uint16* f, dropus_uint16 n, dropus_uint16 fs, dropus_uint16* flOut, dropus_uint16* fhOut) -{ - dropus_uint8 i; - dropus_uint16 k = 0; - dropus_uint16 fl = 0; - dropus_uint16 fh = 0; - for (i = 0; i < n; ++i) { - fh = fl + f[i]; - if (fl <= fs && fs < fh) { - k = i; - break; - } - - fl += f[i]; - } - - *flOut = fl; - *fhOut = fh; - return k; -} - -static DROPUS_INLINE dropus_uint16 dropus_range_decoder_update(dropus_range_decoder* pRangeDecoder, dropus_uint16* f, dropus_uint16 n, dropus_uint16 ft, dropus_uint16 fs) -{ - /* Implements RFC 6716 - Section 4.1.2 (second step) */ - dropus_uint16 k; - dropus_uint16 fl; - dropus_uint16 fh; - - DROPUS_ASSERT(pRangeDecoder != NULL); - DROPUS_ASSERT(f != NULL); - DROPUS_ASSERT(n > 0); - DROPUS_ASSERT(ft > 0); - - k = dropus_range_decoder_k(f, n, fs, &fl, &fh); - - /*DROPUS_ASSERT(0 <= fl);*/ /* RFC 6716 - Section 4.1 */ /* Always true due to `fl` being unsigned. */ - DROPUS_ASSERT(fl < fh); /* RFC 6716 - Section 4.1 */ - DROPUS_ASSERT(fh <= ft); /* RFC 6716 - Section 4.1 */ - /*DROPUS_ASSERT(ft <= 65535);*/ /* RFC 6716 - Section 4.1 */ /* Always true due to range limit of `ft`. */ - - /* val */ - pRangeDecoder->val = pRangeDecoder->val - (pRangeDecoder->rng/ft) * (ft - fh); - - /* rng */ - if (fl > 0) { /* RFC 6716 - Section 4.1.2 - If fl[k] is greater than zero, then the decoder updates rng using... */ - pRangeDecoder->rng = (pRangeDecoder->rng/ft) * (fh - fl); - } else { /* RFC 6716 - Section 4.1.2 - Otherwise, it updates rng using... */ - pRangeDecoder->rng = pRangeDecoder->rng - (pRangeDecoder->rng/ft) * (ft - fh); - } - - /* - RFC 6716 - Section 4.1.2 - - After the updates, implemented by ec_dec_update() (entdec.c), the - decoder normalizes the range using the procedure in the next section, - and returns the index k. - */ - dropus_range_decoder_normalize(pRangeDecoder); - - return k; -} - -static DROPUS_INLINE dropus_uint16 dropus_range_decoder_decode(dropus_range_decoder* pRangeDecoder, dropus_uint16* f, dropus_uint16 n, dropus_uint16 ft) -{ - dropus_uint16 fs; - - DROPUS_ASSERT(pRangeDecoder != NULL); - DROPUS_ASSERT(f != NULL); - DROPUS_ASSERT(n > 0); - DROPUS_ASSERT(ft > 0); - - /* Step 1 from RFC 6716 - Section 4.1.2. */ - fs = dropus_range_decoder_fs(pRangeDecoder, ft); - - /* Step 2 from RFC 6716 - Section 4.1.2. */ - return dropus_range_decoder_update(pRangeDecoder, f, n, ft, fs); -} - - -DROPUS_API dropus_result dropus_stream_init(dropus_stream* pOpusStream) -{ - if (pOpusStream == NULL) { - return DROPUS_INVALID_ARGS; - } - - DROPUS_ZERO_OBJECT(pOpusStream); - - return DROPUS_SUCCESS; -} - - -#define DROPUS_MAX_SILK_FRAME_SIZE_IN_PCM_FRAMES 20*16 /* 20 = 20ms SILK frame length. 16 = Wideband sample rate. */ - - -typedef enum -{ - dropus_silk_frame_regularity_regular, - dropus_silk_frame_regularity_lbrr, -} dropus_silk_frame_regularity; - -typedef struct -{ - union - { - dropus_int16 s16[DROPUS_MAX_SILK_FRAME_SIZE_IN_PCM_FRAMES]; - float f32[DROPUS_MAX_SILK_FRAME_SIZE_IN_PCM_FRAMES]; - } pcm; -} dropus_silk_frame; - -static dropus_result dropus_stream_decode_silk_frame(dropus_stream* pOpusStream, dropus_range_decoder* pRD, dropus_silk_frame_regularity regularity, dropus_uint8 iSILKFrame, dropus_uint8 iChannel, dropus_uint8* pFlagsVAD, dropus_uint8* pFlagsLBRR, dropus_silk_frame* pSILKFrame) -{ - dropus_uint8 channels; - dropus_uint32 w0_Q13 = 0; - dropus_uint32 w1_Q13 = 0; - dropus_uint8 midOnlyFlag = 0; - - channels = dropus_toc_s(pOpusStream->packet.toc) + 1; - - /* - RFC 6716 - Section 4.2.7.1 - - ... these weights are coded if and only if - - This is a stereo Opus frame (Section 3.1), and - - The current SILK frame corresponds to the mid channel. - */ - if (channels == 2 && iChannel == 0) { - dropus_uint16 f_Stage1[] = {7, 2, 1, 1, 1, 10, 24, 8, 1, 1, 3, 23, 92, 23, 3, 1, 1, 8, 24, 10, 1, 1, 1, 2, 7}, ft_Stage1 = 256; - dropus_uint16 f_Stage2[] = {85, 86, 85}, ft_Stage2 = 256; - dropus_uint16 f_Stage3[] = {51, 51, 52, 51, 51}, ft_Stage3 = 256; - dropus_uint16 n; - dropus_uint16 i0, i1, i2, i3; - dropus_uint16 wi0, wi1; - - n = dropus_range_decoder_decode(pRD, f_Stage1, DROPUS_COUNTOF(f_Stage1), ft_Stage1); - i0 = dropus_range_decoder_decode(pRD, f_Stage2, DROPUS_COUNTOF(f_Stage2), ft_Stage2); - i1 = dropus_range_decoder_decode(pRD, f_Stage3, DROPUS_COUNTOF(f_Stage3), ft_Stage3); - i2 = dropus_range_decoder_decode(pRD, f_Stage2, DROPUS_COUNTOF(f_Stage2), ft_Stage2); - i3 = dropus_range_decoder_decode(pRD, f_Stage3, DROPUS_COUNTOF(f_Stage3), ft_Stage3); - - wi0 = i0 + 3 * (n / 5); - wi1 = i2 + 3 * (n % 5); - - /* Note that w0_Q13 depends on w1_Q13 so must be calculated afterwards. */ - w1_Q13 = dropus_Q13(wi1) + (((dropus_Q13((dropus_uint16)(wi1 + 1)) - dropus_Q13(wi1)) * 6554) >> 16) * ((2 * i3) + 1); - w0_Q13 = dropus_Q13(wi0) + (((dropus_Q13((dropus_uint16)(wi0 + 1)) - dropus_Q13(wi0)) * 6554) >> 16) * ((2 * i1) + 1) - w1_Q13; - - /* RFC 6716 - Section 4.2.7.2 - Mid-Only Flag */ - { - dropus_uint16 f_MOF[] = {192, 64}, ft_MOF = 256; - midOnlyFlag = (dropus_uint8)dropus_range_decoder_decode(pRD, f_MOF, DROPUS_COUNTOF(f_MOF), ft_MOF); - } - } -} - -static dropus_result dropus_stream_decode_silk_frame__mono(dropus_stream* pOpusStream, dropus_range_decoder* pRD, dropus_silk_frame_regularity regularity, dropus_uint8 iSILKFrame, dropus_uint8* pFlagsVAD, dropus_uint8* pFlagsLBRR, dropus_silk_frame* pSILKFrames) -{ - -} - -static dropus_result dropus_stream_decode_silk_frame__stereo(dropus_stream* pOpusStream, dropus_range_decoder* pRD, dropus_silk_frame_regularity regularity, dropus_uint8 iSILKFrame, dropus_uint8* pFlagsVAD, dropus_uint8* pFlagsLBRR, dropus_silk_frame* pSILKFrames) -{ - dropus_uint8 iChannel; - dropus_uint16 f_Stage1[] = {7, 2, 1, 1, 1, 10, 24, 8, 1, 1, 3, 23, 92, 23, 3, 1, 1, 8, 24, 10, 1, 1, 1, 2, 7}, ft_Stage1 = 256; - dropus_uint16 f_Stage2[] = {85, 86, 85}, ft_Stage2 = 256; - dropus_uint16 f_Stage3[] = {51, 51, 52, 51, 51}, ft_Stage3 = 256; - dropus_uint16 n; - dropus_uint16 i0, i1, i2, i3; - dropus_uint16 wi0, wi1; - - /* - RFC 6716 - Section 4.2.7.1 - - ... these weights are coded if and only if - - This is a stereo Opus frame (Section 3.1), and - - The current SILK frame corresponds to the mid channel. - */ - - for (iChannel = 0; iChannel < 2; iChannel += 1) { - /* Don't include LBRR frames if we don't have one. */ - if (regularity == dropus_silk_frame_regularity_lbrr && (pFlagsLBRR[iChannel] & (1 << iSILKFrame)) == 0) { - continue; - } - - /* The mid channel is always the first one in a SILK frame. */ - if (iChannel == 0) { - n = dropus_range_decoder_decode(pRD, f_Stage1, DROPUS_COUNTOF(f_Stage1), ft_Stage1); - i0 = dropus_range_decoder_decode(pRD, f_Stage2, DROPUS_COUNTOF(f_Stage2), ft_Stage2); - i1 = dropus_range_decoder_decode(pRD, f_Stage3, DROPUS_COUNTOF(f_Stage3), ft_Stage3); - i2 = dropus_range_decoder_decode(pRD, f_Stage2, DROPUS_COUNTOF(f_Stage2), ft_Stage2); - i3 = dropus_range_decoder_decode(pRD, f_Stage3, DROPUS_COUNTOF(f_Stage3), ft_Stage3); - - wi0 = i0 + 3 * (n / 5); - wi1 = i2 + 3 * (n % 5); - - #if 0 - /* Note that w0_Q13 depends on w1_Q13 so must be calculated afterwards. */ - w1_Q13 = dropus_Q13(wi1) + (((dropus_Q13((dropus_uint16)(wi1 + 1)) - dropus_Q13(wi1)) * 6554) >> 16) * ((2 * i3) + 1); - w0_Q13 = dropus_Q13(wi0) + (((dropus_Q13((dropus_uint16)(wi0 + 1)) - dropus_Q13(wi0)) * 6554) >> 16) * ((2 * i1) + 1) - w1_Q13; - - /* RFC 6716 - Section 4.2.7.2 - Mid-Only Flag */ - { - dropus_uint16 f_MOF[] = {192, 64}, ft_MOF = 256; - midOnlyFlag = (dropus_uint8)dropus_range_decoder_decode(pRD, f_MOF, DROPUS_COUNTOF(f_MOF), ft_MOF); - } - #endif - } - } -} - -static dropus_result dropus_stream_decode_silk_frames__stereo(dropus_stream* pOpusStream, dropus_range_decoder* pRD, dropus_silk_frame_regularity regularity, dropus_uint8* pFlagsVAD, dropus_uint8* pFlagsLBRR, dropus_silk_frame* pSILKFrames) -{ - dropus_result result; - dropus_uint8 silkFrameCount; - dropus_uint8 iSILKFrame; - - silkFrameCount = dropus_toc_silk_frame_count(pOpusStream->packet.toc); - DROPUS_ASSERT(silkFrameCount > 0); - - for (iSILKFrame = 0; iSILKFrame < silkFrameCount; iSILKFrame += 1) { - result = dropus_stream_decode_silk_frame__stereo(pOpusStream, pRD, regularity, iSILKFrame, pFlagsVAD, pFlagsLBRR, pSILKFrames); - if (result != DROPUS_SUCCESS) { - return result; - } - } - - return DROPUS_SUCCESS; -} - - -static dropus_result dropus_stream_decode_frame__silk(dropus_stream* pOpusStream, dropus_stream_frame* pOpusFrame, const dropus_uint8* pData, size_t dataSize) -{ - dropus_result result; - dropus_range_decoder rd; - - DROPUS_ASSERT(pOpusStream != NULL); - DROPUS_ASSERT(pOpusFrame != NULL); - DROPUS_ASSERT(pData != NULL); - DROPUS_ASSERT(dataSize <= DROPUS_MAX_FRAME_SIZE_IN_BYTES); - - pOpusFrame->sizeInBytes = (dropus_uint16)dataSize; /* Safe cast because dataSize <= DROPUS_MAX_FRAME_SIZE_IN_BYTES <= 1275. */ - - /* Everything is fed through the range decoder. */ - dropus_range_decoder_init(pData, pOpusFrame->sizeInBytes, &rd); - { - dropus_uint16 f_Flags[2] = {1, 1}, ft_Flags = 2; - - dropus_uint8 iChannel; - dropus_uint8 channels; - dropus_uint8 iFrameSILK; - dropus_uint8 frameCountSILK; - dropus_uint16 k; - dropus_uint8 flagsVAD[2] = {0, 0}; /* One for each channel. */ - dropus_uint8 flagsLBRR[2] = {0, 0}; /* One for each channel. */ - dropus_silk_frame silkFrames_LBRR[2][3]; - dropus_silk_frame silkFrames_Regular[2][3]; - - dropus_uint32 w0_Q13[3] = {0, 0, 0}; /* One for each SILK frame (max 3). */ - dropus_uint32 w1_Q13[3] = {0, 0, 0}; /* One for each SILK frame (max 3). */ - dropus_uint8 midOnlyFlag[3] = {0, 0, 0}; /* One for each SILK frame (max 3). */ - - frameCountSILK = dropus_toc_silk_frame_count(pOpusStream->packet.toc); /* SILK frame count. Between 1 and 3. Either 1 10ms SILK frame, or between 1 and 3 20ms frames (20ms, 40ms, 60ms). */ - if (frameCountSILK == 0) { - return DROPUS_BAD_DATA; - } - - channels = dropus_toc_s(pOpusStream->packet.toc) + 1; - - /* Header flags. */ - for (iChannel = 0; iChannel < channels; ++iChannel) { - for (iFrameSILK = 0; iFrameSILK < frameCountSILK; ++iFrameSILK) { - k = dropus_range_decoder_decode(&rd, f_Flags, DROPUS_COUNTOF(f_Flags), ft_Flags); - DROPUS_ASSERT(k <= 1); - flagsVAD[iChannel] |= (k << iFrameSILK); - } - - k = dropus_range_decoder_decode(&rd, f_Flags, DROPUS_COUNTOF(f_Flags), ft_Flags); - DROPUS_ASSERT(k <= 1); - flagsLBRR[iChannel] = (dropus_uint8)k; - } - - /* RFC 6716 - 4.2.4. Per-Frame LBRR Flags. */ - if (frameCountSILK > 1) { - dropus_uint8 iChannel; - for (iChannel = 0; iChannel < channels; iChannel += 1) { - dropus_uint16 f_40[4] = {0, 53, 53, 150}, ft_40 = 256; - dropus_uint16 f_60[8] = {0, 41, 20, 29, 41, 15, 28, 82}, ft_60 = 256; - if (flagsLBRR[iChannel] != 0) { - if (frameCountSILK == 2) { - k = dropus_range_decoder_decode(&rd, f_40, DROPUS_COUNTOF(f_40), ft_40); - DROPUS_ASSERT(k <= 0b11); - } else { - DROPUS_ASSERT(frameCountSILK == 3); - k = dropus_range_decoder_decode(&rd, f_60, DROPUS_COUNTOF(f_60), ft_60); - DROPUS_ASSERT(k <= 0b111); - } - - flagsLBRR[iChannel] = (dropus_uint8)k; - } - } - } - - /* LBRR frames. Only do this if the relevant flag is set. */ - for (iFrameSILK = 0; iFrameSILK < frameCountSILK; ++iFrameSILK) { - if (channels == 1) { - /*result = dropus_stream_decode_silk_frames__mono(pOpusStream, &rd, );*/ - } else { - result = dropus_stream_decode_silk_frames__stereo(pOpusStream, &rd, dropus_silk_frame_regularity_lbrr, flagsVAD, flagsLBRR, silkFrames_LBRR); - } - - for (iChannel = 0; iChannel < channels; ++iChannel) { - if ((flagsLBRR[iChannel] & (1 << iFrameSILK)) != 0) { - result = dropus_stream_decode_frame__silk_frame(pOpusStream, &rd, &silkFrames_LBRR[iFrameSILK]); - if (result != DROPUS_SUCCESS) { - return result; - } - } - } - } - - /* TODO: Don't forget to set the previous stereo weights. Don't just blindly set it without first checking the rules in RFC 6716 - Section 4.2.7.1. */ - /* RFC 6716 - Section 4.2.7.1 - These prediction weights are never included in a mono Opus frame, and the previous weights are reset to zeros on any transition from mono to stereo. */ - if (channels == 1) { - pOpusStream->silk.w0_Q13_prev = 0; - pOpusStream->silk.w1_Q13_prev = 0; - } - - - } - - return DROPUS_SUCCESS; -} - -static dropus_result dropus_stream_decode_frame__celt(dropus_stream* pOpusStream, dropus_stream_frame* pOpusFrame, const dropus_uint8* pData, size_t dataSize) -{ - dropus_range_decoder rd; - - DROPUS_ASSERT(pOpusStream != NULL); - DROPUS_ASSERT(pOpusFrame != NULL); - DROPUS_ASSERT(pData != NULL); - DROPUS_ASSERT(dataSize <= DROPUS_MAX_FRAME_SIZE_IN_BYTES); - - pOpusFrame->sizeInBytes = (dropus_uint16)dataSize; /* Safe cast because dataSize <= DROPUS_MAX_FRAME_SIZE_IN_BYTES <= 1275. */ - - /* Everything is fed through the range decoder. */ - dropus_range_decoder_init(pData, pOpusFrame->sizeInBytes, &rd); - { - - } - - return DROPUS_SUCCESS; -} - -static dropus_result dropus_stream_decode_frame__hybrid(dropus_stream* pOpusStream, dropus_stream_frame* pOpusFrame, const dropus_uint8* pData, size_t dataSize) -{ - dropus_range_decoder rd; - - DROPUS_ASSERT(pOpusStream != NULL); - DROPUS_ASSERT(pOpusFrame != NULL); - DROPUS_ASSERT(pData != NULL); - DROPUS_ASSERT(dataSize <= DROPUS_MAX_FRAME_SIZE_IN_BYTES); - - pOpusFrame->sizeInBytes = (dropus_uint16)dataSize; /* Safe cast because dataSize <= DROPUS_MAX_FRAME_SIZE_IN_BYTES <= 1275. */ - - /* Everything is fed through the range decoder. */ - dropus_range_decoder_init(pData, pOpusFrame->sizeInBytes, &rd); - { - - } - - return DROPUS_SUCCESS; -} - -DROPUS_API dropus_result dropus_stream_decode_packet(dropus_stream* pOpusStream, const void* pData, size_t dataSize) -{ - const dropus_uint8* pRunningData8 = (const dropus_uint8*)pData; - dropus_uint8 toc; /* Table of Contents byte. */ - dropus_uint8 opusFrameCount; - dropus_uint16 opusFrameSizes[DROPUS_MAX_OPUS_FRAMES_PER_PACKET]; - dropus_uint32 code; /* Determines the structure of the Opus packet. */ - - if (pOpusStream == NULL || pData == NULL) { - return DROPUS_INVALID_ARGS; - } - - DROPUS_ASSERT(DROPUS_MAX_PACKET_SIZE_IN_BYTES < 65536); - if (dataSize > DROPUS_MAX_PACKET_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - - /* RFC 6716 - Section 3.4 [R1] Packets are at least one byte. */ - if (dataSize < 1) { - return DROPUS_BAD_DATA; - } - - /* The TOC byte specifies the structure of the packet. */ - toc = pRunningData8[0]; - pRunningData8 += 1; - - /* - We need to look at the code to know the frames making up the packet are structured. We will do a pre-processing step to - extract basic information about each frame in the packet. - */ - code = dropus_toc_c(toc); - switch (code) { - case 0: /* RFC 6716 - Section 3.2.2. Code 0: One Frame in the Packet */ - { - dropus_uint16 opusFrameSize = (dropus_uint16)(dataSize-1); - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (opusFrameSize > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - - opusFrameCount = 1; - opusFrameSizes[0] = opusFrameSize; - } break; - - case 1: /* RFC 6716 - Section 3.2.3. Code 1: Two Frames in the Packet, Each with Equal Compressed Size */ - { - dropus_uint16 opusFrameSize; - - /* RFC 6716 - Section 3.4 [R3] Code 1 packets have an odd total length, N, so that (N-1)/2 is an integer. */ - if ((dataSize & 1) == 0) { - return DROPUS_BAD_DATA; - } - - opusFrameSize = (dropus_uint16)(dataSize-1)/2; - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (opusFrameSize > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - - opusFrameCount = 2; - opusFrameSizes[0] = opusFrameSize; - opusFrameSizes[1] = opusFrameSize; - } break; - - case 2: /* RFC 6716 - Section 3.2.4. Code 2: Two Frames in the Packet, with Different Compressed Sizes */ - { - dropus_uint8 byte0; - dropus_uint8 byte1; - dropus_uint16 opusFrameSize0 = 0; - dropus_uint16 opusFrameSize1 = 0; - dropus_uint16 headerByteCount; - - /* RFC 6716 - Section 3.4 [R4] Code 2 packets have enough bytes after the TOC for a valid frame length, and that length is no larger than the number of bytes remaining in the packet. */ - if (dataSize < 2) { - return DROPUS_BAD_DATA; - } - - /* RFC 6716 - Section 3.2.1. Frame Length Coding */ - byte0 = pRunningData8[0]; pRunningData8 += 1; - if (byte0 == 0) { - /* - Section 3.2.1 of RFC 6716 says the following: - - "Any Opus frame in any mode MAY have a length of 0. - - This implies to me that this is a valid case. dr_opus is going to handle this by setting the PCM frame count to 0 for this packet. - */ - opusFrameSize0 = 0; - opusFrameSize1 = 0; - } else { - if (byte0 >= 1 && byte0 <= 251) { - opusFrameSize0 = byte0; - } - if (byte0 >= 252 /*&& byte0 <= 255*/) { - /* RFC 6716 - Section 3.4 [R4] Code 2 packets have enough bytes after the TOC for a valid frame length, and that length is no larger than the number of bytes remaining in the packet. */ - if (dataSize < 3) { - return DROPUS_BAD_DATA; - } - - byte1 = pRunningData8[0]; pRunningData8 += 1; - opusFrameSize0 = (byte1*4) + byte0; - } - - headerByteCount = (dropus_uint16)(pRunningData8 - (const dropus_uint8*)pData); /* This is a safe case because the maximum difference will be 3. */ - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (opusFrameSize0 > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - - /* RFC 6716 - Section 3.4 [R4] Code 2 packets have enough bytes after the TOC for a valid frame length, and that length is no larger than the number of bytes remaining in the packet. */ - if ((dataSize-headerByteCount) > dataSize) { - return DROPUS_BAD_DATA; - } - - opusFrameSize1 = (dropus_uint16)(dataSize-headerByteCount-opusFrameSize0); /* Safe cast because dataSize is guaranteed to be < 65536 at this point since it was checked at the top of this function. */ - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (opusFrameSize1 > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - - /* RFC 6716 - Section 3.4 [R4] Code 2 packets have enough bytes after the TOC for a valid frame length, and that length is no larger than the number of bytes remaining in the packet. */ - if ((size_t)(headerByteCount + opusFrameSize0 + opusFrameSize1) > dataSize) { - return DROPUS_BAD_DATA; - } - } - - opusFrameCount = 2; - opusFrameSizes[0] = opusFrameSize0; - opusFrameSizes[1] = opusFrameSize1; - } break; - - case 3: /* RFC 6716 - Section 3.2.5. Code 3: A Signaled Number of Frames in the Packet */ - { - dropus_uint16 iFrame; - dropus_uint8 frameCountByte; - dropus_uint8 v; /* Is VBR? */ - dropus_uint8 p; /* Has padding? */ - dropus_uint8 M; /* Frame count. */ - dropus_uint16 P; /* The size of the padding. Must never be more than dataSize-2. */ - dropus_uint16 R; /* The number of bytes remaining in the packet after subtracting the TOC, frame count byte and padding. */ - dropus_uint32 ms; /* Total length in milliseconds. */ - dropus_uint32 paddingByteCount; /* The number of bytes making up the size of the padding. Only used for validation. */ - - /* - RFC 6716 - Section 3.2.5: - "Code 3 packets MUST have at least 2 bytes [R6,R7]." - */ - if (dataSize < 2) { - return DROPUS_BAD_DATA; - } - - frameCountByte = pRunningData8[0]; pRunningData8 += 1; - v = (frameCountByte & 0x80) >> 7; - p = (frameCountByte & 0x40) >> 6; - M = (frameCountByte & 0x3F); - - /* RFC 6716 - Section 3.4 [R5] Code 3 packets contain at least one frame, but no more than 120 ms of audio total. */ - ms = (M * dropus_toc_frame_size_in_pcm_frames(toc)) / dropus_toc_sample_rate_ms(toc); - if (M < 1 || ms > 120) { - return DROPUS_BAD_DATA; - } - - /* Sanity check to ensure the frame count is never greather than the maximum allowed. */ - if (M > DROPUS_MAX_OPUS_FRAMES_PER_PACKET) { - return DROPUS_BAD_DATA; - } - - /* Padding bytes. Need to run this in a loop. */ - P = 0; - paddingByteCount = 0; - if (p != 0) { - size_t iPaddingByte; - for (iPaddingByte = 0; iPaddingByte < dataSize-2; ++iPaddingByte) { - dropus_uint8 paddingByte = pRunningData8[0]; pRunningData8 += 1; - P += paddingByte; - paddingByteCount += 1; - - /* A padding byte not equal to 255 signals the last padding byte. */ - if (paddingByte == 255) { - /* There must be an additional byte available in this case. */ - if (iPaddingByte+1 >= dataSize-2) { - return DROPUS_BAD_DATA; - } - } else { - break; /* Reached the end of the padding bytes. */ - } - } - } - - /* Safety check. */ - if (P > dataSize-2) { - return DROPUS_BAD_DATA; - } - - /* R = bytes remaining. */ - R = (dropus_uint16)(dataSize-2-P); - - if (v == 0) { - /* CBR */ - dropus_uint16 frameSize = R/M; - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (frameSize > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - - /* RFC 6716 - Section 3.4 [R6] ... */ - if (dataSize < 2) { /* ... The length of a CBR code 3 packet, N, is at least two bytes ... */ - return DROPUS_BAD_DATA; - } - if (paddingByteCount+P > dataSize-2) { /* ... the number of bytes added to indicate the padding size plus the trailing padding bytes themselves, P, is no more than N-2 ... */ - return DROPUS_BAD_DATA; - } - if (frameSize*M != (dropus_uint16)(dataSize-2-P)) { /* ... the frame count, M, satisfies the constraint that (N-2-P) is a non-negative integer multiple of M ... */ - return DROPUS_BAD_DATA; - } - - opusFrameCount = M; - for (iFrame = 0; iFrame < opusFrameCount; ++iFrame) { - opusFrameSizes[iFrame] = frameSize; - } - } else { - /* VBR */ - dropus_uint16 totalFrameSizeExceptLast = 0; /* Used later for checking [R7]. */ - dropus_uintptr headerSizeInBytes; /* For validation and deriving the size of the last frame. */ - - opusFrameCount = M; - for (iFrame = 0; iFrame < opusFrameCount-1; ++iFrame) { - dropus_uint8 byte0; - dropus_uint8 byte1; - - if (pRunningData8 >= ((const dropus_uint8*)pData) + dataSize) { - return DROPUS_BAD_DATA; /* Ran out of data in the packet. Implicitly handles part of [R7]. */ - } - - byte0 = pRunningData8[0]; pRunningData8 += 1; - if (byte0 == 0) { - opusFrameSizes[iFrame] = 0; - } else { - if (byte0 >= 1 && byte0 <= 251) { - opusFrameSizes[iFrame] = byte0; - } - if (byte0 >= 252 /*&& byte0 <= 255*/) { - if (pRunningData8 >= ((const dropus_uint8*)pData) + dataSize) { - return DROPUS_BAD_DATA; /* Ran out of data in the packet. Implicitly handles part of [R7]. */ - } - - byte1 = pRunningData8[0]; pRunningData8 += 1; - opusFrameSizes[iFrame] = (byte1*4) + byte0; - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (opusFrameSizes[iFrame] > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - } - } - - totalFrameSizeExceptLast += opusFrameSizes[iFrame]; - } - - headerSizeInBytes = (dropus_uintptr)(pRunningData8 - (const dropus_uint8*)pData); - - /* - RFC 6716 - Section 3.4 [R6] - VBR code 3 packets are large enough to contain all the header - bytes (TOC byte, frame count byte, any padding length bytes, - and any frame length bytes), plus the length of the first M-1 - frames, plus any trailing padding bytes. - */ - if ((headerSizeInBytes + totalFrameSizeExceptLast + P) > dataSize) { - return DROPUS_BAD_DATA; - } - - /* The size of the last frame is derived. */ - opusFrameSizes[opusFrameCount-1] = (dropus_uint16)(dataSize - headerSizeInBytes - totalFrameSizeExceptLast - P); /* Safe cast thanks to the myriad of validation done beforehand. */ - - /* RFC 6716 - Section 3.4 [R2] No implicit frame length is larger than 1275 bytes. */ - if (opusFrameSizes[opusFrameCount-1] > DROPUS_MAX_FRAME_SIZE_IN_BYTES) { - return DROPUS_BAD_DATA; - } - } - } break; - - /* Will never hit this, but need the default to keep some compilers quiet. */ - default: return DROPUS_BAD_DATA; - } - - pOpusStream->packet.toc = toc; - - /* Make sure the frame count is within a valid range. */ - if (opusFrameCount > DROPUS_MAX_OPUS_FRAMES_PER_PACKET) { - return DROPUS_BAD_DATA; - } - - /* At this point, pRunningData8 should be sitting on the first byte of the first frame in the packet. */ - - /* Decoding. */ - { - dropus_result result; - dropus_uint16 iFrame; - dropus_mode mode; - - mode = dropus_toc_mode(pOpusStream->packet.toc); - - /* Would be slightly more optimal to pull the mode checks out of the loop, but it's more compact, readable and maintainable to do it inside. We can let the compiler decide what to do with it. */ - for (iFrame = 0; iFrame < opusFrameCount; ++iFrame) { - /* */ if (mode == dropus_mode_silk) { - result = dropus_stream_decode_frame__silk(pOpusStream, &pOpusStream->packet.frames[iFrame], pRunningData8, opusFrameSizes[iFrame]); - } else if (mode == dropus_mode_celt) { - result = dropus_stream_decode_frame__celt(pOpusStream, &pOpusStream->packet.frames[iFrame], pRunningData8, opusFrameSizes[iFrame]); - } else { - DROPUS_ASSERT(mode == dropus_mode_hybrid); - result = dropus_stream_decode_frame__hybrid(pOpusStream, &pOpusStream->packet.frames[iFrame], pRunningData8, opusFrameSizes[iFrame]); - } - - if (result != DROPUS_SUCCESS) { - return result; /* Probably a corrupt frame. */ - } - - pRunningData8 += opusFrameSizes[iFrame]; - } - } - - return DROPUS_SUCCESS; -} - - - -/*********************************************************************************************************************************************************** - -High-Level Opus Decoding API - -************************************************************************************************************************************************************/ -static void* dropus__malloc_default(size_t sz, void* pUserData) -{ - (void)pUserData; - return DROPUS_MALLOC(sz); -} - -static void* dropus__realloc_default(void* p, size_t sz, void* pUserData) -{ - (void)pUserData; - return DROPUS_REALLOC(p, sz); -} - -static void dropus__free_default(void* p, void* pUserData) -{ - (void)pUserData; - DROPUS_FREE(p); -} - - -static void* dropus__malloc_from_callbacks(size_t sz, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - return NULL; - } - - if (pAllocationCallbacks->onMalloc != NULL) { - return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); - } - - /* Try using realloc(). */ - if (pAllocationCallbacks->onRealloc != NULL) { - return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); - } - - return NULL; -} - -static void* dropus__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - return NULL; - } - - if (pAllocationCallbacks->onRealloc != NULL) { - return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); - } - - /* Try emulating realloc() in terms of malloc()/free(). */ - if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { - void* p2; - - p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); - if (p2 == NULL) { - return NULL; - } - - if (p != NULL) { - DROPUS_COPY_MEMORY(p2, p, szOld); - pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); - } - - return p2; - } - - return NULL; -} - -static void dropus__free_from_callbacks(void* p, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (p == NULL || pAllocationCallbacks == NULL) { - return; - } - - if (pAllocationCallbacks->onFree != NULL) { - pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); - } -} - - -static dropus_allocation_callbacks dropus__copy_allocation_callbacks_or_defaults(const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks != NULL) { - /* Copy. */ - return *pAllocationCallbacks; - } else { - /* Defaults. */ - dropus_allocation_callbacks allocationCallbacks; - allocationCallbacks.pUserData = NULL; - allocationCallbacks.onMalloc = dropus__malloc_default; - allocationCallbacks.onRealloc = dropus__realloc_default; - allocationCallbacks.onFree = dropus__free_default; - return allocationCallbacks; - } -} - -static dropus_result dropus_init_internal(dropus* pOpus, dropus_read_proc onRead, dropus_seek_proc onSeek, void* pUserData, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - DROPUS_ASSERT(pOpus != NULL); - DROPUS_ASSERT(onRead != NULL); - - /* Must always have an onRead callback. */ - if (onRead == NULL) { - return DROPUS_INVALID_ARGS; - } - - pOpus->onRead = onRead; - pOpus->onSeek = onSeek; - pOpus->pUserData = pUserData; - pOpus->allocationCallbacks = dropus__copy_allocation_callbacks_or_defaults(pAllocationCallbacks); - - /* Basic validation for allocation callbacks. free() and at least one of malloc() or realloc() must be set. */ - if (pOpus->allocationCallbacks.onFree == NULL || (pOpus->allocationCallbacks.onMalloc == NULL && pOpus->allocationCallbacks.onRealloc == NULL)) { - return DROPUS_INVALID_ARGS; - } - - /* TODO: Implement me. */ - - return DROPUS_SUCCESS; -} - -DROPUS_API dropus_result dropus_init(dropus* pOpus, dropus_read_proc onRead, dropus_seek_proc onSeek, void* pUserData, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pOpus == NULL) { - return DROPUS_INVALID_ARGS; - } - - DROPUS_ZERO_OBJECT(pOpus); - - return dropus_init_internal(pOpus, onRead, onSeek, pUserData, pAllocationCallbacks); -} - -#ifndef DR_OPUS_NO_STDIO -#include -static dropus_result dropus_result_from_errno(int e) -{ - switch (e) - { - case 0: return DROPUS_SUCCESS; - #ifdef EPERM - case EPERM: return DROPUS_INVALID_OPERATION; - #endif - #ifdef ENOENT - case ENOENT: return DROPUS_DOES_NOT_EXIST; - #endif - #ifdef ESRCH - case ESRCH: return DROPUS_DOES_NOT_EXIST; - #endif - #ifdef EINTR - case EINTR: return DROPUS_INTERRUPT; - #endif - #ifdef EIO - case EIO: return DROPUS_IO_ERROR; - #endif - #ifdef ENXIO - case ENXIO: return DROPUS_DOES_NOT_EXIST; - #endif - #ifdef E2BIG - case E2BIG: return DROPUS_INVALID_ARGS; - #endif - #ifdef ENOEXEC - case ENOEXEC: return DROPUS_INVALID_FILE; - #endif - #ifdef EBADF - case EBADF: return DROPUS_INVALID_FILE; - #endif - #ifdef ECHILD - case ECHILD: return DROPUS_ERROR; - #endif - #ifdef EAGAIN - case EAGAIN: return DROPUS_UNAVAILABLE; - #endif - #ifdef ENOMEM - case ENOMEM: return DROPUS_OUT_OF_MEMORY; - #endif - #ifdef EACCES - case EACCES: return DROPUS_ACCESS_DENIED; - #endif - #ifdef EFAULT - case EFAULT: return DROPUS_BAD_ADDRESS; - #endif - #ifdef ENOTBLK - case ENOTBLK: return DROPUS_ERROR; - #endif - #ifdef EBUSY - case EBUSY: return DROPUS_BUSY; - #endif - #ifdef EEXIST - case EEXIST: return DROPUS_ALREADY_EXISTS; - #endif - #ifdef EXDEV - case EXDEV: return DROPUS_ERROR; - #endif - #ifdef ENODEV - case ENODEV: return DROPUS_DOES_NOT_EXIST; - #endif - #ifdef ENOTDIR - case ENOTDIR: return DROPUS_NOT_DIRECTORY; - #endif - #ifdef EISDIR - case EISDIR: return DROPUS_IS_DIRECTORY; - #endif - #ifdef EINVAL - case EINVAL: return DROPUS_INVALID_ARGS; - #endif - #ifdef ENFILE - case ENFILE: return DROPUS_TOO_MANY_OPEN_FILES; - #endif - #ifdef EMFILE - case EMFILE: return DROPUS_TOO_MANY_OPEN_FILES; - #endif - #ifdef ENOTTY - case ENOTTY: return DROPUS_INVALID_OPERATION; - #endif - #ifdef ETXTBSY - case ETXTBSY: return DROPUS_BUSY; - #endif - #ifdef EFBIG - case EFBIG: return DROPUS_TOO_BIG; - #endif - #ifdef ENOSPC - case ENOSPC: return DROPUS_NO_SPACE; - #endif - #ifdef ESPIPE - case ESPIPE: return DROPUS_BAD_SEEK; - #endif - #ifdef EROFS - case EROFS: return DROPUS_ACCESS_DENIED; - #endif - #ifdef EMLINK - case EMLINK: return DROPUS_TOO_MANY_LINKS; - #endif - #ifdef EPIPE - case EPIPE: return DROPUS_BAD_PIPE; - #endif - #ifdef EDOM - case EDOM: return DROPUS_OUT_OF_RANGE; - #endif - #ifdef ERANGE - case ERANGE: return DROPUS_OUT_OF_RANGE; - #endif - #ifdef EDEADLK - case EDEADLK: return DROPUS_DEADLOCK; - #endif - #ifdef ENAMETOOLONG - case ENAMETOOLONG: return DROPUS_PATH_TOO_LONG; - #endif - #ifdef ENOLCK - case ENOLCK: return DROPUS_ERROR; - #endif - #ifdef ENOSYS - case ENOSYS: return DROPUS_NOT_IMPLEMENTED; - #endif - #ifdef ENOTEMPTY - case ENOTEMPTY: return DROPUS_DIRECTORY_NOT_EMPTY; - #endif - #ifdef ELOOP - case ELOOP: return DROPUS_TOO_MANY_LINKS; - #endif - #ifdef ENOMSG - case ENOMSG: return DROPUS_NO_MESSAGE; - #endif - #ifdef EIDRM - case EIDRM: return DROPUS_ERROR; - #endif - #ifdef ECHRNG - case ECHRNG: return DROPUS_ERROR; - #endif - #ifdef EL2NSYNC - case EL2NSYNC: return DROPUS_ERROR; - #endif - #ifdef EL3HLT - case EL3HLT: return DROPUS_ERROR; - #endif - #ifdef EL3RST - case EL3RST: return DROPUS_ERROR; - #endif - #ifdef ELNRNG - case ELNRNG: return DROPUS_OUT_OF_RANGE; - #endif - #ifdef EUNATCH - case EUNATCH: return DROPUS_ERROR; - #endif - #ifdef ENOCSI - case ENOCSI: return DROPUS_ERROR; - #endif - #ifdef EL2HLT - case EL2HLT: return DROPUS_ERROR; - #endif - #ifdef EBADE - case EBADE: return DROPUS_ERROR; - #endif - #ifdef EBADR - case EBADR: return DROPUS_ERROR; - #endif - #ifdef EXFULL - case EXFULL: return DROPUS_ERROR; - #endif - #ifdef ENOANO - case ENOANO: return DROPUS_ERROR; - #endif - #ifdef EBADRQC - case EBADRQC: return DROPUS_ERROR; - #endif - #ifdef EBADSLT - case EBADSLT: return DROPUS_ERROR; - #endif - #ifdef EBFONT - case EBFONT: return DROPUS_INVALID_FILE; - #endif - #ifdef ENOSTR - case ENOSTR: return DROPUS_ERROR; - #endif - #ifdef ENODATA - case ENODATA: return DROPUS_NO_DATA_AVAILABLE; - #endif - #ifdef ETIME - case ETIME: return DROPUS_TIMEOUT; - #endif - #ifdef ENOSR - case ENOSR: return DROPUS_NO_DATA_AVAILABLE; - #endif - #ifdef ENONET - case ENONET: return DROPUS_NO_NETWORK; - #endif - #ifdef ENOPKG - case ENOPKG: return DROPUS_ERROR; - #endif - #ifdef EREMOTE - case EREMOTE: return DROPUS_ERROR; - #endif - #ifdef ENOLINK - case ENOLINK: return DROPUS_ERROR; - #endif - #ifdef EADV - case EADV: return DROPUS_ERROR; - #endif - #ifdef ESRMNT - case ESRMNT: return DROPUS_ERROR; - #endif - #ifdef ECOMM - case ECOMM: return DROPUS_ERROR; - #endif - #ifdef EPROTO - case EPROTO: return DROPUS_ERROR; - #endif - #ifdef EMULTIHOP - case EMULTIHOP: return DROPUS_ERROR; - #endif - #ifdef EDOTDOT - case EDOTDOT: return DROPUS_ERROR; - #endif - #ifdef EBADMSG - case EBADMSG: return DROPUS_BAD_MESSAGE; - #endif - #ifdef EOVERFLOW - case EOVERFLOW: return DROPUS_TOO_BIG; - #endif - #ifdef ENOTUNIQ - case ENOTUNIQ: return DROPUS_NOT_UNIQUE; - #endif - #ifdef EBADFD - case EBADFD: return DROPUS_ERROR; - #endif - #ifdef EREMCHG - case EREMCHG: return DROPUS_ERROR; - #endif - #ifdef ELIBACC - case ELIBACC: return DROPUS_ACCESS_DENIED; - #endif - #ifdef ELIBBAD - case ELIBBAD: return DROPUS_INVALID_FILE; - #endif - #ifdef ELIBSCN - case ELIBSCN: return DROPUS_INVALID_FILE; - #endif - #ifdef ELIBMAX - case ELIBMAX: return DROPUS_ERROR; - #endif - #ifdef ELIBEXEC - case ELIBEXEC: return DROPUS_ERROR; - #endif - #ifdef EILSEQ - case EILSEQ: return DROPUS_INVALID_DATA; - #endif - #ifdef ERESTART - case ERESTART: return DROPUS_ERROR; - #endif - #ifdef ESTRPIPE - case ESTRPIPE: return DROPUS_ERROR; - #endif - #ifdef EUSERS - case EUSERS: return DROPUS_ERROR; - #endif - #ifdef ENOTSOCK - case ENOTSOCK: return DROPUS_NOT_SOCKET; - #endif - #ifdef EDESTADDRREQ - case EDESTADDRREQ: return DROPUS_NO_ADDRESS; - #endif - #ifdef EMSGSIZE - case EMSGSIZE: return DROPUS_TOO_BIG; - #endif - #ifdef EPROTOTYPE - case EPROTOTYPE: return DROPUS_BAD_PROTOCOL; - #endif - #ifdef ENOPROTOOPT - case ENOPROTOOPT: return DROPUS_PROTOCOL_UNAVAILABLE; - #endif - #ifdef EPROTONOSUPPORT - case EPROTONOSUPPORT: return DROPUS_PROTOCOL_NOT_SUPPORTED; - #endif - #ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: return DROPUS_SOCKET_NOT_SUPPORTED; - #endif - #ifdef EOPNOTSUPP - case EOPNOTSUPP: return DROPUS_INVALID_OPERATION; - #endif - #ifdef EPFNOSUPPORT - case EPFNOSUPPORT: return DROPUS_PROTOCOL_FAMILY_NOT_SUPPORTED; - #endif - #ifdef EAFNOSUPPORT - case EAFNOSUPPORT: return DROPUS_ADDRESS_FAMILY_NOT_SUPPORTED; - #endif - #ifdef EADDRINUSE - case EADDRINUSE: return DROPUS_ALREADY_IN_USE; - #endif - #ifdef EADDRNOTAVAIL - case EADDRNOTAVAIL: return DROPUS_ERROR; - #endif - #ifdef ENETDOWN - case ENETDOWN: return DROPUS_NO_NETWORK; - #endif - #ifdef ENETUNREACH - case ENETUNREACH: return DROPUS_NO_NETWORK; - #endif - #ifdef ENETRESET - case ENETRESET: return DROPUS_NO_NETWORK; - #endif - #ifdef ECONNABORTED - case ECONNABORTED: return DROPUS_NO_NETWORK; - #endif - #ifdef ECONNRESET - case ECONNRESET: return DROPUS_CONNECTION_RESET; - #endif - #ifdef ENOBUFS - case ENOBUFS: return DROPUS_NO_SPACE; - #endif - #ifdef EISCONN - case EISCONN: return DROPUS_ALREADY_CONNECTED; - #endif - #ifdef ENOTCONN - case ENOTCONN: return DROPUS_NOT_CONNECTED; - #endif - #ifdef ESHUTDOWN - case ESHUTDOWN: return DROPUS_ERROR; - #endif - #ifdef ETOOMANYREFS - case ETOOMANYREFS: return DROPUS_ERROR; - #endif - #ifdef ETIMEDOUT - case ETIMEDOUT: return DROPUS_TIMEOUT; - #endif - #ifdef ECONNREFUSED - case ECONNREFUSED: return DROPUS_CONNECTION_REFUSED; - #endif - #ifdef EHOSTDOWN - case EHOSTDOWN: return DROPUS_NO_HOST; - #endif - #ifdef EHOSTUNREACH - case EHOSTUNREACH: return DROPUS_NO_HOST; - #endif - #ifdef EALREADY - case EALREADY: return DROPUS_IN_PROGRESS; - #endif - #ifdef EINPROGRESS - case EINPROGRESS: return DROPUS_IN_PROGRESS; - #endif - #ifdef ESTALE - case ESTALE: return DROPUS_INVALID_FILE; - #endif - #ifdef EUCLEAN - case EUCLEAN: return DROPUS_ERROR; - #endif - #ifdef ENOTNAM - case ENOTNAM: return DROPUS_ERROR; - #endif - #ifdef ENAVAIL - case ENAVAIL: return DROPUS_ERROR; - #endif - #ifdef EISNAM - case EISNAM: return DROPUS_ERROR; - #endif - #ifdef EREMOTEIO - case EREMOTEIO: return DROPUS_IO_ERROR; - #endif - #ifdef EDQUOT - case EDQUOT: return DROPUS_NO_SPACE; - #endif - #ifdef ENOMEDIUM - case ENOMEDIUM: return DROPUS_DOES_NOT_EXIST; - #endif - #ifdef EMEDIUMTYPE - case EMEDIUMTYPE: return DROPUS_ERROR; - #endif - #ifdef ECANCELED - case ECANCELED: return DROPUS_CANCELLED; - #endif - #ifdef ENOKEY - case ENOKEY: return DROPUS_ERROR; - #endif - #ifdef EKEYEXPIRED - case EKEYEXPIRED: return DROPUS_ERROR; - #endif - #ifdef EKEYREVOKED - case EKEYREVOKED: return DROPUS_ERROR; - #endif - #ifdef EKEYREJECTED - case EKEYREJECTED: return DROPUS_ERROR; - #endif - #ifdef EOWNERDEAD - case EOWNERDEAD: return DROPUS_ERROR; - #endif - #ifdef ENOTRECOVERABLE - case ENOTRECOVERABLE: return DROPUS_ERROR; - #endif - #ifdef ERFKILL - case ERFKILL: return DROPUS_ERROR; - #endif - #ifdef EHWPOISON - case EHWPOISON: return DROPUS_ERROR; - #endif - default: return DROPUS_ERROR; - } -} - -static dropus_result dropus_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) -{ -#if defined(_MSC_VER) && _MSC_VER >= 1400 - errno_t err; -#endif - - if (ppFile != NULL) { - *ppFile = NULL; /* Safety. */ - } - - if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { - return DROPUS_INVALID_ARGS; - } - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - err = fopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return dropus_result_from_errno(err); - } -#else -#if defined(_WIN32) || defined(__APPLE__) - *ppFile = fopen(pFilePath, pOpenMode); -#else - #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) - *ppFile = fopen64(pFilePath, pOpenMode); - #else - *ppFile = fopen(pFilePath, pOpenMode); - #endif -#endif - if (*ppFile == NULL) { - dropus_result result = dropus_result_from_errno(errno); - if (result == DROPUS_SUCCESS) { - result = DROPUS_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ - } - - return result; - } -#endif - - return DROPUS_SUCCESS; -} - -/* -_wfopen() isn't always available in all compilation environments. - - * Windows only. - * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). - * MinGW-64 (both 32- and 64-bit) seems to support it. - * MinGW wraps it in !defined(__STRICT_ANSI__). - -This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() -fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. -*/ -#if defined(_WIN32) - #if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__) - #define DROPUS_HAS_WFOPEN - #endif -#endif - -static dropus_result dropus_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (ppFile != NULL) { - *ppFile = NULL; /* Safety. */ - } - - if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { - return DROPUS_INVALID_ARGS; - } - -#if defined(DROPUS_HAS_WFOPEN) - { - /* Use _wfopen() on Windows. */ - #if defined(_MSC_VER) && _MSC_VER >= 1400 - errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return dropus_result_from_errno(err); - } - #else - *ppFile = _wfopen(pFilePath, pOpenMode); - if (*ppFile == NULL) { - return dropus_result_from_errno(errno); - } - #endif - (void)pAllocationCallbacks; - } -#else - /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can - think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. - */ - { - mbstate_t mbs; - size_t lenMB; - const wchar_t* pFilePathTemp = pFilePath; - char* pFilePathMB = NULL; - char pOpenModeMB[32] = {0}; - - /* Get the length first. */ - DROPUS_ZERO_OBJECT(&mbs); - lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); - if (lenMB == (size_t)-1) { - return dropus_result_from_errno(errno); - } - - pFilePathMB = (char*)dropus__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); - if (pFilePathMB == NULL) { - return DROPUS_OUT_OF_MEMORY; - } - - pFilePathTemp = pFilePath; - DROPUS_ZERO_OBJECT(&mbs); - wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); - - /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ - { - size_t i = 0; - for (;;) { - if (pOpenMode[i] == 0) { - pOpenModeMB[i] = '\0'; - break; - } - - pOpenModeMB[i] = (char)pOpenMode[i]; - i += 1; - } - } - - *ppFile = fopen(pFilePathMB, pOpenModeMB); - - dropus__free_from_callbacks(pFilePathMB, pAllocationCallbacks); - } - - if (*ppFile == NULL) { - return DROPUS_ERROR; - } -#endif - - return DROPUS_SUCCESS; -} - - -static size_t dropus_on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) -{ - return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); -} - -static dropus_bool32 dropus_on_seek_stdio(void* pUserData, int offset, dropus_seek_origin origin) -{ - return fseek((FILE*)pUserData, offset, (origin == dropus_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; -} - -DROPUS_API dropus_result dropus_init_file(dropus* pOpus, const char* pFilePath, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - dropus_result result; - FILE* pFile; - - if (pOpus == NULL) { - return DROPUS_INVALID_ARGS; - } - - DROPUS_ZERO_OBJECT(pOpus); - - if (pFilePath == NULL || pFilePath[0] == '\0') { - return DROPUS_INVALID_ARGS; - } - - result = dropus_fopen(&pFile, pFilePath, "rb"); - if (result != DROPUS_SUCCESS) { - return result; - } - - pOpus->pFile = (void*)pFile; - - result = dropus_init_internal(pOpus, dropus_on_read_stdio, dropus_on_seek_stdio, NULL, pAllocationCallbacks); - if (result != DROPUS_SUCCESS) { - fclose(pFile); - return result; - } - - return DROPUS_SUCCESS; -} - -DROPUS_API dropus_result dropus_init_file_w(dropus* pOpus, const wchar_t* pFilePath, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - dropus_result result; - FILE* pFile; - - if (pOpus == NULL) { - return DROPUS_INVALID_ARGS; - } - - DROPUS_ZERO_OBJECT(pOpus); - - if (pFilePath == NULL || pFilePath[0] == '\0') { - return DROPUS_INVALID_ARGS; - } - - result = dropus_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks); - if (result != DROPUS_SUCCESS) { - return result; - } - - pOpus->pFile = (void*)pFile; - - result = dropus_init_internal(pOpus, dropus_on_read_stdio, dropus_on_seek_stdio, NULL, pAllocationCallbacks); - if (result != DROPUS_SUCCESS) { - fclose(pFile); - return result; - } - - return DROPUS_SUCCESS; -} -#endif - -static size_t dropus_on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) -{ - size_t bytesRemaining; - dropus* pOpus = (dropus*)pUserData; - - DROPUS_ASSERT(pOpus != NULL); - DROPUS_ASSERT(pOpus->memory.dataSize >= pOpus->memory.currentReadPos); - - bytesRemaining = pOpus->memory.dataSize - pOpus->memory.currentReadPos; - if (bytesToRead > bytesRemaining) { - bytesToRead = bytesRemaining; - } - - if (bytesToRead > 0) { - DROPUS_COPY_MEMORY(pBufferOut, pOpus->memory.pData + pOpus->memory.currentReadPos, bytesToRead); - pOpus->memory.currentReadPos += bytesToRead; - } - - return bytesToRead; -} - -static dropus_bool32 dropus_on_seek_memory(void* pUserData, int byteOffset, dropus_seek_origin origin) -{ - dropus* pOpus = (dropus*)pUserData; - DROPUS_ASSERT(pOpus != NULL); - - if (origin == dropus_seek_origin_current) { - if (byteOffset > 0) { - if (pOpus->memory.currentReadPos + byteOffset > pOpus->memory.dataSize) { - byteOffset = (int)(pOpus->memory.dataSize - pOpus->memory.currentReadPos); /* Trying to seek too far forward. */ - } - } else { - if (pOpus->memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(int)pOpus->memory.currentReadPos; /* Trying to seek too far backwards. */ - } - } - - /* This will never underflow thanks to the clamps above. */ - pOpus->memory.currentReadPos += byteOffset; - } else { - if ((dropus_uint32)byteOffset <= pOpus->memory.dataSize) { - pOpus->memory.currentReadPos = byteOffset; - } else { - pOpus->memory.currentReadPos = pOpus->memory.dataSize; /* Trying to seek too far forward. */ - } - } - - return DROPUS_TRUE; -} - -DROPUS_API dropus_result dropus_init_memory(dropus* pOpus, const void* pData, size_t dataSize, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pOpus == NULL) { - return DROPUS_INVALID_ARGS; - } - - DROPUS_ZERO_OBJECT(pOpus); - - if (pData == NULL || dataSize == 0) { - return DROPUS_INVALID_ARGS; - } - - pOpus->memory.pData = (const dropus_uint8*)pData; - pOpus->memory.dataSize = dataSize; - pOpus->memory.currentReadPos = 0; - - return dropus_init_internal(pOpus, dropus_on_read_memory, dropus_on_seek_memory, NULL, pAllocationCallbacks); -} - - -DROPUS_API void dropus_uninit(dropus* pOpus) -{ - if (pOpus == NULL) { - return; - } - -#ifndef DR_OPUS_NO_STDIO - /* Since dr_opus manages the stdio FILE object make sure it's closed on uninitialization. */ - if (pOpus->pFile != NULL) { - fclose((FILE*)pOpus->pFile); - } -#endif -} - - - -DROPUS_API const char* dropus_result_description(dropus_result result) -{ - switch (result) - { - case DROPUS_SUCCESS: return "No error"; - case DROPUS_ERROR: return "Unknown error"; - case DROPUS_INVALID_ARGS: return "Invalid argument"; - case DROPUS_INVALID_OPERATION: return "Invalid operation"; - case DROPUS_OUT_OF_MEMORY: return "Out of memory"; - case DROPUS_OUT_OF_RANGE: return "Out of range"; - case DROPUS_ACCESS_DENIED: return "Permission denied"; - case DROPUS_DOES_NOT_EXIST: return "Resource does not exist"; - case DROPUS_ALREADY_EXISTS: return "Resource already exists"; - case DROPUS_TOO_MANY_OPEN_FILES: return "Too many open files"; - case DROPUS_INVALID_FILE: return "Invalid file"; - case DROPUS_TOO_BIG: return "Too large"; - case DROPUS_PATH_TOO_LONG: return "Path too long"; - case DROPUS_NAME_TOO_LONG: return "Name too long"; - case DROPUS_NOT_DIRECTORY: return "Not a directory"; - case DROPUS_IS_DIRECTORY: return "Is a directory"; - case DROPUS_DIRECTORY_NOT_EMPTY: return "Directory not empty"; - case DROPUS_END_OF_FILE: return "End of file"; - case DROPUS_NO_SPACE: return "No space available"; - case DROPUS_BUSY: return "Device or resource busy"; - case DROPUS_IO_ERROR: return "Input/output error"; - case DROPUS_INTERRUPT: return "Interrupted"; - case DROPUS_UNAVAILABLE: return "Resource unavailable"; - case DROPUS_ALREADY_IN_USE: return "Resource already in use"; - case DROPUS_BAD_ADDRESS: return "Bad address"; - case DROPUS_BAD_SEEK: return "Illegal seek"; - case DROPUS_BAD_PIPE: return "Broken pipe"; - case DROPUS_DEADLOCK: return "Deadlock"; - case DROPUS_TOO_MANY_LINKS: return "Too many links"; - case DROPUS_NOT_IMPLEMENTED: return "Not implemented"; - case DROPUS_NO_MESSAGE: return "No message of desired type"; - case DROPUS_BAD_MESSAGE: return "Invalid message"; - case DROPUS_NO_DATA_AVAILABLE: return "No data available"; - case DROPUS_INVALID_DATA: return "Invalid data"; - case DROPUS_TIMEOUT: return "Timeout"; - case DROPUS_NO_NETWORK: return "Network unavailable"; - case DROPUS_NOT_UNIQUE: return "Not unique"; - case DROPUS_NOT_SOCKET: return "Socket operation on non-socket"; - case DROPUS_NO_ADDRESS: return "Destination address required"; - case DROPUS_BAD_PROTOCOL: return "Protocol wrong type for socket"; - case DROPUS_PROTOCOL_UNAVAILABLE: return "Protocol not available"; - case DROPUS_PROTOCOL_NOT_SUPPORTED: return "Protocol not supported"; - case DROPUS_PROTOCOL_FAMILY_NOT_SUPPORTED: return "Protocol family not supported"; - case DROPUS_ADDRESS_FAMILY_NOT_SUPPORTED: return "Address family not supported"; - case DROPUS_SOCKET_NOT_SUPPORTED: return "Socket type not supported"; - case DROPUS_CONNECTION_RESET: return "Connection reset"; - case DROPUS_ALREADY_CONNECTED: return "Already connected"; - case DROPUS_NOT_CONNECTED: return "Not connected"; - case DROPUS_CONNECTION_REFUSED: return "Connection refused"; - case DROPUS_NO_HOST: return "No host"; - case DROPUS_IN_PROGRESS: return "Operation in progress"; - case DROPUS_CANCELLED: return "Operation cancelled"; - case DROPUS_MEMORY_ALREADY_MAPPED: return "Memory already mapped"; - case DROPUS_AT_END: return "Reached end of collection"; - - /* dr_opus specific result codes. */ - case DROPUS_CRC_MISMATCH: return "CRC mismatch"; - case DROPUS_BAD_DATA: return "Bad data"; - - default: return "Unknown error"; - } -} - -DROPUS_API void* dropus_malloc(size_t sz, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - return dropus__malloc_default(sz, NULL); - } else { - return dropus__malloc_from_callbacks(sz, pAllocationCallbacks); - } -} - -DROPUS_API void* dropus_realloc(void* p, size_t sz, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - return dropus__realloc_default(p, sz, NULL); - } else { - /* - We need to do an explicit check for onRealloc because dropus__realloc_from_callbacks() will fall back to a malloc based emulation if onRealloc is missing - which we do not want to do dropus_realloc(). - */ - if (pAllocationCallbacks->onRealloc == NULL) { - return NULL; - } - - return dropus__realloc_from_callbacks(p, sz, /*szOld*/ 0, pAllocationCallbacks); /* Safe to pass 0 for szOld thanks to the onRealloc check above. */ - } -} - -DROPUS_API void dropus_free(void* p, const dropus_allocation_callbacks* pAllocationCallbacks) -{ - if (pAllocationCallbacks == NULL) { - dropus__free_default(p, NULL); - } else { - dropus__free_from_callbacks(p, pAllocationCallbacks); - } -} -#endif /* DR_OPUS_IMPLEMENTATION */ - -/* -This software is available as a choice of the following licenses. Choose -whichever you prefer. - -=============================================================================== -ALTERNATIVE 1 - Public Domain (www.unlicense.org) -=============================================================================== -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. - -For more information, please refer to - -=============================================================================== -ALTERNATIVE 2 - MIT No Attribution -=============================================================================== -Copyright 2020 David Reid - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so. - -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 OR COPYRIGHT HOLDERS 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. -*/ diff --git a/source/engine/thirdparty/dr_libs/wip/dr_opus_log.txt b/source/engine/thirdparty/dr_libs/wip/dr_opus_log.txt deleted file mode 100644 index 69fc4cf..0000000 --- a/source/engine/thirdparty/dr_libs/wip/dr_opus_log.txt +++ /dev/null @@ -1,318 +0,0 @@ -This is a log of my development of dr_opus - a single file public domain Opus decoder in C. The purpose of this log is -to track the development of the project and log how I solved various problems. - -References: - RFC 6716 - https://tools.ietf.org/html/rfc6716 - Definition of the Opus Audio Codec - RFC 7845 - https://tools.ietf.org/html/rfc7845 - Ogg Encapsulation for the Opus Audio Codec - - -The main reference for development is RFC 6716. An important detail with this specification is in Section 1 - - The primary normative part of this specification is provided by the - source code in Appendix A. Only the decoder portion of this software - is normative, though a significant amount of code is shared by both - the encoder and decoder. Section 6 provides a decoder conformance - test. The decoder contains a great deal of integer and fixed-point - arithmetic that needs to be performed exactly, including all rounding - considerations, so any useful specification requires domain-specific - symbolic language to adequately define these operations. - Additionally, any conflict between the symbolic representation and - the included reference implementation must be resolved. For the - practical reasons of compatibility and testability, it would be - advantageous to give the reference implementation priority in any - disagreement. The C language is also one of the most widely - understood, human-readable symbolic representations for machine - behavior. For these reasons, this RFC uses the reference - implementation as the sole symbolic representation of the codec. - -What this is basically saying is that the source code should be considered the main point of reference for the format of -the Opus bit stream. We cannot, however, just willy nilly take code from the reference implementation because that would -cause licensing problems. However, I'm going to make a prediction before I even begin: I think RFC 6716 with a bit -intuition, problem solving and help from others it can be figured out. Indeed, I think RFC 6716 may even be enough, and -that perhaps the authors of said specification refer to the source code as a self-defence mechanism to guard themselves -from possible subtle errors in the specification. If I'm wrong, the log below will track it. - -Lets begin... - - -2018/11/30 6:55 PM -================== -- Inserted skeleton code with licensing information. Dual licensed as Public Domain _or_ MIT, whichever you prefer. API - is undecided as of yet. -- Decided on supporting C89. Not yet decided on how the standard library will be used. -- Deciding for now to use the init() style of API from dr_wav and dr_mp3 which takes a pre-allocated decoder object. May - need to change this to dr_flac style open() (or perhaps new()/delete()) if the size of the structure is too big. -- dr_wav, etc. use booleans for results status so I'm copying that for consistency. -- Added boilerplate for standard sized types (copied from mini_al). -- Added a comment at the top of the file to show that this isn't complete (even though it's in the "wip" folder!). -- Added boilerplate for read and seek callbacks (copied from dr_flac). -- Added shell APIs: - - dropus_init() - - Not requiring onSeek for the moment because I'm hoping that we can make that optional somehow, with restriction. - - dropus_uninit() - - Does nothing at the moment, but in future will need to close a file when the decoder is opened against a file. -- Added some common overrideable macros (taken from dr_flac): - - DROPUS_ASSERT - - DROPUS_COPY_MEMORY - - DROPUS_ZERO_MEMORY - - DROPUS_ZERO_OBJECT -- Decided to use the C standard library for now. This simplifies things like memset() and assert(). Currently using the - following headers: - - stddef.h - - stdint.h - - stdlib.h - - string.h - - assert.h -- Added some infrastructure for future APIs: dropus_init_file() and dropus_init_memory() - - In dr_flac, dr_wav and dr_mp3, a mistake was made with how the internal file handle is managed by the decoder. In - these libraries the pUserData member of the decoder structure is recycled to hold the FILE pointer. dr_opus is - changing this to be it's own member of the main decoder structure. - - The internal members for use with dropus_init_memory() use the same system as dr_mp3. See drmp3.memory. -- Added dropus_init_file() - - All init() APIs call dropus_init_internal() which is where the main initialization work is done. - - This is using the stdio FILE API. - - dropus_uninit() has been updated to close the file. - - Added dropus_fopen() for compiler compatibility. Taken from dr_flac, but added the "mode" parameter for consistency - with fopen(). - - Added dropus_fclose() for namespace consistency with dropus_fopen(). -- Added dropus_init_memory() - - onRead and onSeek callbacks taken from dr_mp3. -- INITIAL COMMIT - -2018/12/01 12:46 PM -=================== -- Downloading all official test vectors in preparation for future testing. - -2018/12/01 03:58 PM -=================== -- Decided to figure out the different encapsulations for Opus so I can figure out a design for data flow. - - Ogg: https://tools.ietf.org/html/rfc7845 - - Matroska: https://wiki.xiph.org/MatroskaOpus - - WebM: https://www.webmproject.org/docs/container/ - - MPEG-TS: https://wiki.xiph.org/OpusTS - - Mysterious encapsulation used by the official test vectors. Looking at this it's hard to tell what they are using for - this, but I'm assuming it's not documented. Will need to figure that one out for myself later. -- Since WebM is a subset of Matroska, can we combine those together to avoid code duplication? -- Upon reading into Ogg and MPEG-TS encapsulation (not looked into Matroska in detail yet) it looks like handling large - channel counts is going to be a pain. It can support up to 255 channels, which are made up of multiple streams. My - instict is telling me that we won't be able to use a fixed sized data structure and instead might require dynamic - allocations. Darn... -- Leaning towards a two-tier architecture - a low-level decoder for raw Opus streams, and a high-level API for encapsulated - streams. Opus packets support only 1 or 2 channels which means the size of the structure _can_ be fixed. - - Currently I'm thinking something like the following: - - struct dropus_stream - low-level Opus stream decoding - - struct dropus - high-level encapsulated Opus stream decoding - - struct dropus_ogg (Ogg Opus) - - struct dropus_mk (Matroska) - - struct dropus_ts (MPEG-TS) - - struct dropus_tv (That annoying non-standard and undocumented encapsulation used by the test vectors) -- The maximum number of samples per frame (per-channel) is 960 because: - - The maximum frame size for wideband (16kHz) is 60: 16*60 = 960 - - The maximum frame size for fullband (48kHz) is 20: 48*20 = 960 - - To account for stereo frames we would need to multiply 960 by 2: 960*2 = 1920 - - This is small enough that it can be stored statically inside the dropus_stream structure. -- It looks like low level Opus streams won't be able to do efficient seeking without an encapsulation. -- An Opus stream is made up of packets. Each packet has 1 or more frames. Each frame can be made up of 1 or 2 channels. -- The size of the packet in bytes is unknown at the Opus stream level - it depends on the encapsulation to know the - size of the packet. This could be a bit of a problem because we may need to know the size of a frame in order to know - how much data we need from the client. I'm wondering if the low-level API should look something like the following: - - dropus_result dropus_stream_decode_packet(dropus_stream* pOpusStream, const void* pCompressedData, size_t compressedDataSize); - - This will require the caller to have information on the size of the packet. -- Added struct dropus_stream_packet, dropus_stream_frame. -- Each packet contains a byte that defines the structure of the packet. It's called the TOC byte - (Section 3.1. The TOC Byte) in the RFC 6716. -- Added skeleton implementations for dropus_stream_init() and dropus_stream_decode_packet(). -- Added helpers for decoding the different parts of TOC byte. - - dropus_toc_config(), dropus_toc_s() and dropus_toc_c() -- Added enum for the three different modes as outlined in Section 3.1 of RFC 6716. Also added an API to extract this - mode from the config component of the TOC: dropus_toc_config_mode() and dropus_toc_mode(). -- Added API to extract sample rate from the TOC: dropus_toc_config_sample_rate() and dropus_toc_sample_rate() -- Added API to extract the size of an Opus frame in PCM frames from the TOC: - - dropus_toc_config_frame_size_in_pcm_frames() and dropus_toc_frame_size_in_pcm_frames(). -- COMMIT - -2018/12/02 09:45 AM -=================== -- Compiling for the first time. Targetting C89 so need to get it all working property right from the start. -- "test" folder added to my local repository. Not version controlled yet as I'm not sure I want to include all of - the test stuff in the repository. Will definitely not be version controlling the test vectors. Perhaps use a submodule? -- Have decided to not support the mysterious encapsulation format used by the test vectors in dr_opus itself. Instead - I'm just doing it manually in the test program. -- After attempting to build the C++ version, it appears Clang will attempt to #include stdint.h from Visual Studio's - standard library which fails. May need to come up with a way to avoid the dependency on stdint.h. Same thing also - happens with stdlib.h. -- Have cleaned up the sized types stuff for Clang to avoid the dependency on stdint, however errors are still happening - due to the use of stdlib.h. Leaving the Clang C++ issue for now. It's technically a Clang issue rather than dr_opus. -- COMMIT -- Have decided to version control test programs, but not test vectors. Instead I'm putting a note in a readme about - where to download and place the test vectors. -- In my experience I have found that having a testing infrastructure set up earlier saves a lot of time in the long run - so the next thing I have decided to work on is a test program. It makes sense to test against the official test vectors, - so the first thing is to figure out this undocumented encapsulation format... - -Test Vector Encapsulation Format --------------------------------- -- All test vectors seem to start with two bytes of 0x00. - - This does not feel like a magic number or identifier. -- Noticed that first 4 bytes add up to a relatively small number. A counter of some kind in little endian format? -- A pattern can be seen in testvector02.bit: - - The bytes 00 00 00 XX can been seen repeating. This indicates some kind of blocking. - - From the first 4 bytes you see the hex value of 0x0000001E which equals 30 in decimal - - Counting forward 30 bytes brings us 4 bytes before the next set of 00 00 00 XX bytes. Definitely starting to feel like - the first 4 bytes are a byte counter. - - Skipping past those four bytes and looking at the next 00 00 00 XX bytes we get 0x0000001D which is 29 in decimal. - - Again, counting forward by that number of bytes brings us to 4 bytes prior to the next 00 00 00 XX block. First 4 - bytes are definitely a byte counter. -- It makes sense that each of these blocks are an Opus packet. -- Still don't know what the second set of 4 bytes could represent... Does it matter for our purposes? All we care about - is the raw Opus bit stream. - - A Google search for "opus test vector format" brings up the following result (a PDF document): - - https://www.ietf.org/proceedings/82/slides/codec-4.pdf - - From the "Force Multipliers" page: - - "The range coder has 32 bits of state which must match between the encoder and decoder" - - "Provides a checksum of all encoding and decoding decisions" - - "opus_demo bitstreams include the range value with every packet and test for mismatches" - - Willing to bet that the extra 4 bytes are that "32 bits of state". This is actually good for dr_opus. -- I think the format is just a list of Opus packets with 8 bytes of header data for each one: - 4 bytes: Opus packet size in bytes - 4 bytes: 32 bit of range coder state - [Opus Packet] --------------------------------- - -- The test program can either hard code a list of vector files or we can enumerate over files in known directories. I'm - preferring the latter to make it easier to add new vectors. It's also consistent with the way dr_flac does it which has - been pretty good in the past. -- Started work on a "common" lib for test programs. First thing is the new file iterator. - - File iterator now done, but only supporting Windows currently. -- Have implemented the logic for loading test vectors and the byte counter (and I'm assuming the range state) is actually - in big-endian, not little-endian. I'm an idiot! -- Copying endian management APIs from dr_flac over to dr_opus. -- Basic infrastructure for testing against the standard test vectors is now done. -- COMMIT - -2018/12/03 6:15 PM -================== -- The packet enumeration in the test program seems to work so far, but I'm still not 100% sure that my assumptions are - correct. Adding more validation to dropus_stream_decode_packet() to increase my certainty. The next stage is to - implement all of the main packet validation. -- Question for later. How are "Discontinuous Transmission (DTX) or lost packet" handled? Should - dropus_stream_decode_packet() return an error in this case? -- Code for validating packet codes 0, 1 and 2 are now in, however untested so far. Code 3 is a bit more complicated and - right now I need to eat dinner... -- COMMIT - -2018/12/03 6:40 PM -================== -- Code 3 CBR is done (no VBR yet). Still untested. -- Code 3 VBR is done. Still untested. -- Testing and debugging against the standard test vectors coming next. -- Fixed a few compiler warnings. -- COMMIT - -2019/03/08 6:28 PM -================== -- Starting on range decoding. From figure 4 in RFC 6716 the diagram shows that both the SILK and CELT decoders draw - their data from the Range Decoder. Therefore the Range Decoder needs to be figured out before SILK and CELT decoding. - I have no prior knowledge on range coding, so hopefully RFC 6716 has enough information for a complete enough - implementation for purpose of Opus decoding. -- Section 4.1.1 of RGC 6716 is how to initialize the decoder. It references a variable called "rng", but doesn't - specificy it's possible ranges. Setting to a 32-bit unsigned integer for now. - - In this section, it says "or containing zero if there are no bytes in this Opus frame". I'm assuming we do this - by looping over each frame in order... - - Just noticed that the end of section 4.1.1 says "rng > 2**23". So "rng" needs to be 32-bits. -- And now I've just noticed that section 4.1 explicitly says the following: "Both val and rng are 32-bit unsigned integer - values." Problem solved. -- Having read over the range coding stuff in RFC 6716 I had some difficulty figuring out where symbols frequencies are - being stored. They're not stored, but rather specified in the specification in a per-context basis. In the spec there - are references to "PDFs" which is like this "{f[0], f[1]}/ft". Example: "{1, 1}/2". Simple, now that I've finally - figured it out... -- I can therefore not do the range decoder independant of some higher level context. I will start with the SILK decoder - since that's the next section... - -2019/03/09 6:52 AM -================== -- I think I'm getting a feel for the requirements for the range decoding API. I've decided for now to use a structure - for this called dropus_range_decoder. -- dropus_range_decoder_init() implemented based on section 4.1.1. -- Added stub for dropus_stream_decode_frame(). I think the idea is that we iterate over each frame in the packet and - decode them in order? Not fully sure yet how frame transitions will work, so may need to rethink this. -- I'm still not sure if the range decoder is supposed to be initialized once per frame or once per packet... -- After more testing it turns out my test program wasn't reporting errors properly. *Sigh*. These bugs were originating - from the packet decoding section. -- COMMIT -- Section 4.1.2 mentions that there's two steps to decoding a symbol. The first step seems easy enough. Implemented in - dropus_range_decoder_fs(). -- The second step requires updating "val" and "rng" of the range decoder based on (fl[k], fh[k] and ft). Implemented in - dropus_range_decoder_update(pRangeDecoder, fl, fh, ft). -- Normalization of the range decoder is easy (RFC 6716 - 4.1.2.1). Implemented in dropus_range_decoder_normalize(). -- I think at this point we have the foundations done for the range decoder. Still more to do for CELT, but I think I - now have enough to hack away a bit more at the SILK-specific data. -- COMMIT -- I'm still not 100% sure how range decoding works - I know it depends on the context of the specific thing being - decoded, but not sure how the index "k" is handled. The first part of the SILK frame is the VAD flags PDF={1,1}/2. - Do I use the value of k (which I think is 0 or 1) to know whether or not the bit is set? I am going to assume this - for now. - -2019/03/10 7:40 AM -================== -- At the moment I am using what feels like a very cumbersome way of decoding "k" from the range decoder. I'm calling - dropus_range_decoder_fs(), followed by a function called dropus_range_decoder_k() to retrieve "k", and then - dropus_range_decoder_update() at the end of it. I can simplify this into a single function, I think, which I'm - calling dropus_range_decode() which will perform the "fs" decode, perform the update, then return "k". -- As I'm writing dropus_range_decoder_decode() I've realized that I can simplify my dropus_range_decoder_update() - function to do both the "k" lookup and the the update from section 4.1.2. It just needs to be changed to take - the "context" probabilities and "fs" and to return "k". -- This _seems_ to work. Or at least, the results are consistent with my first attempt. Committing. -- Added dropus_Q13() for doing the stereo weight lookup (RFC 7616 - Table 7). -- Section 4.2.7.1 mentions that the weights are linearly interpolated with the weights from the previous frame. What - factor do I use for the interpolation? -- Finished initial work on RFC 7616 - Section 4.2.7.1. Still don't know how the interpolation part works. I'm hoping - this is explained later in the spec. -- COMMIT -- Completed initial implementation of RFC 7616 - Section 4.2.7.2. - -2020/03/29 6:33 AM -================== -- After a whole year, time to take another look at this. Only problem is, I've forgotten everything! Let's do a - quick pass on the high level stuff to get it consistent with dr_flac. Two mistakes I made with dr_flac: Not having - a low-level API that works on the FLAC frame level; and returning booleans instead of result codes. The first one - is already being handled, but lets update the high level APIs to use result codes. -- High level APIs now updated to return result codes. -- People are going to want to log errors: added dropus_result_description() to retrieve a human readable description - of a result code for logging and error reporting purposes. -- I've had reports of people having compilation errors with inlining before. Need to bring over the INLINE macro from - dr_flac to ensure we don't get more reports about that. -- I've had people request the ability to customize whether or not public APIs are marked as static or extern in other - libraries, so adding the DROPUS_API decoration. It's better to do this sooner than later, because this happened with - miniaudio recently which was a ~40K line library at the time, and it was nightmare to update! -- There will be a requirement to allocate memory for high level APIs. Support for allocation macros and allocation - callbacks need to be added now so we can avoid breaking APIs later. -- There have been requests in the past to support loading files from a wchar_t encoded path. Adding support by pulling - in custom fopen() and wfopen() implementations from dr_flac. -- Have not yet compiled on VC6 so lets do a pass on that to make it easier for us later. -- VC6 is now compiling clean. Time to check GCC and Clang in strict C89 mode. -- Getting compiler errors about some Linux specific code for handling byte swaps. Removed and replaced with a cross- - platform solution. -- From what I can see it looks like our boilerplate is now up to date with dr_flac, dr_wav and dr_mp3. Time to get onto - some actual Opus decoding. -- Looks like a typo in dropus_range_decoder_update() for handling the `fl[k] > 0` case. Changed this, but now getting - a division by zero. Debugging... - - And fixed. The last paragraph in RFC 6716 - Section 4.1.2 is the part I was missing: - After the updates, implemented by ec_dec_update() (entdec.c), the - decoder normalizes the range using the procedure in the next section, - and returns the index k. -- Reading through dropus_stream_decode_packet() to refresh my memory and some stuff needs cleaning up. Important from - now on to distinguish between PCM frames and Opus frames. All variables referring to one of the other needs to be - prefixed with "pcm" or "opus", depending on it's use. Example: opusFrameCount / pcmFrameCount. -- Added infrastructure for handling CELT and Hybrid frames when the time comes. For now still focused on getting SILK - frames working. -- Reviewing SILK decoding logic to refresh my memory and looks like I've misinterpreted the encoding for per-frame - LBRR flags. When there's more than one SILK frame, the first LBRR flag is just used to determine whether or not - the per-frame LBRR flags is present. I was _always_ reading the LBRR flags regardless of the value of the primary - LBRR flag. - -2020/03/30 7:30 AM -================== -- The decoding of SILK frames needs to be put in their own function in order to handle LBRR and regular SILK frames. - Looking at the spec, there's some complicated branching logic for determine what needs to be decoded. I've put in - a rough draft as a start, but needs some work. Will continue on this later. \ No newline at end of file diff --git a/source/engine/thirdparty/quickjs/.github/workflows/ci.yml b/source/engine/thirdparty/quickjs/.github/workflows/ci.yml deleted file mode 100644 index 9eab46f..0000000 --- a/source/engine/thirdparty/quickjs/.github/workflows/ci.yml +++ /dev/null @@ -1,166 +0,0 @@ -name: ci - -on: - pull_request: - paths: - - '**' - - '!.gitignore' - - '!LICENSE' - - '!TODO' - - '!doc/**' - - '!examples/**' - - '.github/workflows/ci.yml' - push: - branches: - - '*' - -jobs: - linux: - name: Linux (Ubuntu) - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y - - name: Stats - run: | - ./qjs -qd - - name: Run built-in tests - run: | - make test - - name: Run microbench - run: | - make microbench - - linux-asan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y - - name: Run built-in tests - env: - ASAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_ASAN=y test - - linux-msan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - env: - CC: clang - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_MSAN=y CONFIG_CLANG=y - - name: Run built-in tests - env: - MSAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_MSAN=y CONFIG_CLANG=y test - - linux-ubsan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y - - name: Run built-in tests - env: - UBSAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_UBSAN=y test - - macos: - name: macOS - runs-on: macos-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y - - name: Stats - run: | - ./qjs -qd - - name: Run built-in tests - run: | - make test - - macos-asan: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y - - name: Run built-in tests - env: - ASAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_ASAN=y test - - macos-ubsan: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y - - name: Run built-in tests - env: - UBSAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_UBSAN=y test - - freebsd: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build + test - uses: vmactions/freebsd-vm@v1 - with: - usesh: true - prepare: | - pkg install -y gmake - run: | - gmake - ./qjs -qd - gmake test - - qemu-alpine: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - platform: - - i386 - - arm32v6 - - arm32v7 - - arm64v8 - - s390x - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Get qemu - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - - name: Run tests on ${{ matrix.platform }} - run: docker run --rm --interactive --mount type=bind,source=$(pwd),target=/host ${{ matrix.platform }}/alpine sh -c "apk add git patch make gcc libc-dev && cd /host && make test" - diff --git a/source/engine/thirdparty/quickjs/examples/fib.c b/source/engine/thirdparty/quickjs/examples/fib.c deleted file mode 100644 index be90af5..0000000 --- a/source/engine/thirdparty/quickjs/examples/fib.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * QuickJS: Example of C module - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ -#include "../quickjs.h" - -#define countof(x) (sizeof(x) / sizeof((x)[0])) - -static int fib(int n) -{ - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); -} - -static JSValue js_fib(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int n, res; - if (JS_ToInt32(ctx, &n, argv[0])) - return JS_EXCEPTION; - res = fib(n); - return JS_NewInt32(ctx, res); -} - -static const JSCFunctionListEntry js_fib_funcs[] = { - JS_CFUNC_DEF("fib", 1, js_fib ), -}; - -static int js_fib_init(JSContext *ctx, JSModuleDef *m) -{ - return JS_SetModuleExportList(ctx, m, js_fib_funcs, - countof(js_fib_funcs)); -} - -#ifdef JS_SHARED_LIBRARY -#define JS_INIT_MODULE js_init_module -#else -#define JS_INIT_MODULE js_init_module_fib -#endif - -JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_fib_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs)); - return m; -} diff --git a/source/engine/thirdparty/quickjs/examples/fib_module.js b/source/engine/thirdparty/quickjs/examples/fib_module.js deleted file mode 100644 index 6a81071..0000000 --- a/source/engine/thirdparty/quickjs/examples/fib_module.js +++ /dev/null @@ -1,10 +0,0 @@ -/* fib module */ -export function fib(n) -{ - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); -} diff --git a/source/engine/thirdparty/quickjs/examples/hello.js b/source/engine/thirdparty/quickjs/examples/hello.js deleted file mode 100644 index accefce..0000000 --- a/source/engine/thirdparty/quickjs/examples/hello.js +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello World"); diff --git a/source/engine/thirdparty/quickjs/examples/hello_module.js b/source/engine/thirdparty/quickjs/examples/hello_module.js deleted file mode 100644 index 463660f..0000000 --- a/source/engine/thirdparty/quickjs/examples/hello_module.js +++ /dev/null @@ -1,6 +0,0 @@ -/* example of JS module */ - -import { fib } from "./fib_module.js"; - -console.log("Hello World"); -console.log("fib(10)=", fib(10)); diff --git a/source/engine/thirdparty/quickjs/examples/pi_bigdecimal.js b/source/engine/thirdparty/quickjs/examples/pi_bigdecimal.js deleted file mode 100644 index 7cb7ad6..0000000 --- a/source/engine/thirdparty/quickjs/examples/pi_bigdecimal.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * PI computation in Javascript using the QuickJS bigdecimal type - * (decimal floating point) - */ -"use strict"; - -/* compute PI with a precision of 'prec' digits */ -function calc_pi(prec) { - const CHUD_A = 13591409m; - const CHUD_B = 545140134m; - const CHUD_C = 640320m; - const CHUD_C3 = 10939058860032000m; /* C^3/24 */ - const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1; - if (a == (b - 1n)) { - b1 = BigDecimal(b); - G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m); - P = G * (CHUD_B * b1 + CHUD_A); - if (b & 1n) - P = -P; - G = G; - Q = b1 * b1 * b1 * CHUD_C3; - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0m; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = BigDecimal.div(Q, (P + Q * CHUD_A), - { roundingMode: "half-even", - maximumSignificantDigits: prec }); - G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C, - { roundingMode: "half-even", - maximumSignificantDigits: prec }); - return Q * G; -} - -(function() { - var r, n_digits, n_bits; - if (typeof scriptArgs != "undefined") { - if (scriptArgs.length < 2) { - print("usage: pi n_digits"); - return; - } - n_digits = scriptArgs[1] | 0; - } else { - n_digits = 1000; - } - /* we add more digits to reduce the probability of bad rounding for - the last digits */ - r = calc_pi(n_digits + 20); - print(r.toFixed(n_digits, "down")); -})(); diff --git a/source/engine/thirdparty/quickjs/examples/pi_bigfloat.js b/source/engine/thirdparty/quickjs/examples/pi_bigfloat.js deleted file mode 100644 index 8372379..0000000 --- a/source/engine/thirdparty/quickjs/examples/pi_bigfloat.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * PI computation in Javascript using the QuickJS bigfloat type - * (binary floating point) - */ -"use strict"; - -/* compute PI with a precision of 'prec' bits */ -function calc_pi() { - const CHUD_A = 13591409n; - const CHUD_B = 545140134n; - const CHUD_C = 640320n; - const CHUD_C3 = 10939058860032000n; /* C^3/24 */ - const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; - if (a == (b - 1n)) { - G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); - P = BigFloat(G * (CHUD_B * b + CHUD_A)); - if (b & 1n) - P = -P; - G = BigFloat(G); - Q = BigFloat(b * b * b * CHUD_C3); - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0l; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = Q / (P + Q * BigFloat(CHUD_A)); - G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C)); - return Q * G; -} - -(function() { - var r, n_digits, n_bits; - if (typeof scriptArgs != "undefined") { - if (scriptArgs.length < 2) { - print("usage: pi n_digits"); - return; - } - n_digits = scriptArgs[1]; - } else { - n_digits = 1000; - } - n_bits = Math.ceil(n_digits * Math.log2(10)); - /* we add more bits to reduce the probability of bad rounding for - the last digits */ - BigFloatEnv.setPrec( () => { - r = calc_pi(); - print(r.toFixed(n_digits, BigFloatEnv.RNDZ)); - }, n_bits + 32); -})(); diff --git a/source/engine/thirdparty/quickjs/examples/pi_bigint.js b/source/engine/thirdparty/quickjs/examples/pi_bigint.js deleted file mode 100644 index e15abd1..0000000 --- a/source/engine/thirdparty/quickjs/examples/pi_bigint.js +++ /dev/null @@ -1,118 +0,0 @@ -/* - * PI computation in Javascript using the BigInt type - */ -"use strict"; - -/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ -function floor_log2(a) -{ - var k_max, a1, k, i; - k_max = 0n; - while ((a >> (2n ** k_max)) != 0n) { - k_max++; - } - k = 0n; - a1 = a; - for(i = k_max - 1n; i >= 0n; i--) { - a1 = a >> (2n ** i); - if (a1 != 0n) { - a = a1; - k |= (1n << i); - } - } - return k; -} - -/* return ceil(log2(a)) for a > 0 */ -function ceil_log2(a) -{ - return floor_log2(a - 1n) + 1n; -} - -/* return floor(sqrt(a)) (not efficient but simple) */ -function int_sqrt(a) -{ - var l, u, s; - if (a == 0n) - return a; - l = ceil_log2(a); - u = 1n << ((l + 1n) / 2n); - /* u >= floor(sqrt(a)) */ - for(;;) { - s = u; - u = ((a / s) + s) / 2n; - if (u >= s) - break; - } - return s; -} - -/* return pi * 2**prec */ -function calc_pi(prec) { - const CHUD_A = 13591409n; - const CHUD_B = 545140134n; - const CHUD_C = 640320n; - const CHUD_C3 = 10939058860032000n; /* C^3/24 */ - const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; - if (a == (b - 1n)) { - G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); - P = G * (CHUD_B * b + CHUD_A); - if (b & 1n) - P = -P; - Q = b * b * b * CHUD_C3; - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0n; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); - G = int_sqrt(CHUD_C << (2n * prec)); - return (Q * G) >> prec; -} - -function main(args) { - var r, n_digits, n_bits, out; - if (args.length < 1) { - print("usage: pi n_digits"); - return; - } - n_digits = args[0] | 0; - - /* we add more bits to reduce the probability of bad rounding for - the last digits */ - n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; - r = calc_pi(n_bits); - r = ((10n ** BigInt(n_digits)) * r) >> n_bits; - out = r.toString(); - print(out[0] + "." + out.slice(1)); -} - -var args; -if (typeof scriptArgs != "undefined") { - args = scriptArgs; - args.shift(); -} else if (typeof arguments != "undefined") { - args = arguments; -} else { - /* default: 1000 digits */ - args=[1000]; -} - -main(args); diff --git a/source/engine/thirdparty/quickjs/examples/point.c b/source/engine/thirdparty/quickjs/examples/point.c deleted file mode 100644 index 0386230..0000000 --- a/source/engine/thirdparty/quickjs/examples/point.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * QuickJS: Example of C module with a class - * - * Copyright (c) 2019 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ -#include "../quickjs.h" -#include - -#define countof(x) (sizeof(x) / sizeof((x)[0])) - -/* Point Class */ - -typedef struct { - int x; - int y; -} JSPointData; - -static JSClassID js_point_class_id; - -static void js_point_finalizer(JSRuntime *rt, JSValue val) -{ - JSPointData *s = JS_GetOpaque(val, js_point_class_id); - /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ - js_free_rt(rt, s); -} - -static JSValue js_point_ctor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSPointData *s; - JSValue obj = JS_UNDEFINED; - JSValue proto; - - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &s->x, argv[0])) - goto fail; - if (JS_ToInt32(ctx, &s->y, argv[1])) - goto fail; - /* using new_target to get the prototype is necessary when the - class is extended. */ - proto = JS_GetPropertyStr(ctx, new_target, "prototype"); - if (JS_IsException(proto)) - goto fail; - obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id); - JS_FreeValue(ctx, proto); - if (JS_IsException(obj)) - goto fail; - JS_SetOpaque(obj, s); - return obj; - fail: - js_free(ctx, s); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - if (!s) - return JS_EXCEPTION; - if (magic == 0) - return JS_NewInt32(ctx, s->x); - else - return JS_NewInt32(ctx, s->y); -} - -static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - int v; - if (!s) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &v, val)) - return JS_EXCEPTION; - if (magic == 0) - s->x = v; - else - s->y = v; - return JS_UNDEFINED; -} - -static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - if (!s) - return JS_EXCEPTION; - return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y)); -} - -static JSClassDef js_point_class = { - "Point", - .finalizer = js_point_finalizer, -}; - -static const JSCFunctionListEntry js_point_proto_funcs[] = { - JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0), - JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1), - JS_CFUNC_DEF("norm", 0, js_point_norm), -}; - -static int js_point_init(JSContext *ctx, JSModuleDef *m) -{ - JSValue point_proto, point_class; - - /* create the Point class */ - JS_NewClassID(&js_point_class_id); - JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class); - - point_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); - - point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); - /* set proto.constructor and ctor.prototype */ - JS_SetConstructor(ctx, point_class, point_proto); - JS_SetClassProto(ctx, js_point_class_id, point_proto); - - JS_SetModuleExport(ctx, m, "Point", point_class); - return 0; -} - -JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_point_init); - if (!m) - return NULL; - JS_AddModuleExport(ctx, m, "Point"); - return m; -} diff --git a/source/engine/thirdparty/quickjs/examples/test_fib.js b/source/engine/thirdparty/quickjs/examples/test_fib.js deleted file mode 100644 index 70d26bd..0000000 --- a/source/engine/thirdparty/quickjs/examples/test_fib.js +++ /dev/null @@ -1,6 +0,0 @@ -/* example of JS module importing a C module */ - -import { fib } from "./fib.so"; - -console.log("Hello World"); -console.log("fib(10)=", fib(10)); diff --git a/source/engine/thirdparty/quickjs/examples/test_point.js b/source/engine/thirdparty/quickjs/examples/test_point.js deleted file mode 100644 index 0659bc3..0000000 --- a/source/engine/thirdparty/quickjs/examples/test_point.js +++ /dev/null @@ -1,40 +0,0 @@ -/* example of JS module importing a C module */ -import { Point } from "./point.so"; - -function assert(b, str) -{ - if (b) { - return; - } else { - throw Error("assertion failed: " + str); - } -} - -class ColorPoint extends Point { - constructor(x, y, color) { - super(x, y); - this.color = color; - } - get_color() { - return this.color; - } -}; - -function main() -{ - var pt, pt2; - - pt = new Point(2, 3); - assert(pt.x === 2); - assert(pt.y === 3); - pt.x = 4; - assert(pt.x === 4); - assert(pt.norm() == 5); - - pt2 = new ColorPoint(2, 3, 0xffffff); - assert(pt2.x === 2); - assert(pt2.color === 0xffffff); - assert(pt2.get_color() === 0xffffff); -} - -main(); diff --git a/source/engine/thirdparty/sokol/bindgen/.gitignore b/source/engine/thirdparty/sokol/bindgen/.gitignore deleted file mode 100644 index 4528e59..0000000 --- a/source/engine/thirdparty/sokol/bindgen/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.json -*.nim -*.zig -__pycache__/ -sokol-nim/ -sokol-zig/ -sokol-odin/ -sokol-rust/ diff --git a/source/engine/thirdparty/sokol/bindgen/README.md b/source/engine/thirdparty/sokol/bindgen/README.md deleted file mode 100644 index aef1ec1..0000000 --- a/source/engine/thirdparty/sokol/bindgen/README.md +++ /dev/null @@ -1,40 +0,0 @@ -## Language Binding Generation Scripts - -> REMINDER: we can pass `-fparse-all-comments` to the clang ast-dump command line which adds the following node types to the ast-dump.json: FullComment, ParagraphComment, TextComment. This might allow us to preserve comments in the language bindings (might be useful as part of a bigger change to make sokol header comments autodoc and Intellisense-friendly) - -### Zig - -First make sure that clang and python3 are in the path: - -``` -> clang --version -> python3 --version -``` - -...on Windows I simply install those with scoop: - -``` -> scoop install llvm -> scoop install python -``` - -To update the Zig bindings: - -``` -> cd sokol/bindgen -> git clone https://github.com/floooh/sokol-zig -> git clone https://github.com/floooh/sokol-nim -> git clone https://github.com/floooh/sokol-odin -> git clone https://github.com/floooh/sokol-rust -> python3 gen_all.py -``` - -Test and run samples: - -``` -> cd sokol/bindgen/sokol-zig -> zig build run-clear -> zig build run-triangle -> zig build run-cube -... -``` diff --git a/source/engine/thirdparty/sokol/bindgen/gen_all.py b/source/engine/thirdparty/sokol/bindgen/gen_all.py deleted file mode 100644 index 24389e7..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_all.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, gen_nim, gen_zig, gen_odin, gen_rust - -tasks = [ - [ '../sokol_log.h', 'slog_', [] ], - [ '../sokol_gfx.h', 'sg_', [] ], - [ '../sokol_app.h', 'sapp_', [] ], - [ '../sokol_glue.h', 'sglue_', ['sg_'] ], - [ '../sokol_time.h', 'stm_', [] ], - [ '../sokol_audio.h', 'saudio_', [] ], - [ '../util/sokol_gl.h', 'sgl_', ['sg_'] ], - [ '../util/sokol_debugtext.h', 'sdtx_', ['sg_'] ], - [ '../util/sokol_shape.h', 'sshape_', ['sg_'] ], -] - -# Odin -gen_odin.prepare() -for task in tasks: - [c_header_path, main_prefix, dep_prefixes] = task - gen_odin.gen(c_header_path, main_prefix, dep_prefixes) - -# Nim -gen_nim.prepare() -for task in tasks: - [c_header_path, main_prefix, dep_prefixes] = task - gen_nim.gen(c_header_path, main_prefix, dep_prefixes) - -# Zig -gen_zig.prepare() -for task in tasks: - [c_header_path, main_prefix, dep_prefixes] = task - gen_zig.gen(c_header_path, main_prefix, dep_prefixes) - -# Rust -gen_rust.prepare() -for task in tasks: - [c_header_path, main_prefix, dep_prefixes] = task - gen_rust.gen(c_header_path, main_prefix, dep_prefixes) diff --git a/source/engine/thirdparty/sokol/bindgen/gen_ir.py b/source/engine/thirdparty/sokol/bindgen/gen_ir.py deleted file mode 100644 index 0089ae2..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_ir.py +++ /dev/null @@ -1,124 +0,0 @@ -#------------------------------------------------------------------------------- -# Generate an intermediate representation of a clang AST dump. -#------------------------------------------------------------------------------- -import json, sys, subprocess - -def is_api_decl(decl, prefix): - if 'name' in decl: - return decl['name'].startswith(prefix) - elif decl['kind'] == 'EnumDecl': - # an anonymous enum, check if the items start with the prefix - return decl['inner'][0]['name'].lower().startswith(prefix) - else: - return False - -def is_dep_decl(decl, dep_prefixes): - for prefix in dep_prefixes: - if is_api_decl(decl, prefix): - return True - return False - -def dep_prefix(decl, dep_prefixes): - for prefix in dep_prefixes: - if is_api_decl(decl, prefix): - return prefix - return None - -def filter_types(str): - return str.replace('_Bool', 'bool') - -def parse_struct(decl): - outp = {} - outp['kind'] = 'struct' - outp['name'] = decl['name'] - outp['fields'] = [] - for item_decl in decl['inner']: - if item_decl['kind'] != 'FieldDecl': - sys.exit(f"ERROR: Structs must only contain simple fields ({decl['name']})") - item = {} - if 'name' in item_decl: - item['name'] = item_decl['name'] - item['type'] = filter_types(item_decl['type']['qualType']) - outp['fields'].append(item) - return outp - -def parse_enum(decl): - outp = {} - if 'name' in decl: - outp['kind'] = 'enum' - outp['name'] = decl['name'] - needs_value = False - else: - outp['kind'] = 'consts' - needs_value = True - outp['items'] = [] - for item_decl in decl['inner']: - if item_decl['kind'] == 'EnumConstantDecl': - item = {} - item['name'] = item_decl['name'] - if 'inner' in item_decl: - const_expr = item_decl['inner'][0] - if const_expr['kind'] != 'ConstantExpr': - sys.exit(f"ERROR: Enum values must be a ConstantExpr ({item_decl['name']}), is '{const_expr['kind']}'") - if const_expr['valueCategory'] != 'rvalue' and const_expr['valueCategory'] != 'prvalue': - sys.exit(f"ERROR: Enum value ConstantExpr must be 'rvalue' or 'prvalue' ({item_decl['name']}), is '{const_expr['valueCategory']}'") - if not ((len(const_expr['inner']) == 1) and (const_expr['inner'][0]['kind'] == 'IntegerLiteral')): - sys.exit(f"ERROR: Enum value ConstantExpr must have exactly one IntegerLiteral ({item_decl['name']})") - item['value'] = const_expr['inner'][0]['value'] - if needs_value and 'value' not in item: - sys.exit(f"ERROR: anonymous enum items require an explicit value") - outp['items'].append(item) - return outp - -def parse_func(decl): - outp = {} - outp['kind'] = 'func' - outp['name'] = decl['name'] - outp['type'] = filter_types(decl['type']['qualType']) - outp['params'] = [] - if 'inner' in decl: - for param in decl['inner']: - if param['kind'] != 'ParmVarDecl': - print(f" >> warning: ignoring func {decl['name']} (unsupported parameter type)") - return None - outp_param = {} - outp_param['name'] = param['name'] - outp_param['type'] = filter_types(param['type']['qualType']) - outp['params'].append(outp_param) - return outp - -def parse_decl(decl): - kind = decl['kind'] - if kind == 'RecordDecl': - return parse_struct(decl) - elif kind == 'EnumDecl': - return parse_enum(decl) - elif kind == 'FunctionDecl': - return parse_func(decl) - else: - return None - -def clang(csrc_path): - cmd = ['clang', '-Xclang', '-ast-dump=json', '-c' ] - cmd.append(csrc_path) - return subprocess.check_output(cmd) - -def gen(header_path, source_path, module, main_prefix, dep_prefixes): - ast = clang(source_path) - inp = json.loads(ast) - outp = {} - outp['module'] = module - outp['prefix'] = main_prefix - outp['dep_prefixes'] = dep_prefixes - outp['decls'] = [] - for decl in inp['inner']: - is_dep = is_dep_decl(decl, dep_prefixes) - if is_api_decl(decl, main_prefix) or is_dep: - outp_decl = parse_decl(decl) - if outp_decl is not None: - outp_decl['is_dep'] = is_dep - outp_decl['dep_prefix'] = dep_prefix(decl, dep_prefixes) - outp['decls'].append(outp_decl) - with open(f'{module}.json', 'w') as f: - f.write(json.dumps(outp, indent=2)); - return outp diff --git a/source/engine/thirdparty/sokol/bindgen/gen_nim.py b/source/engine/thirdparty/sokol/bindgen/gen_nim.py deleted file mode 100644 index 700305a..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_nim.py +++ /dev/null @@ -1,613 +0,0 @@ -#------------------------------------------------------------------------------- -# Generate Nim bindings -# -# Nim coding style: -# - type identifiers are PascalCase, everything else is camelCase -# - reference: https://nim-lang.org/docs/nep1.html -#------------------------------------------------------------------------------- -import gen_ir -import gen_util as util -import os, shutil, sys - -module_names = { - 'slog_': 'log', - 'sg_': 'gfx', - 'sapp_': 'app', - 'stm_': 'time', - 'saudio_': 'audio', - 'sgl_': 'gl', - 'sdtx_': 'debugtext', - 'sshape_': 'shape', - 'sglue_': 'glue', -} - -c_source_paths = { - 'slog_': 'sokol-nim/src/sokol/c/sokol_log.c', - 'sg_': 'sokol-nim/src/sokol/c/sokol_gfx.c', - 'sapp_': 'sokol-nim/src/sokol/c/sokol_app.c', - 'stm_': 'sokol-nim/src/sokol/c/sokol_time.c', - 'saudio_': 'sokol-nim/src/sokol/c/sokol_audio.c', - 'sgl_': 'sokol-nim/src/sokol/c/sokol_gl.c', - 'sdtx_': 'sokol-nim/src/sokol/c/sokol_debugtext.c', - 'sshape_': 'sokol-nim/src/sokol/c/sokol_shape.c', - 'sglue_': 'sokol-nim/src/sokol/c/sokol_glue.c', -} - -c_callbacks = [ - 'slog_func', -] - -ignores = [ - 'sdtx_printf', - 'sdtx_vprintf', -] - -overrides = { - 'sgl_error': 'sgl_get_error', - 'sgl_deg': 'sgl_as_degrees', - 'sgl_rad': 'sgl_as_radians', - 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR', - 'SG_BUFFERTYPE_VERTEXBUFFER': 'SG_BUFFERTYPE_VERTEX_BUFFER', - 'SG_BUFFERTYPE_INDEXBUFFER': 'SG_BUFFERTYPE_INDEX_BUFFER', - 'SG_ACTION_DONTCARE': 'SG_ACTION_DONT_CARE', - 'ptr': 'addr', # range ptr - 'func': 'fn', - 'slog_func': 'fn', -} - -enumPrefixOverrides = { - # sokol_gfx.h - 'LOADACTION': 'loadAction', - 'STOREACTION': 'storeAction', - 'PIXELFORMAT': 'pixelFormat', - 'RESOURCESTATE': 'resourceState', - 'BUFFERTYPE': 'bufferType', - 'INDEXTYPE': 'indexType', - 'IMAGETYPE': 'imageType', - 'SAMPLERTYPE': 'samplerType', - 'CUBEFACE': 'cubeFace', - 'SHADERSTAGE': 'shaderStage', - 'PRIMITIVETYPE': 'primitiveType', - 'BORDERCOLOR': 'borderColor', - 'VERTEXFORMAT': 'vertexFormat', - 'VERTEXSTEP': 'vertexStep', - 'UNIFORMTYPE': 'uniformType', - 'UNIFORMLAYOUT': 'uniformLayout', - 'CULLMODE': 'cullMode', - 'FACEWINDING': 'faceWinding', - 'COMPAREFUNC': 'compareFunc', - 'STENCILOP': 'stencilOp', - 'BLENDFACTOR': 'blendFactor', - 'BLENDOP': 'blendOp', - 'COLORMASK': 'colorMask', - # sokol_app.h - 'EVENTTYPE': 'eventType', - 'KEYCODE': 'keyCode', - 'MOUSEBUTTON': 'mouseButton', -} - -prim_types = { - 'int': 'int32', - 'bool': 'bool', - 'char': 'char', - 'int8_t': 'int8', - 'uint8_t': 'uint8', - 'int16_t': 'int16', - 'uint16_t': 'uint16', - 'int32_t': 'int32', - 'uint32_t': 'uint32', - 'int64_t': 'int64', - 'uint64_t': 'uint64', - 'float': 'float32', - 'double': 'float64', - 'uintptr_t': 'uint', - 'intptr_t': 'int', - 'size_t': 'int', # not a bug, Nim's sizeof() returns int -} - -prim_defaults = { - 'int': '0', - 'bool': 'false', - 'int8_t': '0', - 'uint8_t': '0', - 'int16_t': '0', - 'uint16_t': '0', - 'int32_t': '0', - 'uint32_t': '0', - 'int64_t': '0', - 'uint64_t': '0', - 'float': '0.0f', - 'double': '0.0', - 'uintptr_t': '0', - 'intptr_t': '0', - 'size_t': '0' -} - -common_prim_types = """ -array -untyped typed void -bool byte char -int int8 int16 int32 int64 -uint uint8 uint16 uint32 uint64 -float float32 float64 -string -cchar cint csize_t -cfloat cdouble -cstring -pointer -""".split() - -keywords = """ -addr and as asm -bind block break -case cast concept const continue converter -defer discard distinct div do -elif else end enum except export -finally for from func -if import in include interface is isnot iterator -let -macro method mixin mod -nil not notin -object of or out -proc ptr -raise ref return -shl shr static -template try tuple type -using -var -when while -xor -yield -""".split() + common_prim_types - -struct_types = [] -enum_types = [] -out_lines = '' - -def reset_globals(): - global struct_types - global enum_types - global out_lines - struct_types = [] - enum_types = [] - out_lines = '' - -def l(s): - global out_lines - out_lines += s + '\n' - -def as_nim_prim_type(s): - return prim_types[s] - -# prefix_bla_blub(_t) => (dep.)BlaBlub -def as_nim_type_name(s, prefix): - parts = s.lower().split('_') - dep = parts[0] + '_' - outp = '' - if not s.startswith(prefix) and dep in module_names: - outp = module_names[dep] + '.' - for part in parts[1:]: - # ignore '_t' type postfix - if (part != 't'): - outp += part.capitalize() - return outp - -def check_override(name, default=None): - if name in overrides: - return overrides[name] - elif default is None: - return name - else: - return default - -def check_ignore(name): - return name in ignores - -def is_power_of_two(val): - return val == 0 or val & (val - 1) == 0 - -def wrap_keywords(s): - if s in keywords: - return f'`{s}`' - else: - return s - -# prefix_bla_blub => blaBlub -def as_camel_case(s, prefix, wrap=True): - outp = s.lower() - if outp.startswith(prefix): - outp = outp[len(prefix):] - parts = outp.lstrip('_').split('_') - outp = parts[0] - for part in parts[1:]: - outp += part.capitalize() - if wrap: - outp = wrap_keywords(outp) - return outp - -# PREFIX_ENUM_BLA_BLO => blaBlo -def as_enum_item_name(s, wrap=True): - outp = s.lstrip('_') - parts = outp.split('_')[1:] - if parts[0] in enumPrefixOverrides: - parts[0] = enumPrefixOverrides[parts[0]] - else: - parts[0] = parts[0].lower() - outp = parts[0] - for part in parts[1:]: - outp += part.capitalize() - if wrap: - outp = wrap_keywords(outp) - return outp - -def is_prim_type(s): - return s in prim_types - -def is_struct_type(s): - return s in struct_types - -def is_enum_type(s): - return s in enum_types - -def is_const_prim_ptr(s): - for prim_type in prim_types: - if s == f"const {prim_type} *": - return True - return False - -def is_prim_ptr(s): - for prim_type in prim_types: - if s == f"{prim_type} *": - return True - return False - -def is_const_struct_ptr(s): - for struct_type in struct_types: - if s == f"const {struct_type} *": - return True - return False - -def type_default_value(s): - return prim_defaults[s] - -def funcptr_args(field_type, prefix): - tokens = field_type[field_type.index('(*)')+4:-1].split(',') - s = "" - n = 0 - for token in tokens: - n += 1 - arg_ctype = token.strip() - if s != "": - s += ", " - arg_nimtype = as_nim_type(arg_ctype, prefix) - if arg_nimtype == "": - return "" # fun(void) - s += f"a{n}:{arg_nimtype}" - if s == "a1:void": - s = "" - return s - -def funcptr_result(field_type, prefix): - ctype = field_type[:field_type.index('(*)')].strip() - return as_nim_type(ctype, prefix) - -def as_nim_type(ctype, prefix, struct_ptr_as_value=False): - if ctype == "void": - return "" - elif is_prim_type(ctype): - return as_nim_prim_type(ctype) - elif is_struct_type(ctype): - return as_nim_type_name(ctype, prefix) - elif is_enum_type(ctype): - return as_nim_type_name(ctype, prefix) - elif util.is_string_ptr(ctype): - return "cstring" - elif util.is_void_ptr(ctype) or util.is_const_void_ptr(ctype): - return "pointer" - elif is_const_struct_ptr(ctype): - nim_type = as_nim_type(util.extract_ptr_type(ctype), prefix) - if struct_ptr_as_value: - return f"{nim_type}" - else: - return f"ptr {nim_type}" - elif is_prim_ptr(ctype) or is_const_prim_ptr(ctype): - return f"ptr {as_nim_type(util.extract_ptr_type(ctype), prefix)}" - elif util.is_func_ptr(ctype): - args = funcptr_args(ctype, prefix) - res = funcptr_result(ctype, prefix) - if res != "": - res = ":" + res - return f"proc({args}){res} {{.cdecl.}}" - elif util.is_1d_array_type(ctype): - array_ctype = util.extract_array_type(ctype) - array_sizes = util.extract_array_sizes(ctype) - return f'array[{array_sizes[0]}, {as_nim_type(array_ctype, prefix)}]' - elif util.is_2d_array_type(ctype): - array_ctype = util.extract_array_type(ctype) - array_sizes = util.extract_array_sizes(ctype) - return f'array[{array_sizes[0]}, array[{array_sizes[1]}, {as_nim_type(array_ctype, prefix)}]]' - else: - sys.exit(f"ERROR as_nim_type: {ctype}") - -def as_nim_struct_name(struct_decl, prefix): - struct_name = check_override(struct_decl['name']) - nim_type = f'{as_nim_type_name(struct_name, prefix)}' - return nim_type - -def as_nim_field_name(field_decl, prefix, check_private=True): - field_name = as_camel_case(check_override(field_decl['name']), prefix) - if check_private: - is_private = field_decl['name'].startswith('_') - if not is_private: - field_name += "*" - return field_name - -def as_nim_field_type(struct_decl, field_decl, prefix): - return as_nim_type(check_override(f"{struct_decl['name']}.{field_decl['name']}", default=field_decl['type']), prefix) - -def gen_struct(decl, prefix): - l(f"type {as_nim_struct_name(decl, prefix)}* = object") - for field in decl['fields']: - l(f" {as_nim_field_name(field, prefix)}:{as_nim_field_type(decl, field, prefix)}") - l("") - -def gen_consts(decl, prefix): - l("const") - for item in decl['items']: - item_name = check_override(item['name']) - l(f" {as_camel_case(item_name, prefix)}* = {item['value']}") - l("") - -def gen_enum(decl, prefix): - item_names_by_value = {} - value = -1 - has_explicit_values = False - for item in decl['items']: - item_name = check_override(item['name']) - if item_name.endswith("_NUM") or item_name.endswith("_FORCE_U32"): - continue - else: - if 'value' in item: - has_explicit_values = True - value = int(item['value']) - else: - value += 1 - item_names_by_value[value] = as_enum_item_name(item_name) - enum_name_nim = as_nim_type_name(decl['name'], prefix) - l('type') - l(f" {enum_name_nim}* {{.size:sizeof(int32).}} = enum") - if has_explicit_values: - # Nim requires explicit enum values to be declared in ascending order - for value in sorted(item_names_by_value): - name = item_names_by_value[value] - l(f" {name} = {value},") - else: - for name in item_names_by_value.values(): - l(f" {name},") - l("") - -# returns C prototype compatible function args (with pointers) -def funcdecl_args_c(decl, prefix): - s = "" - func_name = decl['name'] - for param_decl in decl['params']: - if s != "": - s += ", " - arg_name = param_decl['name'] - arg_type = check_override(f'{func_name}.{arg_name}', default=param_decl['type']) - s += f"{as_camel_case(arg_name, prefix)}:{as_nim_type(arg_type, prefix)}" - return s - -# returns Nim function args (pass structs by value) -def funcdecl_args_nim(decl, prefix): - s = "" - func_name = decl['name'] - for param_decl in decl['params']: - if s != "": - s += ", " - arg_name = param_decl['name'] - arg_type = check_override(f'{func_name}.{arg_name}', default=param_decl['type']) - s += f"{as_camel_case(arg_name, prefix)}:{as_nim_type(arg_type, prefix, struct_ptr_as_value=True)}" - return s - -def funcdecl_result(decl, prefix): - func_name = decl['name'] - decl_type = decl['type'] - result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip()) - nim_res_type = as_nim_type(result_type, prefix) - if nim_res_type == "": - nim_res_type = "void" - return nim_res_type - -def gen_func_nim(decl, prefix): - c_func_name = decl['name'] - nim_func_name = as_camel_case(check_override(c_func_name), prefix, wrap=False) - nim_res_type = funcdecl_result(decl, prefix) - if c_func_name in c_callbacks: - l(f"proc {nim_func_name}*({funcdecl_args_c(decl, prefix)}):{nim_res_type} {{.cdecl, importc:\"{c_func_name}\".}}") - else: - l(f"proc c_{nim_func_name}({funcdecl_args_c(decl, prefix)}):{nim_res_type} {{.cdecl, importc:\"{c_func_name}\".}}") - l(f"proc {wrap_keywords(nim_func_name)}*({funcdecl_args_nim(decl, prefix)}):{nim_res_type} =") - s = f" c_{nim_func_name}(" - for i, param_decl in enumerate(decl['params']): - if i > 0: - s += ", " - arg_name = param_decl['name'] - arg_type = param_decl['type'] - if is_const_struct_ptr(arg_type): - s += f"addr({arg_name})" - else: - s += arg_name - s += ")" - l(s) - l("") - -def gen_array_converters(decl, prefix): - for field in decl['fields']: - if util.is_array_type(field['type']): - array_type = util.extract_array_type(field['type']) - array_sizes = util.extract_array_sizes(field['type']) - struct_name = as_nim_struct_name(decl, prefix) - field_name = as_nim_field_name(field, prefix, check_private=False) - array_base_type = as_nim_type(array_type, prefix) - if util.is_1d_array_type(field['type']): - n = array_sizes[0] - l(f'converter to{struct_name}{field_name}*[N:static[int]](items: array[N, {array_base_type}]): array[{n}, {array_base_type}] =') - l(f' static: assert(N <= {n})') - l(f' for index,item in items.pairs: result[index]=item') - l('') - elif util.is_2d_array_type(field['type']): - x = array_sizes[1] - y = array_sizes[0] - l(f'converter to{struct_name}{field_name}*[Y:static[int], X:static[int]](items: array[Y, array[X, {array_base_type}]]): array[{y}, array[{x}, {array_base_type}]] =') - l(f' static: assert(X <= {x})') - l(f' static: assert(Y <= {y})') - l(f' for indexY,itemY in items.pairs:') - l(f' for indexX, itemX in itemY.pairs:') - l(f' result[indexY][indexX] = itemX') - l('') - else: - sys.exit('Unsupported converter array dimension (> 2)!') - -def pre_parse(inp): - global struct_types - global enum_types - for decl in inp['decls']: - kind = decl['kind'] - if kind == 'struct': - struct_types.append(decl['name']) - elif kind == 'enum': - enum_name = decl['name'] - enum_types.append(enum_name) - -def gen_imports(inp, dep_prefixes): - for dep_prefix in dep_prefixes: - dep_module_name = module_names[dep_prefix] - l(f'import {dep_module_name}') - l('') - -def gen_extra(inp): - if inp['prefix'] in ['sg_']: - # FIXME: remove when sokol-shdc has been integrated! - l('when defined gl:') - l(' const gl* = true') - l(' const d3d11* = false') - l(' const metal* = false') - l('elif defined windows:') - l(' const gl* = false') - l(' const d3d11* = true') - l(' const metal* = false') - l('elif defined macosx:') - l(' const gl* = false') - l(' const d3d11* = false') - l(' const metal* = true') - l('elif defined linux:') - l(' const gl* = true') - l(' const d3d11* = false') - l(' const metal* = false') - l('else:') - l(' error("unsupported platform")') - l('') - if inp['prefix'] in ['sg_', 'sapp_']: - l('when defined windows:') - l(' when not defined vcc:') - l(' {.passl:"-lkernel32 -luser32 -lshell32 -lgdi32".}') - l(' when defined gl:') - l(' {.passc:"-DSOKOL_GLCORE33".}') - l(' else:') - l(' {.passc:"-DSOKOL_D3D11".}') - l(' when not defined vcc:') - l(' {.passl:"-ld3d11 -ldxgi".}') - l('elif defined macosx:') - l(' {.passc:"-x objective-c".}') - l(' {.passl:"-framework Cocoa -framework QuartzCore".}') - l(' when defined gl:') - l(' {.passc:"-DSOKOL_GLCORE33".}') - l(' {.passl:"-framework OpenGL".}') - l(' else:') - l(' {.passc:"-DSOKOL_METAL".}') - l(' {.passl:"-framework Metal -framework MetalKit".}') - l('elif defined linux:') - l(' {.passc:"-DSOKOL_GLCORE33".}') - l(' {.passl:"-lX11 -lXi -lXcursor -lGL -lm -ldl -lpthread".}') - l('else:') - l(' error("unsupported platform")') - l('') - if inp['prefix'] in ['saudio_']: - l('when defined windows:') - l(' when not defined vcc:') - l(' {.passl:"-lkernel32 -lole32".}') - l('elif defined macosx:') - l(' {.passl:"-framework AudioToolbox".}') - l('elif defined linux:') - l(' {.passl:"-lasound -lm -lpthread".}') - l('else:') - l(' error("unsupported platform")') - l('') - if inp['prefix'] in ['sg_']: - l('## Convert a 4-element tuple of numbers to a gfx.Color') - l('converter toColor*[R:SomeNumber,G:SomeNumber,B:SomeNumber,A:SomeNumber](rgba: tuple [r:R,g:G,b:B,a:A]):Color =') - l(' Color(r:rgba.r.float32, g:rgba.g.float32, b:rgba.b.float32, a:rgba.a.float32)') - l('') - l('## Convert a 3-element tuple of numbers to a gfx.Color') - l('converter toColor*[R:SomeNumber,G:SomeNumber,B:SomeNumber](rgba: tuple [r:R,g:G,b:B]):Color =') - l(' Color(r:rgba.r.float32, g:rgba.g.float32, b:rgba.b.float32, a:1.float32)') - l('') - # NOTE: this simplistic to_Range() converter has various issues, some of them dangerous: - # - doesn't work as expected for slice types - # - it's very easy to create a range that points to invalid memory - # (so far observed for stack-allocated structs <= 16 bytes) - #if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']: - # l('# helper function to convert "anything" into a Range') - # l('converter to_Range*[T](source: T): Range =') - # l(' Range(addr: source.addr, size: source.sizeof.uint)') - # l('') - c_source_path = '/'.join(c_source_paths[inp['prefix']].split('/')[3:]) - l('{.passc:"-DSOKOL_NIM_IMPL".}') - l('when defined(release):') - l(' {.passc:"-DNDEBUG".}') - l(f'{{.compile:"{c_source_path}".}}') - -def gen_module(inp, dep_prefixes): - l('## machine generated, do not edit') - l('') - gen_imports(inp, dep_prefixes) - pre_parse(inp) - prefix = inp['prefix'] - for decl in inp['decls']: - if not decl['is_dep']: - kind = decl['kind'] - if kind == 'consts': - gen_consts(decl, prefix) - elif not check_ignore(decl['name']): - if kind == 'struct': - gen_struct(decl, prefix) - gen_array_converters(decl, prefix) - elif kind == 'enum': - gen_enum(decl, prefix) - elif kind == 'func': - gen_func_nim(decl, prefix) - gen_extra(inp) - -def prepare(): - print('=== Generating Nim bindings:') - if not os.path.isdir('sokol-nim/src/sokol'): - os.makedirs('sokol-nim/src/sokol') - if not os.path.isdir('sokol-nim/src/sokol/c'): - os.makedirs('sokol-nim/src/sokol/c') - -def gen(c_header_path, c_prefix, dep_c_prefixes): - if not c_prefix in module_names: - print(f' >> warning: skipping generation for {c_prefix} prefix...') - return - global out_lines - module_name = module_names[c_prefix] - c_source_path = c_source_paths[c_prefix] - print(f' {c_header_path} => {module_name}') - reset_globals() - shutil.copyfile(c_header_path, f'sokol-nim/src/sokol/c/{os.path.basename(c_header_path)}') - ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes) - gen_module(ir, dep_c_prefixes) - output_path = f"sokol-nim/src/sokol/{ir['module']}.nim" - with open(output_path, 'w', newline='\n') as f_outp: - f_outp.write(out_lines) diff --git a/source/engine/thirdparty/sokol/bindgen/gen_odin.py b/source/engine/thirdparty/sokol/bindgen/gen_odin.py deleted file mode 100644 index 6ba84f3..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_odin.py +++ /dev/null @@ -1,500 +0,0 @@ -#------------------------------------------------------------------------------- -# gen_odin.py -# -# Generate Odin bindings. -#------------------------------------------------------------------------------- -import gen_ir -import gen_util as util -import os, shutil, sys - -bindings_root = 'sokol-odin' -c_root = f'{bindings_root}/c' -module_root = f'{bindings_root}/sokol' - -module_names = { - 'slog_': 'log', - 'sg_': 'gfx', - 'sapp_': 'app', - 'stm_': 'time', - 'saudio_': 'audio', - 'sgl_': 'gl', - 'sdtx_': 'debugtext', - 'sshape_': 'shape', - 'sglue_': 'glue', -} - -system_libs = { - 'sg_': { - 'windows': { - 'd3d11': "", - 'gl': "", - }, - 'macos': { - 'metal': '"system:Cocoa.framework","system:QuartzCore.framework","system:Metal.framework","system:MetalKit.framework"', - 'gl': '"system:Cocoa.framework","system:QuartzCore.framework","system:OpenGL.framework"' - }, - 'linux': { - 'gl': '"system:GL", "system:dl", "system:pthread"' - } - }, - 'sapp_': { - 'windows': { - 'd3d11': '', - 'gl': '', - }, - 'macos': { - 'metal': '"system:Cocoa.framework","system:QuartzCore.framework","system:Metal.framework","system:MetalKit.framework"', - 'gl': '"system:Cocoa.framework","system:QuartzCore.framework","system:OpenGL.framework"', - }, - 'linux': { - 'gl': '"system:X11", "system:Xi", "system:Xcursor", "system:GL", "system:dl", "system:pthread"' - } - }, - 'saudio_': { - 'windows': { - 'd3d11': '', - 'gl': '', - }, - 'macos': { - 'metal': '"system:AudioToolbox.framework"', - 'gl': '"system:AudioToolbox.framework"', - }, - 'linux': { - 'gl': '"system:asound", "system:dl", "system:pthread"', - } - } -} - -c_source_names = { - 'slog_': 'sokol_log.c', - 'sg_': 'sokol_gfx.c', - 'sapp_': 'sokol_app.c', - 'sapp_sg': 'sokol_glue.c', - 'stm_': 'sokol_time.c', - 'saudio_': 'sokol_audio.c', - 'sgl_': 'sokol_gl.c', - 'sdtx_': 'sokol_debugtext.c', - 'sshape_': 'sokol_shape.c', - 'sglue_': 'sokol_glue.c', -} - -ignores = [ - 'sdtx_printf', - 'sdtx_vprintf', - 'sg_install_trace_hooks', - 'sg_trace_hooks', -] - -# NOTE: syntax for function results: "func_name.RESULT" -overrides = { - 'context': 'ctx', # reserved keyword - 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR', -} - -prim_types = { - 'int': 'c.int', - 'bool': 'bool', - 'char': 'u8', - 'int8_t': 'i8', - 'uint8_t': 'u8', - 'int16_t': 'i16', - 'uint16_t': 'u16', - 'int32_t': 'i32', - 'uint32_t': 'u32', - 'int64_t': 'i64', - 'uint64_t': 'u64', - 'float': 'f32', - 'double': 'f64', - 'uintptr_t': 'u64', - 'intptr_t': 'i64', - 'size_t': 'u64' -} - -prim_defaults = { - 'int': '0', - 'bool': 'false', - 'int8_t': '0', - 'uint8_t': '0', - 'int16_t': '0', - 'uint16_t': '0', - 'int32_t': '0', - 'uint32_t': '0', - 'int64_t': '0', - 'uint64_t': '0', - 'float': '0.0', - 'double': '0.0', - 'uintptr_t': '0', - 'intptr_t': '0', - 'size_t': '0' -} - -struct_types = [] -enum_types = [] -enum_items = {} -out_lines = '' - -def reset_globals(): - global struct_types - global enum_types - global enum_items - global out_lines - struct_types = [] - enum_types = [] - enum_items = {} - out_lines = '' - -def l(s): - global out_lines - out_lines += s + '\n' - -def check_override(name, default=None): - if name in overrides: - return overrides[name] - elif default is None: - return name - else: - return default - -def check_ignore(name): - return name in ignores - -# PREFIX_BLA_BLUB to BLA_BLUB, prefix_bla_blub to bla_blub -def as_snake_case(s, prefix): - outp = s - if outp.lower().startswith(prefix): - outp = outp[len(prefix):] - return outp - -def get_odin_module_path(c_prefix): - return f'{module_root}/{module_names[c_prefix]}' - -def get_csource_path(c_prefix): - return f'{c_root}/{c_source_names[c_prefix]}' - -def make_odin_module_directory(c_prefix): - path = get_odin_module_path(c_prefix) - if not os.path.isdir(path): - os.makedirs(path) - -def as_prim_type(s): - return prim_types[s] - -# prefix_bla_blub(_t) => (dep.)Bla_Blub -def as_struct_or_enum_type(s, prefix): - parts = s.lower().split('_') - outp = '' if s.startswith(prefix) else f'{parts[0]}.' - for part in parts[1:]: - # ignore '_t' type postfix - if (part != 't'): - outp += part.capitalize() - outp += '_' - outp = outp[:-1] - return outp - -# PREFIX_ENUM_BLA_BLUB => BLA_BLUB, _PREFIX_ENUM_BLA_BLUB => BLA_BLUB -def as_enum_item_name(s): - outp = s.lstrip('_') - parts = outp.split('_')[2:] - outp = '_'.join(parts) - if outp[0].isdigit(): - outp = '_' + outp - return outp - -def enum_default_item(enum_name): - return enum_items[enum_name][0] - -def is_prim_type(s): - return s in prim_types - -def is_int_type(s): - return s == "int" - -def is_struct_type(s): - return s in struct_types - -def is_enum_type(s): - return s in enum_types - -def is_const_prim_ptr(s): - for prim_type in prim_types: - if s == f"const {prim_type} *": - return True - return False - -def is_prim_ptr(s): - for prim_type in prim_types: - if s == f"{prim_type} *": - return True - return False - -def is_const_struct_ptr(s): - for struct_type in struct_types: - if s == f"const {struct_type} *": - return True - return False - -def type_default_value(s): - return prim_defaults[s] - -def map_type(type, prefix, sub_type): - if sub_type not in ['c_arg', 'odin_arg', 'struct_field']: - sys.exit(f"Error: map_type(): unknown sub_type '{sub_type}") - if type == "void": - return "" - elif is_prim_type(type): - if sub_type == 'odin_arg': - # for Odin args, maps C int (32-bit) to Odin int (pointer-sized), - # and the C bool type to Odin's bool type - if type == 'int' or type == 'uint32_t': - return 'int' - elif type == 'bool': - return 'bool' - return as_prim_type(type) - elif is_struct_type(type): - return as_struct_or_enum_type(type, prefix) - elif is_enum_type(type): - return as_struct_or_enum_type(type, prefix) - elif util.is_void_ptr(type): - return "rawptr" - elif util.is_const_void_ptr(type): - return "rawptr" - elif util.is_string_ptr(type): - return "cstring" - elif is_const_struct_ptr(type): - # pass Odin struct args by value, not by pointer - if sub_type == 'odin_arg': - return f"{as_struct_or_enum_type(util.extract_ptr_type(type), prefix)}" - else: - return f"^{as_struct_or_enum_type(util.extract_ptr_type(type), prefix)}" - elif is_prim_ptr(type): - return f"^{as_prim_type(util.extract_ptr_type(type))}" - elif is_const_prim_ptr(type): - return f"^{as_prim_type(util.extract_ptr_type(type))}" - elif util.is_1d_array_type(type): - array_type = util.extract_array_type(type) - array_sizes = util.extract_array_sizes(type) - return f"[{array_sizes[0]}]{map_type(array_type, prefix, sub_type)}" - elif util.is_2d_array_type(type): - array_type = util.extract_array_type(type) - array_sizes = util.extract_array_sizes(type) - return f"[{array_sizes[0]}][{array_sizes[1]}]{map_type(array_type, prefix, sub_type)}" - elif util.is_func_ptr(type): - res_type = funcptr_result_c(type, prefix) - res_str = '' if res_type == '' else f' -> {res_type}' - return f'proc "c" ({funcptr_args_c(type, prefix)}){res_str}' - else: - sys.exit(f"Error map_type(): unknown type '{type}'") - -def funcdecl_args_c(decl, prefix): - s = '' - func_name = decl['name'] - for param_decl in decl['params']: - if s != '': - s += ', ' - param_name = param_decl['name'] - param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type']) - if is_const_struct_ptr(param_type): - s += f"#by_ptr {param_name}: {map_type(param_type, prefix, 'odin_arg')}" - elif is_int_type(param_type): - s += f"#any_int {param_name}: {map_type(param_type, prefix, 'c_arg')}" - else: - s += f"{param_name}: {map_type(param_type, prefix, 'c_arg')}" - return s - -def funcptr_args_c(field_type, prefix): - tokens = field_type[field_type.index('(*)')+4:-1].split(',') - s = '' - arg_index = 0 - for token in tokens: - arg_type = token.strip() - if s != '': - s += ', ' - c_arg = map_type(arg_type, prefix, 'c_arg') - if c_arg == '': - return '' - else: - s += f'a{arg_index}: {c_arg}' - arg_index += 1 - return s - -def funcptr_result_c(field_type, prefix): - res_type = field_type[:field_type.index('(*)')].strip() - return map_type(res_type, prefix, 'c_arg') - -def funcdecl_result_c(decl, prefix): - func_name = decl['name'] - decl_type = decl['type'] - res_c_type = decl_type[:decl_type.index('(')].strip() - return map_type(check_override(f'{func_name}.RESULT', default=res_c_type), prefix, 'c_arg') - -def get_system_libs(module, platform, backend): - if module in system_libs: - if platform in system_libs[module]: - if backend in system_libs[module][platform]: - libs = system_libs[module][platform][backend] - if libs != '': - return f", {libs}" - return '' - -def gen_c_imports(inp, c_prefix, prefix): - clib_prefix = f'sokol_{inp["module"]}' - clib_import = f'{clib_prefix}_clib' - windows_d3d11_libs = get_system_libs(prefix, 'windows', 'd3d11') - windows_gl_libs = get_system_libs(prefix, 'windows', 'gl') - macos_metal_libs = get_system_libs(prefix, 'macos', 'metal') - macos_gl_libs = get_system_libs(prefix, 'macos', 'gl') - linux_gl_libs = get_system_libs(prefix, 'linux', 'gl') - l( 'import "core:c"') - l( 'when ODIN_OS == .Windows {') - l( ' when #config(SOKOL_USE_GL,false) {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_gl_debug.lib"{windows_gl_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_gl_release.lib"{windows_gl_libs} }} }}') - l( ' } else {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_d3d11_debug.lib"{windows_d3d11_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_d3d11_release.lib"{windows_d3d11_libs} }} }}') - l( ' }') - l( '} else when ODIN_OS == .Darwin {') - l( ' when #config(SOKOL_USE_GL,false) {') - l( ' when ODIN_ARCH == .arm64 {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_gl_debug.a"{macos_gl_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_gl_release.a"{macos_gl_libs} }} }}') - l( ' } else {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_gl_debug.a"{macos_gl_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_gl_release.a"{macos_gl_libs} }} }}') - l( ' }') - l( ' } else {') - l( ' when ODIN_ARCH == .arm64 {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_metal_debug.a"{macos_metal_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_metal_release.a"{macos_metal_libs} }} }}') - l( ' } else {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_metal_debug.a"{macos_metal_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_metal_release.a"{macos_metal_libs} }} }}') - l( ' }') - l( ' }') - l( '}') - l( 'else {') - l(f' when ODIN_DEBUG == true {{ foreign import {clib_import} {{ "{clib_prefix}_linux_x64_gl_debug.a"{linux_gl_libs} }} }}') - l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_linux_x64_gl_release.a"{linux_gl_libs} }} }}') - l( '}') - - # Need to special case sapp_sg to avoid Odin's context keyword - if c_prefix == "sapp_sg": - l(f'@(default_calling_convention="c")') - else: - l(f'@(default_calling_convention="c", link_prefix="{c_prefix}")') - l(f"foreign {clib_import} {{") - prefix = inp['prefix'] - for decl in inp['decls']: - if decl['kind'] == 'func' and not decl['is_dep'] and not check_ignore(decl['name']): - args = funcdecl_args_c(decl, prefix) - res_type = funcdecl_result_c(decl, prefix) - res_str = '' if res_type == '' else f'-> {res_type}' - # Need to special case sapp_sg to avoid Odin's context keyword - if c_prefix == "sapp_sg": - l(f' @(link_name="{decl["name"]}")') - l(f" {check_override(as_snake_case(decl['name'], c_prefix))} :: proc({args}) {res_str} ---") - else: - l(f" {as_snake_case(decl['name'], c_prefix)} :: proc({args}) {res_str} ---") - l('}') - -def gen_consts(decl, prefix): - for item in decl['items']: - item_name = check_override(item['name']) - l(f"{as_snake_case(item_name, prefix)} :: {item['value']}") - -def gen_struct(decl, prefix): - c_struct_name = check_override(decl['name']) - struct_name = as_struct_or_enum_type(c_struct_name, prefix) - l(f'{struct_name} :: struct {{') - for field in decl['fields']: - field_name = check_override(field['name']) - field_type = map_type(check_override(f'{c_struct_name}.{field_name}', default=field['type']), prefix, 'struct_field') - # any field name starting with _ is considered private - if field_name.startswith('_'): - l(f' _ : {field_type},') - else: - l(f' {field_name} : {field_type},') - l('}') - -def gen_enum(decl, prefix): - enum_name = check_override(decl['name']) - l(f'{as_struct_or_enum_type(enum_name, prefix)} :: enum i32 {{') - for item in decl['items']: - item_name = as_enum_item_name(check_override(item['name'])) - if item_name != 'FORCE_U32': - if 'value' in item: - l(f" {item_name} = {item['value']},") - else: - l(f" {item_name},") - l('}') - -def gen_imports(dep_prefixes): - for dep_prefix in dep_prefixes: - dep_module_name = module_names[dep_prefix] - l(f'import {dep_prefix[:-1]} "../{dep_module_name}"') - l('') - -def gen_helpers(inp): - if inp['prefix'] == 'sdtx_': - l('import "core:fmt"') - l('import "core:strings"') - l('printf :: proc(s: string, args: ..any) {') - l(' fstr := fmt.tprintf(s, ..args)') - l(' putr(strings.unsafe_string_to_cstring(fstr), len(fstr))') - l('}') - -def gen_module(inp, c_prefix, dep_prefixes): - pre_parse(inp) - l('// machine generated, do not edit') - l('') - l(f"package sokol_{inp['module']}") - gen_imports(dep_prefixes) - gen_helpers(inp) - prefix = inp['prefix'] - gen_c_imports(inp, c_prefix, prefix) - for decl in inp['decls']: - if not decl['is_dep']: - kind = decl['kind'] - if kind == 'consts': - gen_consts(decl, prefix) - elif not check_ignore(decl['name']): - if kind == 'struct': - gen_struct(decl, prefix) - elif kind == 'enum': - gen_enum(decl, prefix) - -def pre_parse(inp): - global struct_types - global enum_types - for decl in inp['decls']: - kind = decl['kind'] - if kind == 'struct': - struct_types.append(decl['name']) - elif kind == 'enum': - enum_name = decl['name'] - enum_types.append(enum_name) - enum_items[enum_name] = [] - for item in decl['items']: - enum_items[enum_name].append(as_enum_item_name(item['name'])) - -def prepare(): - print('=== Generating Odin bindings:') - if not os.path.isdir(c_root): - os.makedirs(c_root) - if not os.path.isdir(module_root): - os.makedirs(module_root) - -def gen(c_header_path, c_prefix, dep_c_prefixes): - if not c_prefix in module_names: - print(f' >> warning: skipping generation for {c_prefix} prefix...') - return - reset_globals() - make_odin_module_directory(c_prefix) - print(f' {c_header_path} => {module_names[c_prefix]}') - shutil.copyfile(c_header_path, f'{c_root}/{os.path.basename(c_header_path)}') - csource_path = get_csource_path(c_prefix) - module_name = module_names[c_prefix] - ir = gen_ir.gen(c_header_path, csource_path, module_name, c_prefix, dep_c_prefixes) - gen_module(ir, c_prefix, dep_c_prefixes) - with open(f"{module_root}/{ir['module']}/{ir['module']}.odin", 'w', newline='\n') as f_outp: - f_outp.write(out_lines) diff --git a/source/engine/thirdparty/sokol/bindgen/gen_rust.py b/source/engine/thirdparty/sokol/bindgen/gen_rust.py deleted file mode 100644 index 0984d14..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_rust.py +++ /dev/null @@ -1,893 +0,0 @@ -# ------------------------------------------------------------------------------- -# Generate rust bindings. -# -# rust coding style: -# - types are PascalCase -# - otherwise snake_case -# ------------------------------------------------------------------------------- -import gen_ir -import os, shutil, sys - -import gen_util as util - -module_names = { - "slog_": "log", - "sg_": "gfx", - "sapp_": "app", - "stm_": "time", - "saudio_": "audio", - "sgl_": "gl", - "sdtx_": "debugtext", - "sshape_": "shape", - "simgui_": "imgui", - "sglue_": "glue", -} - -module_requires_rust_feature = { - module_names["simgui_"]: "imgui", -} - -c_source_paths = { - "slog_": "sokol-rust/src/sokol/c/sokol_log.c", - "sg_": "sokol-rust/src/sokol/c/sokol_gfx.c", - "sapp_": "sokol-rust/src/sokol/c/sokol_app.c", - "stm_": "sokol-rust/src/sokol/c/sokol_time.c", - "saudio_": "sokol-rust/src/sokol/c/sokol_audio.c", - "sgl_": "sokol-rust/src/sokol/c/sokol_gl.c", - "sdtx_": "sokol-rust/src/sokol/c/sokol_debugtext.c", - "sshape_": "sokol-rust/src/sokol/c/sokol_shape.c", - "simgui_": "sokol-rust/src/sokol/c/sokol_imgui.c", - "sglue_": "sokol-rust/src/sokol/c/sokol_glue.c", -} - -ignores = [ - "sdtx_printf", - "sdtx_vprintf", - "simgui_add_key_event", - # "sg_install_trace_hooks", - # "sg_trace_hooks", -] - -range_struct_name = "Range" - -# functions that need to be exposed as 'raw' C callbacks without a rust wrapper function -c_callbacks = ["slog_func"] - -# NOTE: syntax for function results: "func_name.RESULT" -overrides = { - "type": "_type", - "ref": "_ref", - - "sg_apply_uniforms.ub_index": "uintptr_t", - "sg_draw.base_element": "uintptr_t", - "sg_draw.num_elements": "uintptr_t", - "sg_draw.num_instances": "uintptr_t", - "sshape_element_range_t.base_element": "uintptr_t", - "sshape_element_range_t.num_elements": "uintptr_t", - "sdtx_font.font_index": "uintptr_t", - - "sdtx_move": "sdtx_move_cursor", - "sdtx_move_x": "sdtx_move_cursor_x", - "sdtx_move_y": "sdtx_move_cursor_y", - - "sg_image_type::SG_IMAGETYPE_2D": "SG_IMAGEYPE_DIM2", - "sg_image_type::SG_IMAGETYPE_3D": "SG_IMAGETYPE_DIM3", - - "sapp_keycode::SAPP_KEYCODE_0": "SAPP_KEYCODE_NUM0", - "sapp_keycode::SAPP_KEYCODE_1": "SAPP_KEYCODE_NUM1", - "sapp_keycode::SAPP_KEYCODE_2": "SAPP_KEYCODE_NUM2", - "sapp_keycode::SAPP_KEYCODE_3": "SAPP_KEYCODE_NUM3", - "sapp_keycode::SAPP_KEYCODE_4": "SAPP_KEYCODE_NUM4", - "sapp_keycode::SAPP_KEYCODE_5": "SAPP_KEYCODE_NUM5", - "sapp_keycode::SAPP_KEYCODE_6": "SAPP_KEYCODE_NUM6", - "sapp_keycode::SAPP_KEYCODE_7": "SAPP_KEYCODE_NUM7", - "sapp_keycode::SAPP_KEYCODE_8": "SAPP_KEYCODE_NUM8", - "sapp_keycode::SAPP_KEYCODE_9": "SAPP_KEYCODE_NUM9", - - # "sgl_error": "sgl_get_error", # 'error' is reserved in zig - # "sgl_deg": "sgl_as_degrees", - # "sgl_rad": "sgl_as_radians", - # "sg_context_desc.color_format": "int", - # "SGL_NO_ERROR": "SGL_ERROR_NO_ERROR", - # "sg_context_desc.depth_format": "int", -} - -prim_types = { - "int": "i32", - "bool": "bool", - "char": "core::ffi::c_char", - "int8_t": "i8", - "uint8_t": "u8", - "int16_t": "i16", - "uint16_t": "u16", - "int32_t": "i32", - "uint32_t": "u32", - "int64_t": "i64", - "uint64_t": "u64", - "float": "f32", - "double": "f64", - "uintptr_t": "usize", - "intptr_t": "isize", - "size_t": "usize", -} - -prim_defaults = { - "int": "0", - "bool": "false", - "int8_t": "0", - "uint8_t": "0", - "int16_t": "0", - "uint16_t": "0", - "int32_t": "0", - "uint32_t": "0", - "int64_t": "0", - "uint64_t": "0", - "float": "0.0", - "double": "0.0", - "uintptr_t": "0", - "intptr_t": "0", - "size_t": "0", - "char": "0", -} - -special_constant_types = { - "SG_INVALID_ID": "u32", - "SAPP_MODIFIER_SHIFT": "u32", - "SAPP_MODIFIER_CTRL": "u32", - "SAPP_MODIFIER_ALT": "u32", - "SAPP_MODIFIER_SUPER": "u32", - "SAPP_MODIFIER_LMB": "u32", - "SAPP_MODIFIER_RMB": "u32", - "SAPP_MODIFIER_MMB": "u32", -} - -struct_types = [] -enum_types = [] -enum_items = {} -out_lines = "" - - -def reset_globals(): - global struct_types - global enum_types - global enum_items - global out_lines - struct_types = [] - enum_types = [] - enum_items = {} - out_lines = "" - - -def l(s): - global out_lines - out_lines += s + "\n" - - -def as_rust_prim_type(s): - return prim_types[s] - - -def as_upper_snake_case(s, prefix): - outp = s.lower() - if outp.startswith(prefix): - outp = outp[len(prefix):] - return outp.upper() - - -# prefix_bla_blub(_t) => (dep::)BlaBlub -def as_rust_struct_type(s, prefix): - parts = s.lower().split("_") - outp = "" if s.startswith(prefix) else f"{parts[0]}::" - for part in parts[1:]: - # ignore '_t' type postfix - if part != "t": - outp += part.capitalize() - return outp - - -# prefix_bla_blub(_t) => (dep::)BlaBlub -def as_rust_enum_type(s, prefix): - parts = s.lower().split("_") - outp = "" if s.startswith(prefix) else f"{parts[0]}::" - for part in parts[1:]: - # ignore '_t' type postfix - if part != "t": - outp += part.capitalize() - return outp - - -def check_override(name, default=None): - if name in overrides: - return overrides[name] - elif default is None: - return name - else: - return default - - -def check_ignore(name): - return name in ignores - - -# PREFIX_ENUM_BLA_BLA => BlaBla, _PREFIX_ENUM_BLA_BLA => BlaBla -def as_enum_item_name(s): - parts = s.lstrip("_").split("_") - outp = "" - for i, part in enumerate(parts[2:]): - # TODO: What to do with enum fields starting with numbers? - outp += part.capitalize() - - return outp - - -def enum_default_item(enum_name): - return enum_items[enum_name][0] - - -def is_prim_type(s): - return s in prim_types - - -def is_struct_type(s): - return s in struct_types - - -def is_enum_type(s): - return s in enum_types - - -def is_const_prim_ptr(s): - for prim_type in prim_types: - if s == f"const {prim_type} *": - return True - return False - - -def is_prim_ptr(s): - for prim_type in prim_types: - if s == f"{prim_type} *": - return True - return False - - -def is_const_struct_ptr(s): - for struct_type in struct_types: - if s == f"const {struct_type} *": - return True - return False - - -def is_struct_ptr(s): - for struct_type in struct_types: - if s == f"{struct_type} *": - return True - return False - - -def type_default_value(s): - return prim_defaults[s] - - -def as_c_arg_type(arg_prefix, arg_type, prefix): - # NOTE: if arg_prefix is None, the result is used as return value - pre = "" if arg_prefix is None else arg_prefix - - if arg_type == "void": - return "" - elif is_prim_type(arg_type): - return pre + as_rust_prim_type(arg_type) - elif is_struct_type(arg_type): - return pre + as_rust_struct_type(arg_type, prefix) - elif is_enum_type(arg_type): - return pre + as_rust_enum_type(arg_type, prefix) - elif util.is_void_ptr(arg_type): - return pre + "*mut core::ffi::c_void" - elif util.is_const_void_ptr(arg_type): - return pre + "*const core::ffi::c_void" - elif util.is_string_ptr(arg_type): - return pre + "*const core::ffi::c_char" - elif is_const_struct_ptr(arg_type): - return pre + f"*const {as_rust_struct_type(util.extract_ptr_type(arg_type), prefix)}" - elif is_struct_ptr(arg_type): - return pre + f"*mut {as_rust_struct_type(util.extract_ptr_type(arg_type), prefix)}" - elif is_prim_ptr(arg_type): - return pre + f"*mut {as_rust_prim_type(util.extract_ptr_type(arg_type))}" - elif is_const_prim_ptr(arg_type): - return pre + f"*const {as_rust_prim_type(util.extract_ptr_type(arg_type))}" - else: - sys.exit(f"ERROR as_c_arg_type(): {arg_type}") - - -def as_rust_arg_type(arg_prefix, arg_type, prefix): - # NOTE: if arg_prefix is None, the result is used as return value - pre = "" if arg_prefix is None else arg_prefix - - if arg_type == "void": - return "" - elif is_prim_type(arg_type): - return pre + as_rust_prim_type(arg_type) - elif is_struct_type(arg_type): - return pre + as_rust_struct_type(arg_type, prefix) - elif is_enum_type(arg_type): - return pre + as_rust_enum_type(arg_type, prefix) - elif util.is_void_ptr(arg_type): - return pre + "*mut core::ffi::c_void" - elif util.is_const_void_ptr(arg_type): - return pre + "*const core::ffi::c_void" - elif util.is_string_ptr(arg_type): - return pre + "&str" - elif is_const_struct_ptr(arg_type): - return pre + f"&{as_rust_struct_type(util.extract_ptr_type(arg_type), prefix)}" - elif is_struct_ptr(arg_type): - return pre + f"&mut {as_rust_struct_type(util.extract_ptr_type(arg_type), prefix)}" - elif is_prim_ptr(arg_type): - return pre + f"&mut {as_rust_prim_type(util.extract_ptr_type(arg_type))}" - elif is_const_prim_ptr(arg_type): - return pre + f"&{as_rust_prim_type(util.extract_ptr_type(arg_type))}" - else: - sys.exit(f"ERROR as_rust_arg_type(): {arg_type}") - - -def is_rust_string(rust_type): - return rust_type == "&str" or rust_type == " -> &'static str" - - -# get C-style arguments of a function pointer as string -def funcptr_args_c(field_type, prefix): - tokens = field_type[field_type.index("(*)") + 4: -1].split(",") - s = "" - for token in tokens: - arg_type = token.strip() - if s != "": - s += ", " - c_arg = as_c_arg_type(None, arg_type, prefix) - if c_arg == "void": - return "" - else: - s += c_arg - return s - - -# get C-style result of a function pointer as string -def funcptr_result_c(field_type): - res_type = field_type[: field_type.index("(*)")].strip() - if res_type == "void": - return "" - elif is_prim_type(res_type): - return f" -> {as_rust_prim_type(res_type)}" - elif util.is_const_void_ptr(res_type): - return " -> *const core::ffi::c_void" - elif util.is_void_ptr(res_type): - return " -> *mut core::ffi::c_void" - else: - sys.exit(f"ERROR funcptr_result_c(): {field_type}") - - -def funcdecl_args_c(decl, prefix): - s = "" - func_name = decl["name"] - for param_decl in decl["params"]: - if s != "": - s += ", " - param_name = param_decl["name"] - param_type = check_override( - f"{func_name}.{param_name}", default=param_decl["type"] - ) - s += f"{as_c_arg_type(f'{param_name}: ', param_type, prefix)}" - return s - - -def funcdecl_args_rust(decl, prefix): - s = "" - func_name = decl["name"] - for param_decl in decl["params"]: - if s != "": - s += ", " - param_name = param_decl["name"] - param_type = check_override( - f"{func_name}.{param_name}", default=param_decl["type"] - ) - s += f"{as_rust_arg_type(f'{param_name}: ', param_type, prefix)}" - return s - - -def funcdecl_result_c(decl, prefix): - func_name = decl["name"] - decl_type = decl["type"] - result_type = check_override( - f"{func_name}.RESULT", default=decl_type[: decl_type.index("(")].strip() - ) - - it = as_c_arg_type(None, result_type, prefix) - if it == "()" or it == "": - return "" - else: - return f" -> {it}" - - -def funcdecl_result_rust(decl, prefix): - func_name = decl["name"] - decl_type = decl["type"] - result_type = check_override( - f"{func_name}.RESULT", default=decl_type[: decl_type.index("(")].strip() - ) - rust_res_type = as_rust_arg_type(None, result_type, prefix) - - if is_rust_string(rust_res_type): - rust_res_type = "&'static str" - - if rust_res_type == "": - return "" - else: - return f" -> {rust_res_type }" - - -def gen_struct(decl, prefix): - struct_name = check_override(decl["name"]) - rust_type = as_rust_struct_type(struct_name, prefix) - rust_struct_type = rust_type - - struct_lines = [] - default_lines = [] - - for field in decl["fields"]: - field_name = check_override(field["name"]) - field_type = check_override( - f"{struct_name}.{field_name}", default=field["type"] - ) - - if is_prim_type(field_type): - struct_lines.append( - f"pub {field_name}: {as_rust_prim_type(field_type)}" - ) - default_lines.append( - f"{field_name}: {type_default_value(field_type)}" - ) - elif is_struct_type(field_type): - struct_lines.append( - f"pub {field_name}: {as_rust_struct_type(field_type, prefix)}" - ) - default_lines.append( - f"{field_name}: {as_rust_struct_type(field_type, prefix)}::new()" - ) - elif is_enum_type(field_type): - struct_lines.append( - f"pub {field_name}: {as_rust_enum_type(field_type, prefix)}" - ) - default_lines.append( - f"{field_name}: {as_rust_enum_type(field_type, prefix)}::new()" - ) - elif util.is_string_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *const core::ffi::c_char" - ) - default_lines.append( - f"{field_name}: core::ptr::null()" - ) - elif util.is_const_void_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *const core::ffi::c_void" - ) - default_lines.append( - f"{field_name}: core::ptr::null()" - ) - elif util.is_void_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *mut core::ffi::c_void" - ) - default_lines.append( - f"{field_name}: core::ptr::null_mut()" - ) - elif is_const_prim_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *const {as_rust_prim_type(util.extract_ptr_type(field_type))}" - ) - default_lines.append( - f"{field_name}: core::ptr::null()" - ) - elif is_prim_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *mut {as_rust_prim_type(util.extract_ptr_type(field_type))}" - ) - default_lines.append( - f"{field_name}: core::ptr::null_mut()" - ) - elif is_const_struct_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *const {as_rust_struct_type(util.extract_ptr_type(field_type), prefix)}" - ) - default_lines.append( - f"{field_name}: core::ptr::null()" - ) - elif is_struct_ptr(field_type): - struct_lines.append( - f"pub {field_name}: *mut {as_rust_struct_type(util.extract_ptr_type(field_type), prefix)}" - ) - default_lines.append( - f"{field_name}: core::ptr::null_mut()" - ) - elif util.is_func_ptr(field_type): - struct_lines.append( - f"pub {field_name}: Option" - ) - default_lines.append( - f"{field_name}: None" - ) - elif util.is_1d_array_type(field_type): - array_type = util.extract_array_type(field_type) - array_sizes = util.extract_array_sizes(field_type) - if is_prim_type(array_type) or is_struct_type(array_type): - if is_prim_type(array_type): - rust_type = as_rust_prim_type(array_type) - def_val = type_default_value(array_type) - elif is_struct_type(array_type) or is_enum_type(array_type): - rust_type = as_rust_struct_type(array_type, prefix) - def_val = f"{rust_type}::new()" - else: - sys.exit(f"ERROR gen_struct is_1d_array_type: {array_type}") - t0 = f"[{rust_type}; {array_sizes[0]}]" - # t1 = f"&{rust_type}" - struct_lines.append( - f"pub {field_name}: {t0}" - ) - default_lines.append( - f"{field_name}: [{def_val}; {array_sizes[0]}]" - ) - elif util.is_const_void_ptr(array_type): - struct_lines.append( - f"pub {field_name}: [*const core::ffi::c_void; {array_sizes[0]}]" - ) - default_lines.append( - f"{field_name}: [core::ptr::null(); {array_sizes[0]}]" - ) - else: - sys.exit( - f"ERROR gen_struct: array {field_name}: {field_type} => [{array_type}: {array_sizes[0]}]" - ) - elif util.is_2d_array_type(field_type): - array_type = util.extract_array_type(field_type) - array_sizes = util.extract_array_sizes(field_type) - - if is_prim_type(array_type): - rust_type = as_rust_prim_type(array_type) - def_val = type_default_value(array_type) - elif is_struct_type(array_type): - rust_type = as_rust_struct_type(array_type, prefix) - def_val = f"{rust_type}::new()" - else: - sys.exit(f"ERROR gen_struct is_2d_array_type: {array_type}") - - struct_lines.append( - f"pub {field_name}: [[{rust_type}; {array_sizes[1]}]; {array_sizes[0]}]" - ) - default_lines.append( - f"{field_name}: [[{def_val}; {array_sizes[1]}]; {array_sizes[0]}]" - ) - else: - sys.exit(f"ERROR gen_struct: {field_name}: {field_type};") - - # - # TODO: Is this the best way to have zero-initialization with support for constants? - # core::mem::zeroed() cleaner? - # - - l("#[repr(C)]") - l("#[derive(Copy, Clone, Debug)]") - l(f"pub struct {rust_struct_type} {{") - for line in struct_lines: - l(f" {line},") - l("}") - - l(f"impl {rust_struct_type} {{") - l(" pub const fn new() -> Self {") - l(" Self {") - for line in default_lines: - l(f" {line},") - l(" }") - l(" }") - l("}") - - l(f"impl Default for {rust_struct_type} {{") - l(" fn default() -> Self {") - l(" Self::new()") - l(" }") - l("}") - - -def gen_consts(decl, prefix): - for item in decl["items"]: - # - # TODO: What type should these constants have? Currently giving all `usize` - # unless specifically overridden by `special_constant_types` - # - - item_name = check_override(item["name"]) - if item_name in special_constant_types: - special_type = special_constant_types[item_name] - l(f"pub const {as_upper_snake_case(item_name, prefix)}: {special_type} = {item['value']};") - else: - l(f"pub const {as_upper_snake_case(item_name, prefix)}: usize = {item['value']};") - - -def gen_enum(decl, prefix): - enum_name = check_override(decl["name"]) - - names = [ - as_enum_item_name(check_override(f"{decl['name']}::{item['name']}", item['name'])) for item in decl["items"] - ] - - is_u32 = False - for name in names: - if name == "ForceU32": - is_u32 = True - break - - l("#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]") - if is_u32: - l("#[repr(u32)]") - else: - l("#[repr(i32)]") - - rust_enum_name = as_rust_enum_type(enum_name, prefix) - - l(f"pub enum {rust_enum_name} {{") - for item_name, item in zip(names, decl["items"]): - if item_name != "ForceU32": - if "value" in item: - l(f" {item_name} = {item['value']},") - else: - l(f" {item_name},") - l("}") - - default_item = enum_default_item(enum_name) - l(f"impl {rust_enum_name} {{") - l(" pub const fn new() -> Self {") - l(f" Self::{default_item}") - l(" }") - l("}") - - l(f"impl Default for {rust_enum_name} {{") - l(" fn default() -> Self {") - l(f" Self::{default_item}") - l(" }") - l("}") - - -def gen_func_c(decl, prefix): - l("pub extern \"C\" {") - l(f" fn {decl['name']}({funcdecl_args_c(decl, prefix)}){funcdecl_result_c(decl, prefix)};") - l("}") - - -def gen_c_funcs(funcs): - l("pub mod ffi {") - l(" #![allow(unused_imports)]") - l(" use super::*;") - l(" extern \"C\" {") - for decl, prefix in funcs: - l(f" pub fn {decl['name']}({funcdecl_args_c(decl, prefix)}){funcdecl_result_c(decl, prefix)};") - l(" }") - l("}") - - -def gen_rust_funcs(funcs): - for decl, prefix in funcs: - gen_func_rust(decl, prefix) - - -def gen_func_rust(decl, prefix): - c_func_name = decl["name"] - rust_func_name = util.as_lower_snake_case(check_override(decl["name"]), prefix) - rust_res_type = funcdecl_result_rust(decl, prefix) - - if c_func_name in c_callbacks: - c_res_type = funcdecl_result_c(decl, prefix) - l("#[inline]") - l(f'pub extern "C" fn {c_func_name}({funcdecl_args_c(decl, prefix)}){c_res_type} {{') - l(" unsafe {") - s = f" ffi::{c_func_name}(" - for i, param_decl in enumerate(decl["params"]): - if i > 0: - s += ", " - arg_name = param_decl["name"] - s += arg_name - s += ")" - l(s) - l(" }") - l("}") - else: - l("#[inline]") - l(f"pub fn {rust_func_name}({funcdecl_args_rust(decl, prefix)}){rust_res_type} {{") - for i, param_decl in enumerate(decl["params"]): - arg_name = param_decl["name"] - arg_type = param_decl["type"] - if util.is_string_ptr(arg_type): - l(f" let tmp_{i} = std::ffi::CString::new({arg_name}).unwrap();") - - l(" unsafe {") - if is_rust_string(rust_res_type): - # special case: convert C string to rust string slice - s = f" c_char_ptr_to_rust_str(ffi::{c_func_name}(" - else: - s = f" ffi::{c_func_name}(" - - for i, param_decl in enumerate(decl["params"]): - if i > 0: - s += ", " - arg_name = param_decl["name"] - arg_type = param_decl["type"] - - if util.is_string_ptr(arg_type): - s += f"tmp_{i}.as_ptr()" - else: - s += arg_name - - if is_rust_string(rust_res_type): - s += ")" - s += ")" - l(s) - l(" }") - l("}") - - -def pre_parse(inp): - global struct_types - global enum_types - for decl in inp["decls"]: - kind = decl["kind"] - if kind == "struct": - struct_types.append(decl["name"]) - elif kind == "enum": - enum_name = decl["name"] - enum_types.append(enum_name) - enum_items[enum_name] = [] - for item in decl["items"]: - enum_items[enum_name].append(as_enum_item_name(item["name"])) - -def gen_imports(inp, dep_prefixes): - for dep_prefix in dep_prefixes: - dep_module_name = module_names[dep_prefix] - # l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.rs");') - l(f'use crate::{dep_module_name} as {dep_prefix[:-1]};') - l("") - - -def gen_helpers(inp): - l("/// Helper function to convert a C string to a rust string slice") - l("#[inline]") - l("fn c_char_ptr_to_rust_str(c_char_ptr: *const core::ffi::c_char) -> &'static str {") - l(" let c_str = unsafe { core::ffi::CStr::from_ptr(c_char_ptr) };") - l(" c_str.to_str().expect(\"c_char_ptr contained invalid Utf8 Data\")") - l("}") - l("") - - if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_', 'sapp_']: - l("/// Helper function to cast a rust slice into a sokol Range") - l(f"pub fn slice_as_range(data: &[T]) -> {range_struct_name} {{") - l(f" {range_struct_name} {{ size: std::mem::size_of_val(data), ptr: data.as_ptr() as *const _ }}") - l("}") - l("/// Helper function to cast a rust reference into a sokol Range") - l(f"pub fn value_as_range(value: &T) -> {range_struct_name} {{") - l(f" {range_struct_name} {{ size: std::mem::size_of::(), ptr: value as *const T as *const _ }}") - l("}") - l("") - l(f"impl From<&[T]> for {range_struct_name} {{") - l(" #[inline]") - l(" fn from(data: &[T]) -> Self {") - l(" slice_as_range(data)") - l(" }") - l("}") - l(f"impl From<&T> for {range_struct_name} {{") - l(" #[inline]") - l(" fn from(value: &T) -> Self {") - l(" value_as_range(value)") - l(" }") - l("}") - l("") - - # if inp["prefix"] == "sdtx_": - # l("/// std.fmt compatible Writer") - # l("pub const Writer = struct {") - # l(" pub const Error = error { };") - # l(" pub fn writeAll(self: Writer, bytes: []const u8) Error!void {") - # l(" _ = self;") - # l(" for (bytes) |byte| {") - # l(" putc(byte);") - # l(" }") - # l(" }") - # l(" pub fn writeByteNTimes(self: Writer, byte: u8, n: u64) Error!void {") - # l(" _ = self;") - # l(" var i: u64 = 0;") - # l(" while (i < n): (i += 1) {") - # l(" putc(byte);") - # l(" }") - # l(" }") - # l("};") - # l("// std.fmt-style formatted print") - # l("pub fn print(comptime fmt: anytype, args: anytype) void {") - # l(" var writer: Writer = .{};") - # l(' @import("std").fmt.format(writer, fmt, args) catch {};') - # l("}") - # l("") - - -def gen_module(inp, dep_prefixes): - module = inp['module'] - if module in module_requires_rust_feature: - feature = module_requires_rust_feature[module] - l(f"//! To use this module, enable the feature \"{feature}\"") - - l("// machine generated, do not edit") - l("") - - - l("#![allow(dead_code)]") - l("#![allow(unused_imports)]") - l("") - gen_imports(inp, dep_prefixes) - gen_helpers(inp) - pre_parse(inp) - prefix = inp["prefix"] - - funcs = [] - - for decl in inp["decls"]: - # - # HACK: gen_ir.py accidentally marks all sg_imgui_ declarations as is_dep since sg_imgui - # depends on sg_a but also starts with sg_... Fix gen_ir.py to remove this hack - # - dep_hack = False - if module == "gfx_imgui": - dep_hack = "name" in decl and decl["name"].startswith("sg_imgui_") - - if not decl["is_dep"] or dep_hack: - kind = decl["kind"] - if kind == "consts": - gen_consts(decl, prefix) - elif not check_ignore(decl["name"]): - if kind == "struct": - gen_struct(decl, prefix) - elif kind == "enum": - gen_enum(decl, prefix) - elif kind == "func": - funcs.append((decl, prefix)) - - gen_c_funcs(funcs) - gen_rust_funcs(funcs) - - -def prepare(): - print("=== Generating Rust bindings:") - if not os.path.isdir("sokol-rust/src/sokol"): - os.makedirs("sokol-rust/src/sokol") - if not os.path.isdir("sokol-rust/src/sokol/c"): - os.makedirs("sokol-rust/src/sokol/c") - - with open("sokol-rust/src/lib.rs", "w", newline="\n") as f_outp: - f_outp.write("//! Automatically generated sokol bindings for Rust\n\n") - - -def gen(c_header_path, c_prefix, dep_c_prefixes): - if c_prefix not in module_names: - print(f' >> warning: skipping generation for {c_prefix} prefix...') - return - - module_name = module_names[c_prefix] - c_source_path = c_source_paths[c_prefix] - print(f' {c_header_path} => {module_name}') - reset_globals() - c_path_in_project = f'sokol-rust/src/sokol/c/{os.path.basename(c_header_path)}' - shutil.copyfile(c_header_path, c_path_in_project) - ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes) - gen_module(ir, dep_c_prefixes) - output_path = f"sokol-rust/src/{ir['module']}.rs" - with open(output_path, 'w', newline='\n') as f_outp: - f_outp.write(out_lines) - - with open("sokol-rust/src/lib.rs", "a", newline="\n") as f_outp: - module = ir['module'] - if module in module_requires_rust_feature: - feature = module_requires_rust_feature[module] - f_outp.write(f"/// Enable feature \"{feature}\" to use\n") - f_outp.write(f"#[cfg(feature=\"{feature}\")]\n") - f_outp.write(f"pub mod {module};\n") diff --git a/source/engine/thirdparty/sokol/bindgen/gen_util.py b/source/engine/thirdparty/sokol/bindgen/gen_util.py deleted file mode 100644 index a76f4b2..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_util.py +++ /dev/null @@ -1,57 +0,0 @@ -# common utility functions for all bindings generators -import re - -re_1d_array = re.compile("^(?:const )?\w*\s*\*?\[\d*\]$") -re_2d_array = re.compile("^(?:const )?\w*\s*\*?\[\d*\]\[\d*\]$") - -def is_1d_array_type(s): - return re_1d_array.match(s) is not None - -def is_2d_array_type(s): - return re_2d_array.match(s) is not None - -def is_array_type(s): - return is_1d_array_type(s) or is_2d_array_type(s) - -def extract_array_type(s): - return s[:s.index('[')].strip() - -def extract_array_sizes(s): - return s[s.index('['):].replace('[', ' ').replace(']', ' ').split() - -def is_string_ptr(s): - return s == "const char *" - -def is_const_void_ptr(s): - return s == "const void *" - -def is_void_ptr(s): - return s == "void *" - -def is_func_ptr(s): - return '(*)' in s - -def extract_ptr_type(s): - tokens = s.split() - if tokens[0] == 'const': - return tokens[1] - else: - return tokens[0] - -# PREFIX_BLA_BLUB to bla_blub -def as_lower_snake_case(s, prefix): - outp = s.lower() - if outp.startswith(prefix): - outp = outp[len(prefix):] - return outp - -# prefix_bla_blub => blaBlub, PREFIX_BLA_BLUB => blaBlub -def as_lower_camel_case(s, prefix): - outp = s.lower() - if outp.startswith(prefix): - outp = outp[len(prefix):] - parts = outp.split('_') - outp = parts[0] - for part in parts[1:]: - outp += part.capitalize() - return outp diff --git a/source/engine/thirdparty/sokol/bindgen/gen_zig.py b/source/engine/thirdparty/sokol/bindgen/gen_zig.py deleted file mode 100644 index bf7db05..0000000 --- a/source/engine/thirdparty/sokol/bindgen/gen_zig.py +++ /dev/null @@ -1,552 +0,0 @@ -#------------------------------------------------------------------------------- -# Generate Zig bindings. -# -# Zig coding style: -# - types are PascalCase -# - functions are camelCase -# - otherwise snake_case -#------------------------------------------------------------------------------- -import gen_ir -import os, shutil, sys - -import gen_util as util - -module_names = { - 'slog_': 'log', - 'sg_': 'gfx', - 'sapp_': 'app', - 'stm_': 'time', - 'saudio_': 'audio', - 'sgl_': 'gl', - 'sdtx_': 'debugtext', - 'sshape_': 'shape', - 'sglue_': 'glue', -} - -c_source_paths = { - 'slog_': 'sokol-zig/src/sokol/c/sokol_log.c', - 'sg_': 'sokol-zig/src/sokol/c/sokol_gfx.c', - 'sapp_': 'sokol-zig/src/sokol/c/sokol_app.c', - 'stm_': 'sokol-zig/src/sokol/c/sokol_time.c', - 'saudio_': 'sokol-zig/src/sokol/c/sokol_audio.c', - 'sgl_': 'sokol-zig/src/sokol/c/sokol_gl.c', - 'sdtx_': 'sokol-zig/src/sokol/c/sokol_debugtext.c', - 'sshape_': 'sokol-zig/src/sokol/c/sokol_shape.c', - 'sglue_': 'sokol-zig/src/sokol/c/sokol_glue.c', -} - -ignores = [ - 'sdtx_printf', - 'sdtx_vprintf', - 'sg_install_trace_hooks', - 'sg_trace_hooks', -] - -# functions that need to be exposed as 'raw' C callbacks without a Zig wrapper function -c_callbacks = [ - 'slog_func' -] - -# NOTE: syntax for function results: "func_name.RESULT" -overrides = { - 'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig - 'sgl_deg': 'sgl_as_degrees', - 'sgl_rad': 'sgl_as_radians', - 'sg_apply_uniforms.ub_index': 'uint32_t', - 'sg_draw.base_element': 'uint32_t', - 'sg_draw.num_elements': 'uint32_t', - 'sg_draw.num_instances': 'uint32_t', - 'sshape_element_range_t.base_element': 'uint32_t', - 'sshape_element_range_t.num_elements': 'uint32_t', - 'sdtx_font.font_index': 'uint32_t', - 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR', -} - -prim_types = { - 'int': 'i32', - 'bool': 'bool', - 'char': 'u8', - 'int8_t': 'i8', - 'uint8_t': 'u8', - 'int16_t': 'i16', - 'uint16_t': 'u16', - 'int32_t': 'i32', - 'uint32_t': 'u32', - 'int64_t': 'i64', - 'uint64_t': 'u64', - 'float': 'f32', - 'double': 'f64', - 'uintptr_t': 'usize', - 'intptr_t': 'isize', - 'size_t': 'usize' -} - -prim_defaults = { - 'int': '0', - 'bool': 'false', - 'int8_t': '0', - 'uint8_t': '0', - 'int16_t': '0', - 'uint16_t': '0', - 'int32_t': '0', - 'uint32_t': '0', - 'int64_t': '0', - 'uint64_t': '0', - 'float': '0.0', - 'double': '0.0', - 'uintptr_t': '0', - 'intptr_t': '0', - 'size_t': '0' -} - - -struct_types = [] -enum_types = [] -enum_items = {} -out_lines = '' - -def reset_globals(): - global struct_types - global enum_types - global enum_items - global out_lines - struct_types = [] - enum_types = [] - enum_items = {} - out_lines = '' - -def l(s): - global out_lines - out_lines += s + '\n' - -def as_zig_prim_type(s): - return prim_types[s] - -# prefix_bla_blub(_t) => (dep.)BlaBlub -def as_zig_struct_type(s, prefix): - parts = s.lower().split('_') - outp = '' if s.startswith(prefix) else f'{parts[0]}.' - for part in parts[1:]: - # ignore '_t' type postfix - if (part != 't'): - outp += part.capitalize() - return outp - -# prefix_bla_blub(_t) => (dep.)BlaBlub -def as_zig_enum_type(s, prefix): - parts = s.lower().split('_') - outp = '' if s.startswith(prefix) else f'{parts[0]}.' - for part in parts[1:]: - if (part != 't'): - outp += part.capitalize() - return outp - -def check_override(name, default=None): - if name in overrides: - return overrides[name] - elif default is None: - return name - else: - return default - -def check_ignore(name): - return name in ignores - -# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla -def as_enum_item_name(s): - outp = s.lstrip('_') - parts = outp.split('_')[2:] - outp = '_'.join(parts) - if outp[0].isdigit(): - outp = '_' + outp - return outp - -def enum_default_item(enum_name): - return enum_items[enum_name][0] - -def is_prim_type(s): - return s in prim_types - -def is_struct_type(s): - return s in struct_types - -def is_enum_type(s): - return s in enum_types - -def is_const_prim_ptr(s): - for prim_type in prim_types: - if s == f"const {prim_type} *": - return True - return False - -def is_prim_ptr(s): - for prim_type in prim_types: - if s == f"{prim_type} *": - return True - return False - -def is_const_struct_ptr(s): - for struct_type in struct_types: - if s == f"const {struct_type} *": - return True - return False - -def type_default_value(s): - return prim_defaults[s] - -def as_c_arg_type(arg_type, prefix): - if arg_type == "void": - return "void" - elif is_prim_type(arg_type): - return as_zig_prim_type(arg_type) - elif is_struct_type(arg_type): - return as_zig_struct_type(arg_type, prefix) - elif is_enum_type(arg_type): - return as_zig_enum_type(arg_type, prefix) - elif util.is_void_ptr(arg_type): - return "?*anyopaque" - elif util.is_const_void_ptr(arg_type): - return "?*const anyopaque" - elif util.is_string_ptr(arg_type): - return "[*c]const u8" - elif is_const_struct_ptr(arg_type): - return f"[*c]const {as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}" - elif is_prim_ptr(arg_type): - return f"[*c]{as_zig_prim_type(util.extract_ptr_type(arg_type))}" - elif is_const_prim_ptr(arg_type): - return f"[*c]const {as_zig_prim_type(util.extract_ptr_type(arg_type))}" - else: - sys.exit(f"Error as_c_arg_type(): {arg_type}") - -def as_zig_arg_type(arg_prefix, arg_type, prefix): - # NOTE: if arg_prefix is None, the result is used as return value - pre = "" if arg_prefix is None else arg_prefix - if arg_type == "void": - if arg_prefix is None: - return "void" - else: - return "" - elif is_prim_type(arg_type): - return pre + as_zig_prim_type(arg_type) - elif is_struct_type(arg_type): - return pre + as_zig_struct_type(arg_type, prefix) - elif is_enum_type(arg_type): - return pre + as_zig_enum_type(arg_type, prefix) - elif util.is_void_ptr(arg_type): - return pre + "?*anyopaque" - elif util.is_const_void_ptr(arg_type): - return pre + "?*const anyopaque" - elif util.is_string_ptr(arg_type): - return pre + "[:0]const u8" - elif is_const_struct_ptr(arg_type): - # not a bug, pass const structs by value - return pre + f"{as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}" - elif is_prim_ptr(arg_type): - return pre + f"*{as_zig_prim_type(util.extract_ptr_type(arg_type))}" - elif is_const_prim_ptr(arg_type): - return pre + f"*const {as_zig_prim_type(util.extract_ptr_type(arg_type))}" - else: - sys.exit(f"ERROR as_zig_arg_type(): {arg_type}") - -def is_zig_string(zig_type): - return zig_type == "[:0]const u8" - -# get C-style arguments of a function pointer as string -def funcptr_args_c(field_type, prefix): - tokens = field_type[field_type.index('(*)')+4:-1].split(',') - s = "" - for token in tokens: - arg_type = token.strip() - if s != "": - s += ", " - c_arg = as_c_arg_type(arg_type, prefix) - if c_arg == "void": - return "" - else: - s += c_arg - return s - -# get C-style result of a function pointer as string -def funcptr_result_c(field_type): - res_type = field_type[:field_type.index('(*)')].strip() - if res_type == 'void': - return 'void' - elif is_prim_type(res_type): - return as_zig_prim_type(res_type) - elif util.is_const_void_ptr(res_type): - return '?*const anyopaque' - elif util.is_void_ptr(res_type): - return '?*anyopaque' - else: - sys.exit(f"ERROR funcptr_result_c(): {field_type}") - -def funcdecl_args_c(decl, prefix): - s = "" - func_name = decl['name'] - for param_decl in decl['params']: - if s != "": - s += ", " - param_name = param_decl['name'] - param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type']) - s += as_c_arg_type(param_type, prefix) - return s - -def funcdecl_args_zig(decl, prefix): - s = "" - func_name = decl['name'] - for param_decl in decl['params']: - if s != "": - s += ", " - param_name = param_decl['name'] - param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type']) - s += f"{as_zig_arg_type(f'{param_name}: ', param_type, prefix)}" - return s - -def funcdecl_result_c(decl, prefix): - func_name = decl['name'] - decl_type = decl['type'] - result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip()) - return as_c_arg_type(result_type, prefix) - -def funcdecl_result_zig(decl, prefix): - func_name = decl['name'] - decl_type = decl['type'] - result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip()) - zig_res_type = as_zig_arg_type(None, result_type, prefix) - return zig_res_type - -def gen_struct(decl, prefix): - struct_name = check_override(decl['name']) - zig_type = as_zig_struct_type(struct_name, prefix) - l(f"pub const {zig_type} = extern struct {{") - for field in decl['fields']: - field_name = check_override(field['name']) - field_type = check_override(f'{struct_name}.{field_name}', default=field['type']) - if is_prim_type(field_type): - l(f" {field_name}: {as_zig_prim_type(field_type)} = {type_default_value(field_type)},") - elif is_struct_type(field_type): - l(f" {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{}},") - elif is_enum_type(field_type): - l(f" {field_name}: {as_zig_enum_type(field_type, prefix)} = .{enum_default_item(field_type)},") - elif util.is_string_ptr(field_type): - l(f" {field_name}: [*c]const u8 = null,") - elif util.is_const_void_ptr(field_type): - l(f" {field_name}: ?*const anyopaque = null,") - elif util.is_void_ptr(field_type): - l(f" {field_name}: ?*anyopaque = null,") - elif is_const_prim_ptr(field_type): - l(f" {field_name}: ?[*]const {as_zig_prim_type(util.extract_ptr_type(field_type))} = null,") - elif util.is_func_ptr(field_type): - l(f" {field_name}: ?*const fn ({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_result_c(field_type)} = null,") - elif util.is_1d_array_type(field_type): - array_type = util.extract_array_type(field_type) - array_sizes = util.extract_array_sizes(field_type) - if is_prim_type(array_type) or is_struct_type(array_type): - if is_prim_type(array_type): - zig_type = as_zig_prim_type(array_type) - def_val = type_default_value(array_type) - elif is_struct_type(array_type): - zig_type = as_zig_struct_type(array_type, prefix) - def_val = '.{}' - elif is_enum_type(array_type): - zig_type = as_zig_enum_type(array_type, prefix) - def_val = '.{}' - else: - sys.exit(f"ERROR gen_struct is_1d_array_type: {array_type}") - t0 = f"[{array_sizes[0]}]{zig_type}" - t1 = f"[_]{zig_type}" - l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_sizes[0]},") - elif util.is_const_void_ptr(array_type): - l(f" {field_name}: [{array_sizes[0]}]?*const anyopaque = [_]?*const anyopaque{{null}} ** {array_sizes[0]},") - else: - sys.exit(f"ERROR gen_struct: array {field_name}: {field_type} => {array_type} [{array_sizes[0]}]") - elif util.is_2d_array_type(field_type): - array_type = util.extract_array_type(field_type) - array_sizes = util.extract_array_sizes(field_type) - if is_prim_type(array_type): - zig_type = as_zig_prim_type(array_type) - def_val = type_default_value(array_type) - elif is_struct_type(array_type): - zig_type = as_zig_struct_type(array_type, prefix) - def_val = ".{}" - else: - sys.exit(f"ERROR gen_struct is_2d_array_type: {array_type}") - t0 = f"[{array_sizes[0]}][{array_sizes[1]}]{zig_type}" - l(f" {field_name}: {t0} = [_][{array_sizes[1]}]{zig_type}{{[_]{zig_type}{{{def_val}}} ** {array_sizes[1]}}} ** {array_sizes[0]},") - else: - sys.exit(f"ERROR gen_struct: {field_name}: {field_type};") - l("};") - -def gen_consts(decl, prefix): - for item in decl['items']: - item_name = check_override(item['name']) - l(f"pub const {util.as_lower_snake_case(item_name, prefix)} = {item['value']};") - -def gen_enum(decl, prefix): - enum_name = check_override(decl['name']) - l(f"pub const {as_zig_enum_type(enum_name, prefix)} = enum(i32) {{") - for item in decl['items']: - item_name = as_enum_item_name(check_override(item['name'])) - if item_name != "FORCE_U32": - if 'value' in item: - l(f" {item_name} = {item['value']},") - else: - l(f" {item_name},") - l("};") - -def gen_func_c(decl, prefix): - l(f"pub extern fn {decl['name']}({funcdecl_args_c(decl, prefix)}) {funcdecl_result_c(decl, prefix)};") - -def gen_func_zig(decl, prefix): - c_func_name = decl['name'] - zig_func_name = util.as_lower_camel_case(check_override(decl['name']), prefix) - if c_func_name in c_callbacks: - # a simple forwarded C callback function - l(f"pub const {zig_func_name} = {c_func_name};") - else: - zig_res_type = funcdecl_result_zig(decl, prefix) - l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{") - if is_zig_string(zig_res_type): - # special case: convert C string to Zig string slice - s = f" return cStrToZig({c_func_name}(" - elif zig_res_type != 'void': - s = f" return {c_func_name}(" - else: - s = f" {c_func_name}(" - for i, param_decl in enumerate(decl['params']): - if i > 0: - s += ", " - arg_name = param_decl['name'] - arg_type = param_decl['type'] - if is_const_struct_ptr(arg_type): - s += f"&{arg_name}" - elif util.is_string_ptr(arg_type): - s += f"@ptrCast({arg_name})" - else: - s += arg_name - if is_zig_string(zig_res_type): - s += ")" - s += ");" - l(s) - l("}") - -def pre_parse(inp): - global struct_types - global enum_types - for decl in inp['decls']: - kind = decl['kind'] - if kind == 'struct': - struct_types.append(decl['name']) - elif kind == 'enum': - enum_name = decl['name'] - enum_types.append(enum_name) - enum_items[enum_name] = [] - for item in decl['items']: - enum_items[enum_name].append(as_enum_item_name(item['name'])) - -def gen_imports(inp, dep_prefixes): - l('const builtin = @import("builtin");') - for dep_prefix in dep_prefixes: - dep_module_name = module_names[dep_prefix] - l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.zig");') - l('') - -def gen_helpers(inp): - l('// helper function to convert a C string to a Zig string slice') - l('fn cStrToZig(c_str: [*c]const u8) [:0]const u8 {') - l(' return @import("std").mem.span(c_str);') - l('}') - if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']: - l('// helper function to convert "anything" to a Range struct') - l('pub fn asRange(val: anytype) Range {') - l(' const type_info = @typeInfo(@TypeOf(val));') - l(' switch (type_info) {') - l(' .Pointer => {') - l(' switch (type_info.Pointer.size) {') - l(' .One => return .{ .ptr = val, .size = @sizeOf(type_info.Pointer.child) },') - l(' .Slice => return .{ .ptr = val.ptr, .size = @sizeOf(type_info.Pointer.child) * val.len },') - l(' else => @compileError("FIXME: Pointer type!"),') - l(' }') - l(' },') - l(' .Struct, .Array => {') - l(' @compileError("Structs and arrays must be passed as pointers to asRange");') - l(' },') - l(' else => {') - l(' @compileError("Cannot convert to range!");') - l(' },') - l(' }') - l('}') - l('') - if inp['prefix'] == 'sdtx_': - l('// std.fmt compatible Writer') - l('pub const Writer = struct {') - l(' pub const Error = error{};') - l(' pub fn writeAll(self: Writer, bytes: []const u8) Error!void {') - l(' _ = self;') - l(' for (bytes) |byte| {') - l(' putc(byte);') - l(' }') - l(' }') - l(' pub fn writeByteNTimes(self: Writer, byte: u8, n: usize) Error!void {') - l(' _ = self;') - l(' var i: u64 = 0;') - l(' while (i < n) : (i += 1) {') - l(' putc(byte);') - l(' }') - l(' }') - l(' pub fn writeBytesNTimes(self: Writer, bytes: []const u8, n: usize) Error!void {') - l(' var i: usize = 0;') - l(' while (i < n) : (i += 1) {') - l(' try self.writeAll(bytes);') - l(' }') - l(' }') - l('};') - l('// std.fmt-style formatted print') - l('pub fn print(comptime fmt: anytype, args: anytype) void {') - l(' const writer: Writer = .{};') - l(' @import("std").fmt.format(writer, fmt, args) catch {};') - l('}') - l('') - -def gen_module(inp, dep_prefixes): - l('// machine generated, do not edit') - l('') - gen_imports(inp, dep_prefixes) - gen_helpers(inp) - pre_parse(inp) - prefix = inp['prefix'] - for decl in inp['decls']: - if not decl['is_dep']: - kind = decl['kind'] - if kind == 'consts': - gen_consts(decl, prefix) - elif not check_ignore(decl['name']): - if kind == 'struct': - gen_struct(decl, prefix) - elif kind == 'enum': - gen_enum(decl, prefix) - elif kind == 'func': - gen_func_c(decl, prefix) - gen_func_zig(decl, prefix) - -def prepare(): - print('=== Generating Zig bindings:') - if not os.path.isdir('sokol-zig/src/sokol'): - os.makedirs('sokol-zig/src/sokol') - if not os.path.isdir('sokol-zig/src/sokol/c'): - os.makedirs('sokol-zig/src/sokol/c') - -def gen(c_header_path, c_prefix, dep_c_prefixes): - if not c_prefix in module_names: - print(f' >> warning: skipping generation for {c_prefix} prefix...') - return - module_name = module_names[c_prefix] - c_source_path = c_source_paths[c_prefix] - print(f' {c_header_path} => {module_name}') - reset_globals() - shutil.copyfile(c_header_path, f'sokol-zig/src/sokol/c/{os.path.basename(c_header_path)}') - ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes) - gen_module(ir, dep_c_prefixes) - output_path = f"sokol-zig/src/sokol/{ir['module']}.zig" - with open(output_path, 'w', newline='\n') as f_outp: - f_outp.write(out_lines) diff --git a/source/engine/thirdparty/sokol/tests/.gitignore b/source/engine/thirdparty/sokol/tests/.gitignore deleted file mode 100644 index 567609b..0000000 --- a/source/engine/thirdparty/sokol/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/source/engine/thirdparty/sokol/tests/CMakeLists.txt b/source/engine/thirdparty/sokol/tests/CMakeLists.txt deleted file mode 100644 index cfaf7d4..0000000 --- a/source/engine/thirdparty/sokol/tests/CMakeLists.txt +++ /dev/null @@ -1,164 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(sokol-test) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 11) - -# SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU, SOKOL_DUMMY -set(SOKOL_BACKEND "SOKOL_DUMMY_BACKEND" CACHE STRING "Select 3D backend API") -set_property(CACHE SOKOL_BACKEND PROPERTY STRINGS SOKOL_GLCORE33 SOKOL_METAL SOKOL_D3D11 SOKOL_DUMMY_BACKEND) -option(SOKOL_FORCE_EGL "Force EGL with GLCORE33 backend" OFF) -option(SOKOL_FORCE_SLES "Force SLES in sokol-audio Android backend" OFF) -option(USE_ARC "Enable/disable ARC" OFF) -option(USE_ANALYZER "Enable/disable clang analyzer" OFF) - -if (CMAKE_SYSTEM_NAME STREQUAL Emscripten) - set(EMSCRIPTEN 1) -elseif (CMAKE_SYSTEM_NAME STREQUAL iOS) - set(OSX_IOS 1) -elseif (CMAKE_SYSTEM_NAME STREQUAL Android) - set(ANDROID 1) -elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) - set(LINUX 1) -elseif (CMAKE_SYSTEM_NAME STREQUAL Darwin) - set(OSX_MACOS 1) -elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) - set(WINDOWS 1) -else() - message(FATAL_ERROR "Unrecognized CMAKE_SYSTEM_NAME") -endif() - -message(">> CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") -message(">> SOKOL_BACKEND: ${SOKOL_BACKEND}") -message(">> SOKOL_FORCE_EGL: ${SOKOL_FORCE_EGL}") -message(">> SOKOL_FORCE_SLES: ${SOKOL_FORCE_SLES}") -if (OSX_IOS OR OSX_MACOS) - if (USE_ARC) - message(">> ObjC ARC ENABLED") - else() - message(">> ObjC ARC DISABLED") - endif() -endif() -message(">> BUILD_TYPE: ${CMAKE_BUILD_TYPE}") -message(">> TOOLCHAIN: ${CMAKE_TOOLCHAIN_FILE}") - -set(c_flags) -set(cxx_flags) -set(link_flags) -set(system_libs) - -if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(c_flags ${c_flags} /W4 /WX /D_CRT_SECURE_NO_WARNINGS) - set(cxx_flags ${cxx_flags} /W4 /WX /EHsc /D_CRT_SECURE_NO_WARNINGS) -else() - set(c_flags ${c_flags} -Wall -Wextra -Werror -Wsign-conversion -Wstrict-prototypes) - set(cxx_flags ${cxx_flags} -Wall -Wextra -Werror -Wsign-conversion -fno-rtti -fno-exceptions) - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(c_flags ${c_flags} -Wno-missing-field-initializers) - set(cxx_flags ${cxx_flags} -Wno-missing-field-initializers) - endif() - if (USE_ANALYZER) - # FIXME: consider using clang-tidy via CMAKE_CXX_CLANG_TIDY: https://ortogonal.github.io/cmake-clang-tidy/ - # with the default settings this spams the output with irrelevant C++ coding style warnings in 3rd party libs though - message(">> Configuring for static code analysis") - set(c_flags ${c_flags} --analyze -Xanalyzer -analyzer-opt-analyze-headers) - set(cxx_flags ${cxx_flags} --analyze -Xanalyzer -analyzer-opt-analyze-headers) - set(link_flags ${link_flags} --analyze -Wno-unused-command-line-argument) - endif() -endif() - -if (EMSCRIPTEN) - set(CMAKE_EXECUTABLE_SUFFIX ".html") - set(link_flags ${link_flags} -sNO_FILESYSTEM=1 -sASSERTIONS=0 -sMALLOC=emmalloc -sINITIAL_MEMORY=33554432 --closure=1) - if (SOKOL_BACKEND STREQUAL SOKOL_WGPU) - set(link_flags ${link_flags} -sUSE_WEBGPU=1) - else() - set(link_flags ${link_flags} -sUSE_WEBGL2=1) - endif() -elseif (OSX_IOS) - set(exe_type MACOSX_BUNDLE) - if (USE_ARC) - set(c_flags ${c_flags} -fobjc-arc) - set(cxx_flags ${cxx_flags} -fobjc-arc) - endif() - set(system_libs ${system_libs} "-framework Foundation" "-framework UIKit" "-framework AudioToolbox" "-framework AVFoundation") - if (SOKOL_BACKEND STREQUAL SOKOL_METAL) - set(system_libs ${system_libs} "-framework Metal" "-framework MetalKit") - else() - set(system_libs ${system_libs} "-framework OpenGLES" "-framework GLKit") - endif() -elseif (ANDROID) - if (SOKOL_FORCE_SLES) - set(system_libs ${system_libs} GLESv3 EGL OpenSLES log android) - else() - set(system_libs ${system_libs} GLESv3 EGL aaudio log android) - endif() -elseif (LINUX) - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - if ((SOKOL_BACKEND STREQUAL SOKOL_GLES3) OR SOKOL_FORCE_EGL) - set(system_libs ${system_libs} X11 Xi Xcursor EGL GL asound dl m Threads::Threads) - else() - set(system_libs ${system_libs} X11 Xi Xcursor GL asound dl m Threads::Threads) - endif() -elseif (OSX_MACOS) - set(exe_type MACOSX_BUNDLE) - if (USE_ARC) - set(c_flags ${c_flags} -fobjc-arc) - set(cxx_flags ${cxx_flags} -fobjc-arc) - endif() - set(system_libs ${system_libs} "-framework QuartzCore" "-framework Cocoa" "-framework AudioToolbox") - if (SOKOL_BACKEND STREQUAL SOKOL_METAL) - set(system_libs ${system_libs} "-framework MetalKit" "-framework Metal") - else() - set(system_libs ${system_libs} "-framework OpenGL") - endif() -elseif (WINDOWS) - set(exe_type WIN32) -endif() - -macro(configure_common target) - if (SOKOL_FORCE_EGL) - target_compile_definitions(${target} PRIVATE SOKOL_FORCE_EGL) - endif() - if (SOKOL_FORCE_SLES) - target_compile_definitions(${target} PRIVATE SAUDIO_ANDROID_SLES) - endif() - target_compile_definitions(${target} PRIVATE ${SOKOL_BACKEND}) - target_link_options(${target} PRIVATE ${link_flags}) - target_link_libraries(${target} PRIVATE ${system_libs}) - target_include_directories(${target} PRIVATE ../.. ../../util) - target_include_directories(${target} PRIVATE ../ext) -endmacro() - -macro(configure_osx_properties target) - if (OSX_IOS) - target_compile_definitions(${target} PRIVATE GLES_SILENCE_DEPRECATION) - endif() - set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${target}") - set_target_properties(${target} PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "${target}") - set_target_properties(${target} PROPERTIES MACOSX_BUNDLE_PRODUCT_NAME "${target}") - set_target_properties(${target} PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "${target}") -endmacro() - -macro(configure_c target) - configure_common(${target}) - target_compile_options(${target} PRIVATE ${c_flags}) - if (OSX_MACOS OR OSX_IOS) - target_compile_options(${target} PRIVATE -x objective-c) - configure_osx_properties(${target}) - endif() -endmacro() - -macro(configure_cxx target) - configure_common(${target}) - target_compile_options(${target} PRIVATE ${cxx_flags}) - if (OSX_MACOS OR OSX_IOS) - target_compile_options(${target} PRIVATE -x objective-c++) - configure_osx_properties(${target}) - endif() -endmacro() - -add_subdirectory(ext) -add_subdirectory(compile) -add_subdirectory(functional) diff --git a/source/engine/thirdparty/sokol/tests/CMakePresets.json b/source/engine/thirdparty/sokol/tests/CMakePresets.json deleted file mode 100644 index fe0b896..0000000 --- a/source/engine/thirdparty/sokol/tests/CMakePresets.json +++ /dev/null @@ -1,720 +0,0 @@ -{ - "version": 3, - "cmakeMinimumRequired": { - "major": 3, - "minor": 21, - "patch": 0 - }, - "configurePresets": [ - { - "name": "macos_gl_debug", - "generator": "Ninja", - "binaryDir": "build/macos_gl_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "macos_gl_release", - "generator": "Ninja", - "binaryDir": "build/macos_gl_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "macos_gl_analyze", - "generator": "Ninja", - "binaryDir": "build/macos_gl_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "macos_metal_debug", - "generator": "Ninja", - "binaryDir": "build/macos_metal_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "macos_metal_release", - "generator": "Ninja", - "binaryDir": "build/macos_metal_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "macos_metal_analyze", - "generator": "Ninja", - "binaryDir": "build/macos_metal_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "macos_arc_gl_debug", - "generator": "Ninja", - "binaryDir": "build/macos_arc_gl_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "macos_arc_gl_release", - "generator": "Ninja", - "binaryDir": "build/macos_arc_gl_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "macos_arc_gl_analyze", - "generator": "Ninja", - "binaryDir": "build/macos_arc_gl_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "macos_arc_metal_debug", - "generator": "Ninja", - "binaryDir": "build/macos_arc_metal_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "macos_arc_metal_release", - "generator": "Ninja", - "binaryDir": "build/macos_arc_metal_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "macos_arc_metal_analyze", - "generator": "Ninja", - "binaryDir": "build/macos_arc_metal_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "ios_gl", - "generator": "Xcode", - "binaryDir": "build/ios_gl", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_SYSTEM_NAME": "iOS" - } - }, - { - "name": "ios_gl_analyze", - "generator": "Ninja", - "binaryDir": "build/ios_gl_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_SYSTEM_NAME": "iOS", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "ios_metal", - "generator": "Xcode", - "binaryDir": "build/ios_metal", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "CMAKE_SYSTEM_NAME": "iOS" - } - }, - { - "name": "ios_metal_analyze", - "generator": "Ninja", - "binaryDir": "build/ios_metal_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_SYSTEM_NAME": "iOS", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "ios_arc_gl", - "generator": "Xcode", - "binaryDir": "build/ios_arc_gl", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_SYSTEM_NAME": "iOS" - } - }, - { - "name": "ios_arc_gl_analyze", - "generator": "Ninja", - "binaryDir": "build/ios_arc_gl_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_SYSTEM_NAME": "iOS", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "ios_arc_metal", - "generator": "Xcode", - "binaryDir": "build/ios_arc_metal", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_SYSTEM_NAME": "iOS" - } - }, - { - "name": "ios_arc_metal_analyze", - "generator": "Ninja", - "binaryDir": "build/ios_arc_metal_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_METAL", - "USE_ARC": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_SYSTEM_NAME": "iOS", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "linux_gl_debug", - "generator": "Ninja", - "binaryDir": "build/linux_gl_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "linux_gl_release", - "generator": "Ninja", - "binaryDir": "build/linux_gl_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "linux_gl_analyze", - "generator": "Ninja", - "binaryDir": "build/linux_gl_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "linux_gles3_debug", - "generator": "Ninja", - "binaryDir": "build/linux_gles3_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "linux_gles3_release", - "generator": "Ninja", - "binaryDir": "build/linux_gles3_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "linux_gles3_analyze", - "generator": "Ninja", - "binaryDir": "build/linux_gles3_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "linux_gl_egl_debug", - "generator": "Ninja", - "binaryDir": "build/linux_gl_egl_debug", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "SOKOL_FORCE_EGL": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "linux_gl_egl_release", - "generator": "Ninja", - "binaryDir": "build/linux_gl_egl_release", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "SOKOL_FORCE_EGL": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "emsc_webgl2_debug", - "generator": "Ninja", - "binaryDir": "build/emsc_webgl2_debug", - "toolchainFile": "build/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "emsc_webgl2_release", - "generator": "Ninja", - "binaryDir": "build/emsc_webgl2_release", - "toolchainFile": "build/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "emsc_wgpu_debug", - "generator": "Ninja", - "binaryDir": "build/emsc_wgpu_debug", - "toolchainFile": "build/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_WGPU", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "emsc_wgpu_release", - "generator": "Ninja", - "binaryDir": "build/emsc_wgpu_release", - "toolchainFile": "build/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_WGPU", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "android_debug", - "generator": "Ninja", - "binaryDir": "build/android_debug", - "toolchainFile": "build/android_sdk/ndk-bundle/build/cmake/android.toolchain.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "ANDROID_ABI": "armeabi-v7a", - "ANDROID_PLATFORM": "android-28", - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "android_release", - "generator": "Ninja", - "binaryDir": "build/android_release", - "toolchainFile": "build/android_sdk/ndk-bundle/build/cmake/android.toolchain.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "ANDROID_ABI": "armeabi-v7a", - "ANDROID_PLATFORM": "android-28", - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "android_sles_debug", - "generator": "Ninja", - "binaryDir": "build/android_sles_debug", - "toolchainFile": "build/android_sdk/ndk-bundle/build/cmake/android.toolchain.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "ANDROID_ABI": "armeabi-v7a", - "ANDROID_PLATFORM": "android-28", - "CMAKE_BUILD_TYPE": "Debug", - "SOKOL_FORCE_SLES": { - "type": "BOOL", - "value": "ON" - } - } - }, - { - "name": "android_sles_release", - "generator": "Ninja", - "binaryDir": "build/android_sles_release", - "toolchainFile": "build/android_sdk/ndk-bundle/build/cmake/android.toolchain.cmake", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLES3", - "ANDROID_ABI": "armeabi-v7a", - "ANDROID_PLATFORM": "android-28", - "CMAKE_BUILD_TYPE": "Release", - "SOKOL_FORCE_SLES": { - "type": "BOOL", - "value": "ON" - } - } - }, - { - "name": "win_gl", - "binaryDir": "build/win_gl", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33" - } - }, - { - "name": "win_gl_analyze", - "generator": "Ninja", - "binaryDir": "build/win_gl_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_GLCORE33", - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - }, - { - "name": "win_d3d11", - "binaryDir": "build/win_d3d11", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_D3D11" - } - }, - { - "name": "win_d3d11_analyze", - "generator": "Ninja", - "binaryDir": "build/win_d3d11_analyze", - "cacheVariables": { - "SOKOL_BACKEND": "SOKOL_D3D11", - "CMAKE_BUILD_TYPE": "Debug", - "USE_ANALYZER": { - "type": "BOOL", - "value": "ON" - }, - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - } - } - ], - "buildPresets": [ - { - "name": "macos_gl_debug", - "configurePreset": "macos_gl_debug" - }, - { - "name": "macos_gl_release", - "configurePreset": "macos_gl_release" - }, - { - "name": "macos_gl_analyze", - "configurePreset": "macos_gl_analyze" - }, - { - "name": "macos_metal_debug", - "configurePreset": "macos_metal_debug" - }, - { - "name": "macos_metal_release", - "configurePreset": "macos_metal_release" - }, - { - "name": "macos_metal_analyze", - "configurePreset": "macos_metal_analyze" - }, - { - "name": "macos_arc_gl_debug", - "configurePreset": "macos_arc_gl_debug" - }, - { - "name": "macos_arc_gl_release", - "configurePreset": "macos_arc_gl_release" - }, - { - "name": "macos_arc_gl_analyze", - "configurePreset": "macos_arc_gl_analyze" - }, - { - "name": "macos_arc_metal_debug", - "configurePreset": "macos_arc_metal_debug" - }, - { - "name": "macos_arc_metal_release", - "configurePreset": "macos_arc_metal_release" - }, - { - "name": "macos_arc_metal_analyze", - "configurePreset": "macos_arc_metal_analyze" - }, - { - "name": "ios_gl_debug", - "configurePreset": "ios_gl", - "configuration": "Debug", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_gl_release", - "configurePreset": "ios_gl", - "configuration": "Release", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_gl_analyze", - "configurePreset": "ios_gl_analyze" - }, - { - "name": "ios_metal_debug", - "configurePreset": "ios_metal", - "configuration": "Debug", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_metal_release", - "configurePreset": "ios_metal", - "configuration": "Release", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_metal_analyze", - "configurePreset": "ios_metal_analyze" - }, - { - "name": "ios_arc_gl_debug", - "configurePreset": "ios_arc_gl", - "configuration": "Debug", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_arc_gl_release", - "configurePreset": "ios_arc_gl", - "configuration": "Release", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_arc_gl_analyze", - "configurePreset": "ios_arc_gl_analyze" - }, - { - "name": "ios_arc_metal_debug", - "configurePreset": "ios_arc_metal", - "configuration": "Debug", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_arc_metal_release", - "configurePreset": "ios_arc_metal", - "configuration": "Release", - "nativeToolOptions": [ "CODE_SIGN_IDENTITY=\"\"", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGNING_ALLOWED=NO" ] - }, - { - "name": "ios_arc_metal_analyze", - "configurePreset": "ios_arc_metal_analyze" - }, - { - "name": "linux_gl_debug", - "configurePreset": "linux_gl_debug" - }, - { - "name": "linux_gl_release", - "configurePreset": "linux_gl_release" - }, - { - "name": "linux_gl_analyze", - "configurePreset": "linux_gl_analyze" - }, - { - "name": "linux_gles3_debug", - "configurePreset": "linux_gles3_debug" - }, - { - "name": "linux_gles3_release", - "configurePreset": "linux_gles3_release" - }, - { - "name": "linux_gles3_analyze", - "configurePreset": "linux_gles3_analyze" - }, - { - "name": "linux_gl_egl_debug", - "configurePreset": "linux_gl_egl_debug" - }, - { - "name": "linux_gl_egl_release", - "configurePreset": "linux_gl_egl_release" - }, - { - "name": "emsc_webgl2_debug", - "configurePreset": "emsc_webgl2_debug" - }, - { - "name": "emsc_webgl2_release", - "configurePreset": "emsc_webgl2_release" - }, - { - "name": "emsc_wgpu_debug", - "configurePreset": "emsc_wgpu_debug" - }, - { - "name": "emsc_wgpu_release", - "configurePreset": "emsc_wgpu_release" - }, - { - "name": "android_debug", - "configurePreset": "android_debug" - }, - { - "name": "android_release", - "configurePreset": "android_release" - }, - { - "name": "android_sles_debug", - "configurePreset": "android_sles_debug" - }, - { - "name": "android_sles_release", - "configurePreset": "android_sles_release" - }, - { - "name": "win_gl_debug", - "configurePreset": "win_gl", - "configuration": "Debug" - }, - { - "name": "win_gl_release", - "configurePreset": "win_gl", - "configuration": "Release" - }, - { - "name": "win_gl_analyze", - "configurePreset": "win_gl_analyze" - }, - { - "name": "win_d3d11_debug", - "configurePreset": "win_d3d11", - "configuration": "Debug" - }, - { - "name": "win_d3d11_release", - "configurePreset": "win_d3d11", - "configuration": "Release" - }, - { - "name": "win_d3d11_analyze", - "configurePreset": "win_d3d11_analyze" - } - ] -} diff --git a/source/engine/thirdparty/sokol/tests/analyze_ios.sh b/source/engine/thirdparty/sokol/tests/analyze_ios.sh deleted file mode 100755 index 5b3f474..0000000 --- a/source/engine/thirdparty/sokol/tests/analyze_ios.sh +++ /dev/null @@ -1,6 +0,0 @@ -set -e -source test_common.sh -build ios_gl_analyze ios_gl_analyze -build ios_metal_analyze ios_metal_analyze -build ios_arc_gl_analyze ios_arc_gl_analyze -build ios_arc_metal_analyze ios_arc_metal_analyze diff --git a/source/engine/thirdparty/sokol/tests/analyze_linux.sh b/source/engine/thirdparty/sokol/tests/analyze_linux.sh deleted file mode 100755 index 87099b9..0000000 --- a/source/engine/thirdparty/sokol/tests/analyze_linux.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -set -e -source test_common.sh - -build linux_gl_analyze linux_gl_analyze -build linux_gles3_analyze linux_gles3_analyze diff --git a/source/engine/thirdparty/sokol/tests/analyze_macos.sh b/source/engine/thirdparty/sokol/tests/analyze_macos.sh deleted file mode 100755 index 3134070..0000000 --- a/source/engine/thirdparty/sokol/tests/analyze_macos.sh +++ /dev/null @@ -1,8 +0,0 @@ -set -e -source test_common.sh - -build macos_gl_analyze macos_gl_analyze -build macos_metal_analyze macos_metal_analyze - -build macos_arc_gl_analyze macos_arc_gl_analyze -build macos_arc_metal_analyze macos_arc_metal_analyze diff --git a/source/engine/thirdparty/sokol/tests/analyze_win.cmd b/source/engine/thirdparty/sokol/tests/analyze_win.cmd deleted file mode 100644 index 39aa798..0000000 --- a/source/engine/thirdparty/sokol/tests/analyze_win.cmd +++ /dev/null @@ -1,4 +0,0 @@ -cmake --preset win_gl_analyze || exit /b 10 -cmake --build --preset win_gl_analyze || exit /b 10 -cmake --preset win_d3d11_analyze || exit /b 10 -cmake --build --preset win_d3d11_analyze || exit /b 10 diff --git a/source/engine/thirdparty/sokol/tests/compile/CMakeLists.txt b/source/engine/thirdparty/sokol/tests/compile/CMakeLists.txt deleted file mode 100644 index e664555..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -set(c_sources - sokol_app.c - sokol_glue.c - sokol_gfx.c - sokol_time.c - sokol_args.c - sokol_audio.c - sokol_debugtext.c - sokol_gl.c - sokol_fontstash.c - sokol_imgui.c - sokol_gfx_imgui.c - sokol_shape.c - sokol_nuklear.c - sokol_color.c - sokol_spine.c - sokol_log.c - sokol_main.c) -if (NOT ANDROID) - set(c_sources ${c_sources} sokol_fetch.c) -endif() - -set(cxx_sources - sokol_app.cc - sokol_glue.cc - sokol_gfx.cc - sokol_time.cc - sokol_args.cc - sokol_audio.cc - sokol_debugtext.cc - sokol_gl.cc - sokol_fontstash.cc - sokol_imgui.cc - sokol_gfx_imgui.cc - sokol_shape.cc - sokol_color.cc - sokol_spine.cc - sokol_log.cc - sokol_main.cc) -if (NOT ANDROID) - set(cxx_sources ${cxx_sources} sokol_fetch.cc) -endif() - -if (ANDROID) - add_library(sokol-compiletest-c SHARED ${c_sources}) -else() - add_executable(sokol-compiletest-c ${exe_type} sokol_app.c sokol_glue.c ${c_sources}) -endif() -target_link_libraries(sokol-compiletest-c PUBLIC cimgui nuklear spine) -configure_c(sokol-compiletest-c) - -if (ANDROID) - add_library(sokol-compiletest-cxx SHARED ${cxx_sources}) -else() - add_executable(sokol-compiletest-cxx ${exe_type} ${cxx_sources}) -endif() -target_link_libraries(sokol-compiletest-cxx PUBLIC imgui nuklear spine) -configure_cxx(sokol-compiletest-cxx) diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_app.c b/source/engine/thirdparty/sokol/tests/compile/sokol_app.c deleted file mode 100644 index 33304cf..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_app.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_app.h" - -void use_app_impl(void) { - sapp_run(&(sapp_desc){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_app.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_app.cc deleted file mode 100644 index 49c254e..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_app.cc +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_app.h" - -void use_app_impl() { - sapp_run({ }); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_args.c b/source/engine/thirdparty/sokol/tests/compile/sokol_args.c deleted file mode 100644 index 4005283..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_args.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_args.h" - -void use_args_impl(void) { - sargs_setup(&(sargs_desc){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_args.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_args.cc deleted file mode 100644 index 7e31d46..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_args.cc +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_args.h" - -void use_args_impl() { - sargs_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_audio.c b/source/engine/thirdparty/sokol/tests/compile/sokol_audio.c deleted file mode 100644 index 1dc12f2..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_audio.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_audio.h" - -void use_audio_impl(void) { - saudio_setup(&(saudio_desc){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_audio.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_audio.cc deleted file mode 100644 index 4205d51..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_audio.cc +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_audio.h" - -void use_audio_impl() { - saudio_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_color.c b/source/engine/thirdparty/sokol/tests/compile/sokol_color.c deleted file mode 100644 index ea3a354..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_color.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_color.h" - -void use_color_impl(void) { - sg_color c = sg_make_color_4b(255, 0, 0, 255); - (void)c; -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_color.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_color.cc deleted file mode 100644 index ccb6d2b..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_color.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_color.h" - -void use_color_impl(void) { - sg_color c = sg_make_color(255, 0, 0, 255); - (void)c; -} - diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_debugtext.c b/source/engine/thirdparty/sokol/tests/compile/sokol_debugtext.c deleted file mode 100644 index 1d22c63..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_debugtext.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_debugtext.h" - -void use_debugtext_impl(void) { - sdtx_setup(&(sdtx_desc_t){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_debugtext.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_debugtext.cc deleted file mode 100644 index 6889405..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_debugtext.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_debugtext.h" - -void use_debugtext_impl() { - sdtx_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_fetch.c b/source/engine/thirdparty/sokol/tests/compile/sokol_fetch.c deleted file mode 100644 index 2509056..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_fetch.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_fetch.h" - -void use_fetch_impl(void) { - sfetch_setup(&(sfetch_desc_t){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_fetch.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_fetch.cc deleted file mode 100644 index 69cc228..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_fetch.cc +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_fetch.h" - -void use_fetch_impl() { - sfetch_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_fontstash.c b/source/engine/thirdparty/sokol/tests/compile/sokol_fontstash.c deleted file mode 100644 index 0232de8..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_fontstash.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "sokol_gfx.h" -#include "sokol_gl.h" - -#define FONTSTASH_IMPLEMENTATION -#if defined(_MSC_VER ) -#pragma warning(disable:4996) // strncpy use in fontstash.h -#endif -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif -#include // malloc/free -#include "fontstash.h" -#define SOKOL_IMPL -#include "sokol_fontstash.h" - -void use_fontstash_impl(void) { - FONScontext* ctx = sfons_create(&(sfons_desc_t){ 0 }); - sfons_destroy(ctx); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_fontstash.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_fontstash.cc deleted file mode 100644 index 96d7c31..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_fontstash.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include "sokol_gfx.h" -#include "sokol_gl.h" - -#define FONTSTASH_IMPLEMENTATION -#if defined(_MSC_VER ) -#pragma warning(disable:4996) // strncpy use in fontstash.h -#pragma warning(disable:4505) // unreferenced local function has been removed -#pragma warning(disable:4100) // unreferenced formal parameter -#endif -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif -#include // malloc/free -#include "fontstash.h" -#define SOKOL_IMPL -#include "sokol_fontstash.h" - -void use_fontstash_impl() { - const sfons_desc_t desc = { }; - FONScontext* ctx = sfons_create(&desc); - sfons_destroy(ctx); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx.c b/source/engine/thirdparty/sokol/tests/compile/sokol_gfx.c deleted file mode 100644 index 8926310..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_gfx.h" - -void use_gfx_impl(void) { - sg_setup(&(sg_desc){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_gfx.cc deleted file mode 100644 index 58f6592..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx.cc +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_gfx.h" - -void use_gfx_impl() { - sg_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx_imgui.c b/source/engine/thirdparty/sokol/tests/compile/sokol_gfx_imgui.c deleted file mode 100644 index 5b59501..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx_imgui.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" -#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS -#if defined(_MSC_VER ) -#pragma warning(disable:4201) // nonstandard extension used: nameless struct/union -#pragma warning(disable:4214) // nonstandard extension used: bit field types other than int -#endif -#include "cimgui/cimgui.h" -#include "sokol_imgui.h" -#define SOKOL_IMPL -#include "sokol_gfx_imgui.h" - -void use_gfx_imgui_impl(void) { - sgimgui_t ctx = {0}; - sgimgui_init(&ctx, &(sgimgui_desc_t){0}); - sgimgui_discard(&ctx); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx_imgui.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_gfx_imgui.cc deleted file mode 100644 index 2e64dbc..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_gfx_imgui.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" -#include "imgui.h" -#include "sokol_imgui.h" -#define SOKOL_IMPL -#include "sokol_gfx_imgui.h" - -void use_gfx_imgui_impl() { - sgimgui_t ctx = {}; - sgimgui_init(&ctx, { }); - sgimgui_discard(&ctx); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_gl.c b/source/engine/thirdparty/sokol/tests/compile/sokol_gl.c deleted file mode 100644 index 6dbeea1..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_gl.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_gl.h" - -void use_gl_impl(void) { - sgl_setup(&(sgl_desc_t){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_gl.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_gl.cc deleted file mode 100644 index a4177cb..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_gl.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_gl.h" - -void use_gl_impl() { - sgl_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_glue.c b/source/engine/thirdparty/sokol/tests/compile/sokol_glue.c deleted file mode 100644 index 114b6e2..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_glue.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_glue.h" - -void use_glue_impl(void) { - const sg_environment env = sglue_environment(); - (void)env; -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_glue.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_glue.cc deleted file mode 100644 index 4aaf21c..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_glue.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_glue.h" - -void use_glue_impl() { - const sg_environment ctx = sglue_environment(); - (void)ctx; -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_imgui.c b/source/engine/thirdparty/sokol/tests/compile/sokol_imgui.c deleted file mode 100644 index 90f0bb7..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_imgui.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" -#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS -#if defined(_MSC_VER ) -#pragma warning(disable:4201) // nonstandard extension used: nameless struct/union -#pragma warning(disable:4214) // nonstandard extension used: bit field types other than int -#endif -#include "cimgui/cimgui.h" -#define SOKOL_IMPL -#if defined(SOKOL_DUMMY_BACKEND) -#define SOKOL_IMGUI_NO_SOKOL_APP -#endif -#include "sokol_imgui.h" - -void use_imgui_impl(void) { - simgui_setup(&(simgui_desc_t){0}); -} - diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_imgui.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_imgui.cc deleted file mode 100644 index 5a6a32f..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_imgui.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" -#include "imgui.h" -#define SOKOL_IMPL -#if defined(SOKOL_DUMMY_BACKEND) -#define SOKOL_IMGUI_NO_SOKOL_APP -#endif -#include "sokol_imgui.h" - -void use_imgui_impl() { - simgui_setup({}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_log.c b/source/engine/thirdparty/sokol/tests/compile/sokol_log.c deleted file mode 100644 index ac66ec5..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_log.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_log.h" - -void use_sokol_log(void) { - slog_func("bla", 1, 123, "123", 42, "bla.c", 0); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_log.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_log.cc deleted file mode 100644 index ac66ec5..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_log.cc +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_log.h" - -void use_sokol_log(void) { - slog_func("bla", 1, 123, "123", 42, "bla.c", 0); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_main.c b/source/engine/thirdparty/sokol/tests/compile/sokol_main.c deleted file mode 100644 index d1e34b6..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_main.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "sokol_app.h" - -#if defined(SOKOL_DUMMY_BACKEND) -int main() { - return 0; -} -#else -sapp_desc sokol_main(int argc, char* argv[]) { - (void)argc; - (void)argv; - return (sapp_desc){0}; -} -#endif diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_main.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_main.cc deleted file mode 100644 index c27ed3e..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_main.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_app.h" - -sapp_desc sokol_main(int argc, char* argv[]) { - (void)argc; - (void)argv; - return { }; -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_nuklear.c b/source/engine/thirdparty/sokol/tests/compile/sokol_nuklear.c deleted file mode 100644 index e5311b4..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_nuklear.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "sokol_app.h" -#include "sokol_gfx.h" - -// include nuklear.h before the sokol_nuklear.h implementation -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_INCLUDE_STANDARD_VARARGS -#include "nuklear.h" - -#define SOKOL_IMPL -#if defined(SOKOL_DUMMY_BACKEND) -#define SOKOL_NUKLEAR_NO_SOKOL_APP -#endif -#include "sokol_nuklear.h" - -void use_nuklear_impl(void) { - snk_setup(&(snk_desc_t){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_shape.c b/source/engine/thirdparty/sokol/tests/compile/sokol_shape.c deleted file mode 100644 index 72c48b6..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_shape.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_shape.h" - -void use_shape_impl(void) { - sshape_plane_sizes(10); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_shape.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_shape.cc deleted file mode 100644 index 0013ea6..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_shape.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "sokol_shape.h" - -void use_shape_impl() { - sshape_plane_sizes(10); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_spine.c b/source/engine/thirdparty/sokol/tests/compile/sokol_spine.c deleted file mode 100644 index 4669003..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_spine.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "spine/spine.h" -#include "sokol_spine.h" - -void use_sspine_impl(void) { - sspine_setup(&(sspine_desc){0}); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_spine.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_spine.cc deleted file mode 100644 index e484dbe..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_spine.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include "sokol_gfx.h" -#define SOKOL_IMPL -#include "spine/spine.h" -#include "sokol_spine.h" - -void use_sspine_impl(void) { - const sspine_desc desc = {}; - sspine_setup(&desc); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_time.c b/source/engine/thirdparty/sokol/tests/compile/sokol_time.c deleted file mode 100644 index 416e500..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_time.c +++ /dev/null @@ -1,6 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_time.h" - -void use_time_impl(void) { - stm_setup(); -} diff --git a/source/engine/thirdparty/sokol/tests/compile/sokol_time.cc b/source/engine/thirdparty/sokol/tests/compile/sokol_time.cc deleted file mode 100644 index f0c19c9..0000000 --- a/source/engine/thirdparty/sokol/tests/compile/sokol_time.cc +++ /dev/null @@ -1,7 +0,0 @@ -#define SOKOL_IMPL -#include "sokol_time.h" - -void use_time_impl() { - stm_setup(); -} - diff --git a/source/engine/thirdparty/sokol/tests/ext/CMakeLists.txt b/source/engine/thirdparty/sokol/tests/ext/CMakeLists.txt deleted file mode 100644 index 4ded7c4..0000000 --- a/source/engine/thirdparty/sokol/tests/ext/CMakeLists.txt +++ /dev/null @@ -1,97 +0,0 @@ -# external dependencies - -# NOTE FetchContent is so frigging slow that we just run git directly -set(cimgui_dir ${CMAKE_BINARY_DIR}/../_deps/cimgui) -set(spineruntimes_dir ${CMAKE_BINARY_DIR}/../_deps/spineruntimes) - -if (IS_DIRECTORY ${cimgui_dir}) - message("### ${cimgui_dir} exists...") -else() - message("### Fetching cimgui to ${cimgui_dir} (this may take a while...)") - execute_process(COMMAND git clone --depth=1 --recursive https://github.com/fips-libs/fips-cimgui ${cimgui_dir}) -endif() -if (IS_DIRECTORY ${spineruntimes_dir}) - message("### ${spineruntimes_dir} exists...") -else() - message("### Fetching spine runtimes to ${spineruntimes_dir} (this may take a while...)") - execute_process(COMMAND git clone --depth=1 --recursive https://github.com/EsotericSoftware/spine-runtimes ${spineruntimes_dir}) -endif() - -add_library(cimgui - ${cimgui_dir}/cimgui/cimgui.cpp - ${cimgui_dir}/cimgui/imgui/imgui.cpp - ${cimgui_dir}/cimgui/imgui/imgui_demo.cpp - ${cimgui_dir}/cimgui/imgui/imgui_draw.cpp - ${cimgui_dir}/cimgui/imgui/imgui_tables.cpp - ${cimgui_dir}/cimgui/imgui/imgui_widgets.cpp) -target_include_directories(cimgui SYSTEM PUBLIC ${cimgui_dir}) - -add_library(imgui - ${cimgui_dir}/cimgui/imgui/imgui.cpp - ${cimgui_dir}/cimgui/imgui/imgui_demo.cpp - ${cimgui_dir}/cimgui/imgui/imgui_draw.cpp - ${cimgui_dir}/cimgui/imgui/imgui_tables.cpp - ${cimgui_dir}/cimgui/imgui/imgui_widgets.cpp) -target_include_directories(imgui SYSTEM PUBLIC ${cimgui_dir}/cimgui/imgui) - -add_library(spine - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Animation.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/AnimationState.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/AnimationStateData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Array.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Atlas.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/AtlasAttachmentLoader.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Attachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/AttachmentLoader.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Bone.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/BoneData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/BoundingBoxAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/ClippingAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Color.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Debug.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Event.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/EventData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/IkConstraint.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/IkConstraintData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Json.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Json.h - ${spineruntimes_dir}/spine-c/spine-c/src/spine/MeshAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/PathAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/PathConstraint.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/PathConstraintData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/PointAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/RegionAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Sequence.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Skeleton.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/SkeletonBinary.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/SkeletonBounds.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/SkeletonClipping.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/SkeletonData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/SkeletonJson.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Skin.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Slot.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/SlotData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/TransformConstraint.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/TransformConstraintData.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/Triangulator.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/VertexAttachment.c - ${spineruntimes_dir}/spine-c/spine-c/src/spine/extension.c) -target_include_directories(spine SYSTEM PUBLIC ${spineruntimes_dir}/spine-c/spine-c/include) -if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - target_compile_options(spine PRIVATE /wd4267 /wd4244) # conversion from 'x' to 'y' possible loss of data -endif() -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - target_compile_options(spine PRIVATE -Wno-shorten-64-to-32) -endif() - -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy-pro.json DESTINATION ${CMAKE_BINARY_DIR}) -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy-pro.skel DESTINATION ${CMAKE_BINARY_DIR}) -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy.atlas DESTINATION ${CMAKE_BINARY_DIR}) -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy.png DESTINATION ${CMAKE_BINARY_DIR}) - -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy-pro.json DESTINATION ${CMAKE_BINARY_DIR}/Debug) -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy-pro.skel DESTINATION ${CMAKE_BINARY_DIR}/Debug) -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy.atlas DESTINATION ${CMAKE_BINARY_DIR}/Debug) -file(COPY ${spineruntimes_dir}/examples/spineboy/export/spineboy.png DESTINATION ${CMAKE_BINARY_DIR}/Debug) - -add_library(nuklear nuklear.c) diff --git a/source/engine/thirdparty/sokol/tests/ext/fontstash.h b/source/engine/thirdparty/sokol/tests/ext/fontstash.h deleted file mode 100644 index a09e6f1..0000000 --- a/source/engine/thirdparty/sokol/tests/ext/fontstash.h +++ /dev/null @@ -1,1714 +0,0 @@ -// -// NOTE sokol: all IO functions have been removed -// -// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org -// -// 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. -// - -#ifndef FONS_H -#define FONS_H - -#ifdef __cplusplus -extern "C" { -#endif - -// To make the implementation private to the file that generates the implementation -#ifdef FONS_STATIC -#define FONS_DEF static -#else -#define FONS_DEF extern -#endif - -#define FONS_INVALID -1 - -enum FONSflags { - FONS_ZERO_TOPLEFT = 1, - FONS_ZERO_BOTTOMLEFT = 2, -}; - -enum FONSalign { - // Horizontal align - FONS_ALIGN_LEFT = 1<<0, // Default - FONS_ALIGN_CENTER = 1<<1, - FONS_ALIGN_RIGHT = 1<<2, - // Vertical align - FONS_ALIGN_TOP = 1<<3, - FONS_ALIGN_MIDDLE = 1<<4, - FONS_ALIGN_BOTTOM = 1<<5, - FONS_ALIGN_BASELINE = 1<<6, // Default -}; - -enum FONSerrorCode { - // Font atlas is full. - FONS_ATLAS_FULL = 1, - // Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE. - FONS_SCRATCH_FULL = 2, - // Calls to fonsPushState has created too large stack, if you need deep state stack bump up FONS_MAX_STATES. - FONS_STATES_OVERFLOW = 3, - // Trying to pop too many states fonsPopState(). - FONS_STATES_UNDERFLOW = 4, -}; - -struct FONSparams { - int width, height; - unsigned char flags; - void* userPtr; - int (*renderCreate)(void* uptr, int width, int height); - int (*renderResize)(void* uptr, int width, int height); - void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data); - void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts); - void (*renderDelete)(void* uptr); -}; -typedef struct FONSparams FONSparams; - -struct FONSquad -{ - float x0,y0,s0,t0; - float x1,y1,s1,t1; -}; -typedef struct FONSquad FONSquad; - -struct FONStextIter { - float x, y, nextx, nexty, scale, spacing; - unsigned int codepoint; - short isize, iblur; - struct FONSfont* font; - int prevGlyphIndex; - const char* str; - const char* next; - const char* end; - unsigned int utf8state; -}; -typedef struct FONStextIter FONStextIter; - -typedef struct FONScontext FONScontext; - -// Contructor and destructor. -FONS_DEF FONScontext* fonsCreateInternal(FONSparams* params); -FONS_DEF void fonsDeleteInternal(FONScontext* s); - -FONS_DEF void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr); -// Returns current atlas size. -FONS_DEF void fonsGetAtlasSize(FONScontext* s, int* width, int* height); -// Expands the atlas size. -FONS_DEF int fonsExpandAtlas(FONScontext* s, int width, int height); -// Resets the whole stash. -FONS_DEF int fonsResetAtlas(FONScontext* stash, int width, int height); - -// Add fonts -FONS_DEF int fonsGetFontByName(FONScontext* s, const char* name); -FONS_DEF int fonsAddFallbackFont(FONScontext* stash, int base, int fallback); - -// State handling -FONS_DEF void fonsPushState(FONScontext* s); -FONS_DEF void fonsPopState(FONScontext* s); -FONS_DEF void fonsClearState(FONScontext* s); - -// State setting -FONS_DEF void fonsSetSize(FONScontext* s, float size); -FONS_DEF void fonsSetColor(FONScontext* s, unsigned int color); -FONS_DEF void fonsSetSpacing(FONScontext* s, float spacing); -FONS_DEF void fonsSetBlur(FONScontext* s, float blur); -FONS_DEF void fonsSetAlign(FONScontext* s, int align); -FONS_DEF void fonsSetFont(FONScontext* s, int font); - -// Draw text -FONS_DEF float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end); - -// Measure text -FONS_DEF float fonsTextBounds(FONScontext* s, float x, float y, const char* string, const char* end, float* bounds); -FONS_DEF void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy); -FONS_DEF void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh); - -// Text iterator -FONS_DEF int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end); -FONS_DEF int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad); - -// Pull texture changes -FONS_DEF const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height); -FONS_DEF int fonsValidateTexture(FONScontext* s, int* dirty); - -// Draws the stash texture for debugging -FONS_DEF void fonsDrawDebug(FONScontext* s, float x, float y); - -#ifdef __cplusplus -} -#endif - -#endif // FONS_H - - -#ifdef FONTSTASH_IMPLEMENTATION - -#define FONS_NOTUSED(v) (void)sizeof(v) - -#ifdef FONS_USE_FREETYPE - -#include -#include FT_FREETYPE_H -#include FT_ADVANCES_H -#include - -struct FONSttFontImpl { - FT_Face font; -}; -typedef struct FONSttFontImpl FONSttFontImpl; - -static FT_Library ftLibrary; - -static int fons__tt_init() -{ - FT_Error ftError; - FONS_NOTUSED(context); - ftError = FT_Init_FreeType(&ftLibrary); - return ftError == 0; -} - -static int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize) -{ - FT_Error ftError; - FONS_NOTUSED(context); - - //font->font.userdata = stash; - ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, 0, &font->font); - return ftError == 0; -} - -static void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap) -{ - *ascent = font->font->ascender; - *descent = font->font->descender; - *lineGap = font->font->height - (*ascent - *descent); -} - -static float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size) -{ - return size / (font->font->ascender - font->font->descender); -} - -static int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint) -{ - return FT_Get_Char_Index(font->font, codepoint); -} - -static int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale, - int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1) -{ - FT_Error ftError; - FT_GlyphSlot ftGlyph; - FT_Fixed advFixed; - FONS_NOTUSED(scale); - - ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender))); - if (ftError) return 0; - ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER); - if (ftError) return 0; - ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed); - if (ftError) return 0; - ftGlyph = font->font->glyph; - *advance = (int)advFixed; - *lsb = (int)ftGlyph->metrics.horiBearingX; - *x0 = ftGlyph->bitmap_left; - *x1 = *x0 + ftGlyph->bitmap.width; - *y0 = -ftGlyph->bitmap_top; - *y1 = *y0 + ftGlyph->bitmap.rows; - return 1; -} - -static void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride, - float scaleX, float scaleY, int glyph) -{ - FT_GlyphSlot ftGlyph = font->font->glyph; - int ftGlyphOffset = 0; - int x, y; - FONS_NOTUSED(outWidth); - FONS_NOTUSED(outHeight); - FONS_NOTUSED(scaleX); - FONS_NOTUSED(scaleY); - FONS_NOTUSED(glyph); // glyph has already been loaded by fons__tt_buildGlyphBitmap - - for ( y = 0; y < ftGlyph->bitmap.rows; y++ ) { - for ( x = 0; x < ftGlyph->bitmap.width; x++ ) { - output[(y * outStride) + x] = ftGlyph->bitmap.buffer[ftGlyphOffset++]; - } - } -} - -static int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2) -{ - FT_Vector ftKerning; - FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning); - return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer -} - -#else - -#define STB_TRUETYPE_IMPLEMENTATION -#define STBTT_STATIC -static void* fons__tmpalloc(size_t size, void* up); -static void fons__tmpfree(void* ptr, void* up); -#define STBTT_malloc(x,u) fons__tmpalloc(x,u) -#define STBTT_free(x,u) fons__tmpfree(x,u) -#include "stb_truetype.h" - -struct FONSttFontImpl { - stbtt_fontinfo font; -}; -typedef struct FONSttFontImpl FONSttFontImpl; - -static int fons__tt_init(FONScontext *context) -{ - FONS_NOTUSED(context); - return 1; -} - -static int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize) -{ - int stbError; - FONS_NOTUSED(dataSize); - - font->font.userdata = context; - stbError = stbtt_InitFont(&font->font, data, 0); - return stbError; -} - -static void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap) -{ - stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap); -} - -static float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size) -{ - return stbtt_ScaleForPixelHeight(&font->font, size); -} - -static int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint) -{ - return stbtt_FindGlyphIndex(&font->font, codepoint); -} - -static int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale, - int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1) -{ - FONS_NOTUSED(size); - stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb); - stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1); - return 1; -} - -static void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride, - float scaleX, float scaleY, int glyph) -{ - stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph); -} - -static int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2) -{ - return stbtt_GetGlyphKernAdvance(&font->font, glyph1, glyph2); -} - -#endif - -#ifndef FONS_SCRATCH_BUF_SIZE -# define FONS_SCRATCH_BUF_SIZE 64000 -#endif -#ifndef FONS_HASH_LUT_SIZE -# define FONS_HASH_LUT_SIZE 256 -#endif -#ifndef FONS_INIT_FONTS -# define FONS_INIT_FONTS 4 -#endif -#ifndef FONS_INIT_GLYPHS -# define FONS_INIT_GLYPHS 256 -#endif -#ifndef FONS_INIT_ATLAS_NODES -# define FONS_INIT_ATLAS_NODES 256 -#endif -#ifndef FONS_VERTEX_COUNT -# define FONS_VERTEX_COUNT 1024 -#endif -#ifndef FONS_MAX_STATES -# define FONS_MAX_STATES 20 -#endif -#ifndef FONS_MAX_FALLBACKS -# define FONS_MAX_FALLBACKS 20 -#endif - -static unsigned int fons__hashint(unsigned int a) -{ - a += ~(a<<15); - a ^= (a>>10); - a += (a<<3); - a ^= (a>>6); - a += ~(a<<11); - a ^= (a>>16); - return a; -} - -static int fons__mini(int a, int b) -{ - return a < b ? a : b; -} - -static int fons__maxi(int a, int b) -{ - return a > b ? a : b; -} - -struct FONSglyph -{ - unsigned int codepoint; - int index; - int next; - short size, blur; - short x0,y0,x1,y1; - short xadv,xoff,yoff; -}; -typedef struct FONSglyph FONSglyph; - -struct FONSfont -{ - FONSttFontImpl font; - char name[64]; - unsigned char* data; - int dataSize; - unsigned char freeData; - float ascender; - float descender; - float lineh; - FONSglyph* glyphs; - int cglyphs; - int nglyphs; - int lut[FONS_HASH_LUT_SIZE]; - int fallbacks[FONS_MAX_FALLBACKS]; - int nfallbacks; -}; -typedef struct FONSfont FONSfont; - -struct FONSstate -{ - int font; - int align; - float size; - unsigned int color; - float blur; - float spacing; -}; -typedef struct FONSstate FONSstate; - -struct FONSatlasNode { - short x, y, width; -}; -typedef struct FONSatlasNode FONSatlasNode; - -struct FONSatlas -{ - int width, height; - FONSatlasNode* nodes; - int nnodes; - int cnodes; -}; -typedef struct FONSatlas FONSatlas; - -struct FONScontext -{ - FONSparams params; - float itw,ith; - unsigned char* texData; - int dirtyRect[4]; - FONSfont** fonts; - FONSatlas* atlas; - int cfonts; - int nfonts; - float verts[FONS_VERTEX_COUNT*2]; - float tcoords[FONS_VERTEX_COUNT*2]; - unsigned int colors[FONS_VERTEX_COUNT]; - int nverts; - unsigned char* scratch; - int nscratch; - FONSstate states[FONS_MAX_STATES]; - int nstates; - void (*handleError)(void* uptr, int error, int val); - void* errorUptr; -}; - -#ifdef STB_TRUETYPE_IMPLEMENTATION - -static void* fons__tmpalloc(size_t size, void* up) -{ - unsigned char* ptr; - FONScontext* stash = (FONScontext*)up; - - // 16-byte align the returned pointer - size = (size + 0xf) & ~0xf; - - if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) { - if (stash->handleError) - stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size); - return NULL; - } - ptr = stash->scratch + stash->nscratch; - stash->nscratch += (int)size; - return ptr; -} - -static void fons__tmpfree(void* ptr, void* up) -{ - (void)ptr; - (void)up; - // empty -} - -#endif // STB_TRUETYPE_IMPLEMENTATION - -// Copyright (c) 2008-2010 Bjoern Hoehrmann -// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. - -#define FONS_UTF8_ACCEPT 0 -#define FONS_UTF8_REJECT 12 - -static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsigned int byte) -{ - static const unsigned char utf8d[] = { - // The first part of the table maps bytes to character classes that - // to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - - // The second part is a transition table that maps a combination - // of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, - }; - - unsigned int type = utf8d[byte]; - - *codep = (*state != FONS_UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); - - *state = utf8d[256 + *state + type]; - return *state; -} - -// Atlas based on Skyline Bin Packer by Jukka Jylänki - -static void fons__deleteAtlas(FONSatlas* atlas) -{ - if (atlas == NULL) return; - if (atlas->nodes != NULL) free(atlas->nodes); - free(atlas); -} - -static FONSatlas* fons__allocAtlas(int w, int h, int nnodes) -{ - FONSatlas* atlas = NULL; - - // Allocate memory for the font stash. - atlas = (FONSatlas*)malloc(sizeof(FONSatlas)); - if (atlas == NULL) goto error; - memset(atlas, 0, sizeof(FONSatlas)); - - atlas->width = w; - atlas->height = h; - - // Allocate space for skyline nodes - atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes); - if (atlas->nodes == NULL) goto error; - memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes); - atlas->nnodes = 0; - atlas->cnodes = nnodes; - - // Init root node. - atlas->nodes[0].x = 0; - atlas->nodes[0].y = 0; - atlas->nodes[0].width = (short)w; - atlas->nnodes++; - - return atlas; - -error: - if (atlas) fons__deleteAtlas(atlas); - return NULL; -} - -static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w) -{ - int i; - // Insert node - if (atlas->nnodes+1 > atlas->cnodes) { - atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2; - atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes, sizeof(FONSatlasNode) * atlas->cnodes); - if (atlas->nodes == NULL) - return 0; - } - for (i = atlas->nnodes; i > idx; i--) - atlas->nodes[i] = atlas->nodes[i-1]; - atlas->nodes[idx].x = (short)x; - atlas->nodes[idx].y = (short)y; - atlas->nodes[idx].width = (short)w; - atlas->nnodes++; - - return 1; -} - -static void fons__atlasRemoveNode(FONSatlas* atlas, int idx) -{ - int i; - if (atlas->nnodes == 0) return; - for (i = idx; i < atlas->nnodes-1; i++) - atlas->nodes[i] = atlas->nodes[i+1]; - atlas->nnodes--; -} - -static void fons__atlasExpand(FONSatlas* atlas, int w, int h) -{ - // Insert node for empty space - if (w > atlas->width) - fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width); - atlas->width = w; - atlas->height = h; -} - -static void fons__atlasReset(FONSatlas* atlas, int w, int h) -{ - atlas->width = w; - atlas->height = h; - atlas->nnodes = 0; - - // Init root node. - atlas->nodes[0].x = 0; - atlas->nodes[0].y = 0; - atlas->nodes[0].width = (short)w; - atlas->nnodes++; -} - -static int fons__atlasAddSkylineLevel(FONSatlas* atlas, int idx, int x, int y, int w, int h) -{ - int i; - - // Insert new node - if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0) - return 0; - - // Delete skyline segments that fall under the shadow of the new segment. - for (i = idx+1; i < atlas->nnodes; i++) { - if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) { - int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x; - atlas->nodes[i].x += (short)shrink; - atlas->nodes[i].width -= (short)shrink; - if (atlas->nodes[i].width <= 0) { - fons__atlasRemoveNode(atlas, i); - i--; - } else { - break; - } - } else { - break; - } - } - - // Merge same height skyline segments that are next to each other. - for (i = 0; i < atlas->nnodes-1; i++) { - if (atlas->nodes[i].y == atlas->nodes[i+1].y) { - atlas->nodes[i].width += atlas->nodes[i+1].width; - fons__atlasRemoveNode(atlas, i+1); - i--; - } - } - - return 1; -} - -static int fons__atlasRectFits(FONSatlas* atlas, int i, int w, int h) -{ - // Checks if there is enough space at the location of skyline span 'i', - // and return the max height of all skyline spans under that at that location, - // (think tetris block being dropped at that position). Or -1 if no space found. - int x = atlas->nodes[i].x; - int y = atlas->nodes[i].y; - int spaceLeft; - if (x + w > atlas->width) - return -1; - spaceLeft = w; - while (spaceLeft > 0) { - if (i == atlas->nnodes) return -1; - y = fons__maxi(y, atlas->nodes[i].y); - if (y + h > atlas->height) return -1; - spaceLeft -= atlas->nodes[i].width; - ++i; - } - return y; -} - -static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry) -{ - int besth = atlas->height, bestw = atlas->width, besti = -1; - int bestx = -1, besty = -1, i; - - // Bottom left fit heuristic. - for (i = 0; i < atlas->nnodes; i++) { - int y = fons__atlasRectFits(atlas, i, rw, rh); - if (y != -1) { - if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) { - besti = i; - bestw = atlas->nodes[i].width; - besth = y + rh; - bestx = atlas->nodes[i].x; - besty = y; - } - } - } - - if (besti == -1) - return 0; - - // Perform the actual packing. - if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0) - return 0; - - *rx = bestx; - *ry = besty; - - return 1; -} - -static void fons__addWhiteRect(FONScontext* stash, int w, int h) -{ - int x, y, gx, gy; - unsigned char* dst; - if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0) - return; - - // Rasterize - dst = &stash->texData[gx + gy * stash->params.width]; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) - dst[x] = 0xff; - dst += stash->params.width; - } - - stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx); - stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy); - stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w); - stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h); -} - -FONScontext* fonsCreateInternal(FONSparams* params) -{ - FONScontext* stash = NULL; - - // Allocate memory for the font stash. - stash = (FONScontext*)malloc(sizeof(FONScontext)); - if (stash == NULL) goto error; - memset(stash, 0, sizeof(FONScontext)); - - stash->params = *params; - - // Allocate scratch buffer. - stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE); - if (stash->scratch == NULL) goto error; - - // Initialize implementation library - if (!fons__tt_init(stash)) goto error; - - if (stash->params.renderCreate != NULL) { - if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0) - goto error; - } - - stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES); - if (stash->atlas == NULL) goto error; - - // Allocate space for fonts. - stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS); - if (stash->fonts == NULL) goto error; - memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS); - stash->cfonts = FONS_INIT_FONTS; - stash->nfonts = 0; - - // Create texture for the cache. - stash->itw = 1.0f/stash->params.width; - stash->ith = 1.0f/stash->params.height; - stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height); - if (stash->texData == NULL) goto error; - memset(stash->texData, 0, stash->params.width * stash->params.height); - - stash->dirtyRect[0] = stash->params.width; - stash->dirtyRect[1] = stash->params.height; - stash->dirtyRect[2] = 0; - stash->dirtyRect[3] = 0; - - // Add white rect at 0,0 for debug drawing. - fons__addWhiteRect(stash, 2,2); - - fonsPushState(stash); - fonsClearState(stash); - - return stash; - -error: - fonsDeleteInternal(stash); - return NULL; -} - -static FONSstate* fons__getState(FONScontext* stash) -{ - return &stash->states[stash->nstates-1]; -} - -int fonsAddFallbackFont(FONScontext* stash, int base, int fallback) -{ - FONSfont* baseFont = stash->fonts[base]; - if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) { - baseFont->fallbacks[baseFont->nfallbacks++] = fallback; - return 1; - } - return 0; -} - -void fonsSetSize(FONScontext* stash, float size) -{ - fons__getState(stash)->size = size; -} - -void fonsSetColor(FONScontext* stash, unsigned int color) -{ - fons__getState(stash)->color = color; -} - -void fonsSetSpacing(FONScontext* stash, float spacing) -{ - fons__getState(stash)->spacing = spacing; -} - -void fonsSetBlur(FONScontext* stash, float blur) -{ - fons__getState(stash)->blur = blur; -} - -void fonsSetAlign(FONScontext* stash, int align) -{ - fons__getState(stash)->align = align; -} - -void fonsSetFont(FONScontext* stash, int font) -{ - fons__getState(stash)->font = font; -} - -void fonsPushState(FONScontext* stash) -{ - if (stash->nstates >= FONS_MAX_STATES) { - if (stash->handleError) - stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0); - return; - } - if (stash->nstates > 0) - memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate)); - stash->nstates++; -} - -void fonsPopState(FONScontext* stash) -{ - if (stash->nstates <= 1) { - if (stash->handleError) - stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0); - return; - } - stash->nstates--; -} - -void fonsClearState(FONScontext* stash) -{ - FONSstate* state = fons__getState(stash); - state->size = 12.0f; - state->color = 0xffffffff; - state->font = 0; - state->blur = 0; - state->spacing = 0; - state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE; -} - -static void fons__freeFont(FONSfont* font) -{ - if (font == NULL) return; - if (font->glyphs) free(font->glyphs); - if (font->freeData && font->data) free(font->data); - free(font); -} - -static int fons__allocFont(FONScontext* stash) -{ - FONSfont* font = NULL; - if (stash->nfonts+1 > stash->cfonts) { - stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2; - stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts); - if (stash->fonts == NULL) - return -1; - } - font = (FONSfont*)malloc(sizeof(FONSfont)); - if (font == NULL) goto error; - memset(font, 0, sizeof(FONSfont)); - - font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS); - if (font->glyphs == NULL) goto error; - font->cglyphs = FONS_INIT_GLYPHS; - font->nglyphs = 0; - - stash->fonts[stash->nfonts++] = font; - return stash->nfonts-1; - -error: - fons__freeFont(font); - - return FONS_INVALID; -} - -int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData) -{ - int i, ascent, descent, fh, lineGap; - FONSfont* font; - - int idx = fons__allocFont(stash); - if (idx == FONS_INVALID) - return FONS_INVALID; - - font = stash->fonts[idx]; - - strncpy(font->name, name, sizeof(font->name)); - font->name[sizeof(font->name)-1] = '\0'; - - // Init hash lookup. - for (i = 0; i < FONS_HASH_LUT_SIZE; ++i) - font->lut[i] = -1; - - // Read in the font data. - font->dataSize = dataSize; - font->data = data; - font->freeData = (unsigned char)freeData; - - // Init font - stash->nscratch = 0; - if (!fons__tt_loadFont(stash, &font->font, data, dataSize)) goto error; - - // Store normalized line height. The real line height is got - // by multiplying the lineh by font size. - fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap); - fh = ascent - descent; - font->ascender = (float)ascent / (float)fh; - font->descender = (float)descent / (float)fh; - font->lineh = (float)(fh + lineGap) / (float)fh; - - return idx; - -error: - fons__freeFont(font); - stash->nfonts--; - return FONS_INVALID; -} - -int fonsGetFontByName(FONScontext* s, const char* name) -{ - int i; - for (i = 0; i < s->nfonts; i++) { - if (strcmp(s->fonts[i]->name, name) == 0) - return i; - } - return FONS_INVALID; -} - - -static FONSglyph* fons__allocGlyph(FONSfont* font) -{ - if (font->nglyphs+1 > font->cglyphs) { - font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2; - font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs); - if (font->glyphs == NULL) return NULL; - } - font->nglyphs++; - return &font->glyphs[font->nglyphs-1]; -} - - -// Based on Exponential blur, Jani Huhtanen, 2006 - -#define APREC 16 -#define ZPREC 7 - -static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha) -{ - int x, y; - for (y = 0; y < h; y++) { - int z = 0; // force zero border - for (x = 1; x < w; x++) { - z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC; - dst[x] = (unsigned char)(z >> ZPREC); - } - dst[w-1] = 0; // force zero border - z = 0; - for (x = w-2; x >= 0; x--) { - z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC; - dst[x] = (unsigned char)(z >> ZPREC); - } - dst[0] = 0; // force zero border - dst += dstStride; - } -} - -static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha) -{ - int x, y; - for (x = 0; x < w; x++) { - int z = 0; // force zero border - for (y = dstStride; y < h*dstStride; y += dstStride) { - z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC; - dst[y] = (unsigned char)(z >> ZPREC); - } - dst[(h-1)*dstStride] = 0; // force zero border - z = 0; - for (y = (h-2)*dstStride; y >= 0; y -= dstStride) { - z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC; - dst[y] = (unsigned char)(z >> ZPREC); - } - dst[0] = 0; // force zero border - dst++; - } -} - - -static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur) -{ - int alpha; - float sigma; - (void)stash; - - if (blur < 1) - return; - // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity) - sigma = (float)blur * 0.57735f; // 1 / sqrt(3) - alpha = (int)((1< 20) iblur = 20; - pad = iblur+2; - - // Reset allocator. - stash->nscratch = 0; - - // Find code point and size. - h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1); - i = font->lut[h]; - while (i != -1) { - if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur) - return &font->glyphs[i]; - i = font->glyphs[i].next; - } - - // Could not find glyph, create it. - g = fons__tt_getGlyphIndex(&font->font, codepoint); - // Try to find the glyph in fallback fonts. - if (g == 0) { - for (i = 0; i < font->nfallbacks; ++i) { - FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]]; - int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint); - if (fallbackIndex != 0) { - g = fallbackIndex; - renderFont = fallbackFont; - break; - } - } - // It is possible that we did not find a fallback glyph. - // In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph. - } - scale = fons__tt_getPixelHeightScale(&renderFont->font, size); - fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1); - gw = x1-x0 + pad*2; - gh = y1-y0 + pad*2; - - // Find free spot for the rect in the atlas - added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy); - if (added == 0 && stash->handleError != NULL) { - // Atlas is full, let the user to resize the atlas (or not), and try again. - stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0); - added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy); - } - if (added == 0) return NULL; - - // Init glyph. - glyph = fons__allocGlyph(font); - glyph->codepoint = codepoint; - glyph->size = isize; - glyph->blur = iblur; - glyph->index = g; - glyph->x0 = (short)gx; - glyph->y0 = (short)gy; - glyph->x1 = (short)(glyph->x0+gw); - glyph->y1 = (short)(glyph->y0+gh); - glyph->xadv = (short)(scale * advance * 10.0f); - glyph->xoff = (short)(x0 - pad); - glyph->yoff = (short)(y0 - pad); - glyph->next = 0; - - // Insert char to hash lookup. - glyph->next = font->lut[h]; - font->lut[h] = font->nglyphs-1; - - // Rasterize - dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width]; - fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g); - - // Make sure there is one pixel empty border. - dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; - for (y = 0; y < gh; y++) { - dst[y*stash->params.width] = 0; - dst[gw-1 + y*stash->params.width] = 0; - } - for (x = 0; x < gw; x++) { - dst[x] = 0; - dst[x + (gh-1)*stash->params.width] = 0; - } - - // Debug code to color the glyph background -/* unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; - for (y = 0; y < gh; y++) { - for (x = 0; x < gw; x++) { - int a = (int)fdst[x+y*stash->params.width] + 20; - if (a > 255) a = 255; - fdst[x+y*stash->params.width] = a; - } - }*/ - - // Blur - if (iblur > 0) { - stash->nscratch = 0; - bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; - fons__blur(stash, bdst, gw,gh, stash->params.width, iblur); - } - - stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0); - stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0); - stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1); - stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1); - - return glyph; -} - -static void fons__getQuad(FONScontext* stash, FONSfont* font, - int prevGlyphIndex, FONSglyph* glyph, - float scale, float spacing, float* x, float* y, FONSquad* q) -{ - float rx,ry,xoff,yoff,x0,y0,x1,y1; - - if (prevGlyphIndex != -1) { - float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale; - *x += (int)(adv + spacing + 0.5f); - } - - // Each glyph has 2px border to allow good interpolation, - // one pixel to prevent leaking, and one to allow good interpolation for rendering. - // Inset the texture region by one pixel for correct interpolation. - xoff = (short)(glyph->xoff+1); - yoff = (short)(glyph->yoff+1); - x0 = (float)(glyph->x0+1); - y0 = (float)(glyph->y0+1); - x1 = (float)(glyph->x1-1); - y1 = (float)(glyph->y1-1); - - if (stash->params.flags & FONS_ZERO_TOPLEFT) { - rx = (float)(int)(*x + xoff); - ry = (float)(int)(*y + yoff); - - q->x0 = rx; - q->y0 = ry; - q->x1 = rx + x1 - x0; - q->y1 = ry + y1 - y0; - - q->s0 = x0 * stash->itw; - q->t0 = y0 * stash->ith; - q->s1 = x1 * stash->itw; - q->t1 = y1 * stash->ith; - } else { - rx = (float)(int)(*x + xoff); - ry = (float)(int)(*y - yoff); - - q->x0 = rx; - q->y0 = ry; - q->x1 = rx + x1 - x0; - q->y1 = ry - y1 + y0; - - q->s0 = x0 * stash->itw; - q->t0 = y0 * stash->ith; - q->s1 = x1 * stash->itw; - q->t1 = y1 * stash->ith; - } - - *x += (int)(glyph->xadv / 10.0f + 0.5f); -} - -static void fons__flush(FONScontext* stash) -{ - // Flush texture - if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) { - if (stash->params.renderUpdate != NULL) - stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData); - // Reset dirty rect - stash->dirtyRect[0] = stash->params.width; - stash->dirtyRect[1] = stash->params.height; - stash->dirtyRect[2] = 0; - stash->dirtyRect[3] = 0; - } - - // Flush triangles - if (stash->nverts > 0) { - if (stash->params.renderDraw != NULL) - stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts); - stash->nverts = 0; - } -} - -static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned int c) -{ - stash->verts[stash->nverts*2+0] = x; - stash->verts[stash->nverts*2+1] = y; - stash->tcoords[stash->nverts*2+0] = s; - stash->tcoords[stash->nverts*2+1] = t; - stash->colors[stash->nverts] = c; - stash->nverts++; -} - -static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize) -{ - if (stash->params.flags & FONS_ZERO_TOPLEFT) { - if (align & FONS_ALIGN_TOP) { - return font->ascender * (float)isize/10.0f; - } else if (align & FONS_ALIGN_MIDDLE) { - return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f; - } else if (align & FONS_ALIGN_BASELINE) { - return 0.0f; - } else if (align & FONS_ALIGN_BOTTOM) { - return font->descender * (float)isize/10.0f; - } - } else { - if (align & FONS_ALIGN_TOP) { - return -font->ascender * (float)isize/10.0f; - } else if (align & FONS_ALIGN_MIDDLE) { - return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f; - } else if (align & FONS_ALIGN_BASELINE) { - return 0.0f; - } else if (align & FONS_ALIGN_BOTTOM) { - return -font->descender * (float)isize/10.0f; - } - } - return 0.0; -} - -FONS_DEF float fonsDrawText(FONScontext* stash, - float x, float y, - const char* str, const char* end) -{ - FONSstate* state = fons__getState(stash); - unsigned int codepoint; - unsigned int utf8state = 0; - FONSglyph* glyph = NULL; - FONSquad q; - int prevGlyphIndex = -1; - short isize = (short)(state->size*10.0f); - short iblur = (short)state->blur; - float scale; - FONSfont* font; - float width; - - if (stash == NULL) return x; - if (state->font < 0 || state->font >= stash->nfonts) return x; - font = stash->fonts[state->font]; - if (font->data == NULL) return x; - - scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f); - - if (end == NULL) - end = str + strlen(str); - - // Align horizontally - if (state->align & FONS_ALIGN_LEFT) { - // empty - } else if (state->align & FONS_ALIGN_RIGHT) { - width = fonsTextBounds(stash, x,y, str, end, NULL); - x -= width; - } else if (state->align & FONS_ALIGN_CENTER) { - width = fonsTextBounds(stash, x,y, str, end, NULL); - x -= width * 0.5f; - } - // Align vertically. - y += fons__getVertAlign(stash, font, state->align, isize); - - for (; str != end; ++str) { - if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) - continue; - glyph = fons__getGlyph(stash, font, codepoint, isize, iblur); - if (glyph != NULL) { - fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q); - - if (stash->nverts+6 > FONS_VERTEX_COUNT) - fons__flush(stash); - - fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color); - fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color); - fons__vertex(stash, q.x1, q.y0, q.s1, q.t0, state->color); - - fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color); - fons__vertex(stash, q.x0, q.y1, q.s0, q.t1, state->color); - fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color); - } - prevGlyphIndex = glyph != NULL ? glyph->index : -1; - } - fons__flush(stash); - - return x; -} - -FONS_DEF int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, - float x, float y, const char* str, const char* end) -{ - FONSstate* state = fons__getState(stash); - float width; - - memset(iter, 0, sizeof(*iter)); - - if (stash == NULL) return 0; - if (state->font < 0 || state->font >= stash->nfonts) return 0; - iter->font = stash->fonts[state->font]; - if (iter->font->data == NULL) return 0; - - iter->isize = (short)(state->size*10.0f); - iter->iblur = (short)state->blur; - iter->scale = fons__tt_getPixelHeightScale(&iter->font->font, (float)iter->isize/10.0f); - - // Align horizontally - if (state->align & FONS_ALIGN_LEFT) { - // empty - } else if (state->align & FONS_ALIGN_RIGHT) { - width = fonsTextBounds(stash, x,y, str, end, NULL); - x -= width; - } else if (state->align & FONS_ALIGN_CENTER) { - width = fonsTextBounds(stash, x,y, str, end, NULL); - x -= width * 0.5f; - } - // Align vertically. - y += fons__getVertAlign(stash, iter->font, state->align, iter->isize); - - if (end == NULL) - end = str + strlen(str); - - iter->x = iter->nextx = x; - iter->y = iter->nexty = y; - iter->spacing = state->spacing; - iter->str = str; - iter->next = str; - iter->end = end; - iter->codepoint = 0; - iter->prevGlyphIndex = -1; - - return 1; -} - -FONS_DEF int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad) -{ - FONSglyph* glyph = NULL; - const char* str = iter->next; - iter->str = iter->next; - - if (str == iter->end) - return 0; - - for (; str != iter->end; str++) { - if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str)) - continue; - str++; - // Get glyph and quad - iter->x = iter->nextx; - iter->y = iter->nexty; - glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur); - if (glyph != NULL) - fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad); - iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1; - break; - } - iter->next = str; - - return 1; -} - -FONS_DEF void fonsDrawDebug(FONScontext* stash, float x, float y) -{ - int i; - int w = stash->params.width; - int h = stash->params.height; - float u = w == 0 ? 0 : (1.0f / w); - float v = h == 0 ? 0 : (1.0f / h); - - if (stash->nverts+6+6 > FONS_VERTEX_COUNT) - fons__flush(stash); - - // Draw background - fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff); - fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff); - fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff); - - fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff); - fons__vertex(stash, x+0, y+h, u, v, 0x0fffffff); - fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff); - - // Draw texture - fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff); - fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff); - fons__vertex(stash, x+w, y+0, 1, 0, 0xffffffff); - - fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff); - fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff); - fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff); - - // Drawbug draw atlas - for (i = 0; i < stash->atlas->nnodes; i++) { - FONSatlasNode* n = &stash->atlas->nodes[i]; - - if (stash->nverts+6 > FONS_VERTEX_COUNT) - fons__flush(stash); - - fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff); - fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff); - fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff); - - fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff); - fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc00000ff); - fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff); - } - - fons__flush(stash); -} - -FONS_DEF float fonsTextBounds(FONScontext* stash, - float x, float y, - const char* str, const char* end, - float* bounds) -{ - FONSstate* state = fons__getState(stash); - unsigned int codepoint; - unsigned int utf8state = 0; - FONSquad q; - FONSglyph* glyph = NULL; - int prevGlyphIndex = -1; - short isize = (short)(state->size*10.0f); - short iblur = (short)state->blur; - float scale; - FONSfont* font; - float startx, advance; - float minx, miny, maxx, maxy; - - if (stash == NULL) return 0; - if (state->font < 0 || state->font >= stash->nfonts) return 0; - font = stash->fonts[state->font]; - if (font->data == NULL) return 0; - - scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f); - - // Align vertically. - y += fons__getVertAlign(stash, font, state->align, isize); - - minx = maxx = x; - miny = maxy = y; - startx = x; - - if (end == NULL) - end = str + strlen(str); - - for (; str != end; ++str) { - if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) - continue; - glyph = fons__getGlyph(stash, font, codepoint, isize, iblur); - if (glyph != NULL) { - fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q); - if (q.x0 < minx) minx = q.x0; - if (q.x1 > maxx) maxx = q.x1; - if (stash->params.flags & FONS_ZERO_TOPLEFT) { - if (q.y0 < miny) miny = q.y0; - if (q.y1 > maxy) maxy = q.y1; - } else { - if (q.y1 < miny) miny = q.y1; - if (q.y0 > maxy) maxy = q.y0; - } - } - prevGlyphIndex = glyph != NULL ? glyph->index : -1; - } - - advance = x - startx; - - // Align horizontally - if (state->align & FONS_ALIGN_LEFT) { - // empty - } else if (state->align & FONS_ALIGN_RIGHT) { - minx -= advance; - maxx -= advance; - } else if (state->align & FONS_ALIGN_CENTER) { - minx -= advance * 0.5f; - maxx -= advance * 0.5f; - } - - if (bounds) { - bounds[0] = minx; - bounds[1] = miny; - bounds[2] = maxx; - bounds[3] = maxy; - } - - return advance; -} - -FONS_DEF void fonsVertMetrics(FONScontext* stash, - float* ascender, float* descender, float* lineh) -{ - FONSfont* font; - FONSstate* state = fons__getState(stash); - short isize; - - if (stash == NULL) return; - if (state->font < 0 || state->font >= stash->nfonts) return; - font = stash->fonts[state->font]; - isize = (short)(state->size*10.0f); - if (font->data == NULL) return; - - if (ascender) - *ascender = font->ascender*isize/10.0f; - if (descender) - *descender = font->descender*isize/10.0f; - if (lineh) - *lineh = font->lineh*isize/10.0f; -} - -FONS_DEF void fonsLineBounds(FONScontext* stash, float y, float* miny, float* maxy) -{ - FONSfont* font; - FONSstate* state = fons__getState(stash); - short isize; - - if (stash == NULL) return; - if (state->font < 0 || state->font >= stash->nfonts) return; - font = stash->fonts[state->font]; - isize = (short)(state->size*10.0f); - if (font->data == NULL) return; - - y += fons__getVertAlign(stash, font, state->align, isize); - - if (stash->params.flags & FONS_ZERO_TOPLEFT) { - *miny = y - font->ascender * (float)isize/10.0f; - *maxy = *miny + font->lineh*isize/10.0f; - } else { - *maxy = y + font->descender * (float)isize/10.0f; - *miny = *maxy - font->lineh*isize/10.0f; - } -} - -FONS_DEF const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height) -{ - if (width != NULL) - *width = stash->params.width; - if (height != NULL) - *height = stash->params.height; - return stash->texData; -} - -FONS_DEF int fonsValidateTexture(FONScontext* stash, int* dirty) -{ - if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) { - dirty[0] = stash->dirtyRect[0]; - dirty[1] = stash->dirtyRect[1]; - dirty[2] = stash->dirtyRect[2]; - dirty[3] = stash->dirtyRect[3]; - // Reset dirty rect - stash->dirtyRect[0] = stash->params.width; - stash->dirtyRect[1] = stash->params.height; - stash->dirtyRect[2] = 0; - stash->dirtyRect[3] = 0; - return 1; - } - return 0; -} - -FONS_DEF void fonsDeleteInternal(FONScontext* stash) -{ - int i; - if (stash == NULL) return; - - if (stash->params.renderDelete) - stash->params.renderDelete(stash->params.userPtr); - - for (i = 0; i < stash->nfonts; ++i) - fons__freeFont(stash->fonts[i]); - - if (stash->atlas) fons__deleteAtlas(stash->atlas); - if (stash->fonts) free(stash->fonts); - if (stash->texData) free(stash->texData); - if (stash->scratch) free(stash->scratch); - free(stash); -} - -FONS_DEF void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr) -{ - if (stash == NULL) return; - stash->handleError = callback; - stash->errorUptr = uptr; -} - -FONS_DEF void fonsGetAtlasSize(FONScontext* stash, int* width, int* height) -{ - if (stash == NULL) return; - *width = stash->params.width; - *height = stash->params.height; -} - -FONS_DEF int fonsExpandAtlas(FONScontext* stash, int width, int height) -{ - int i, maxy = 0; - unsigned char* data = NULL; - if (stash == NULL) return 0; - - width = fons__maxi(width, stash->params.width); - height = fons__maxi(height, stash->params.height); - - if (width == stash->params.width && height == stash->params.height) - return 1; - - // Flush pending glyphs. - fons__flush(stash); - - // Create new texture - if (stash->params.renderResize != NULL) { - if (stash->params.renderResize(stash->params.userPtr, width, height) == 0) - return 0; - } - // Copy old texture data over. - data = (unsigned char*)malloc(width * height); - if (data == NULL) - return 0; - for (i = 0; i < stash->params.height; i++) { - unsigned char* dst = &data[i*width]; - unsigned char* src = &stash->texData[i*stash->params.width]; - memcpy(dst, src, stash->params.width); - if (width > stash->params.width) - memset(dst+stash->params.width, 0, width - stash->params.width); - } - if (height > stash->params.height) - memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width); - - free(stash->texData); - stash->texData = data; - - // Increase atlas size - fons__atlasExpand(stash->atlas, width, height); - - // Add existing data as dirty. - for (i = 0; i < stash->atlas->nnodes; i++) - maxy = fons__maxi(maxy, stash->atlas->nodes[i].y); - stash->dirtyRect[0] = 0; - stash->dirtyRect[1] = 0; - stash->dirtyRect[2] = stash->params.width; - stash->dirtyRect[3] = maxy; - - stash->params.width = width; - stash->params.height = height; - stash->itw = 1.0f/stash->params.width; - stash->ith = 1.0f/stash->params.height; - - return 1; -} - -FONS_DEF int fonsResetAtlas(FONScontext* stash, int width, int height) -{ - int i, j; - if (stash == NULL) return 0; - - // Flush pending glyphs. - fons__flush(stash); - - // Create new texture - if (stash->params.renderResize != NULL) { - if (stash->params.renderResize(stash->params.userPtr, width, height) == 0) - return 0; - } - - // Reset atlas - fons__atlasReset(stash->atlas, width, height); - - // Clear texture data. - stash->texData = (unsigned char*)realloc(stash->texData, width * height); - if (stash->texData == NULL) return 0; - memset(stash->texData, 0, width * height); - - // Reset dirty rect - stash->dirtyRect[0] = width; - stash->dirtyRect[1] = height; - stash->dirtyRect[2] = 0; - stash->dirtyRect[3] = 0; - - // Reset cached glyphs - for (i = 0; i < stash->nfonts; i++) { - FONSfont* font = stash->fonts[i]; - font->nglyphs = 0; - for (j = 0; j < FONS_HASH_LUT_SIZE; j++) - font->lut[j] = -1; - } - - stash->params.width = width; - stash->params.height = height; - stash->itw = 1.0f/stash->params.width; - stash->ith = 1.0f/stash->params.height; - - // Add white rect at 0,0 for debug drawing. - fons__addWhiteRect(stash, 2,2); - - return 1; -} - -#endif // FONTSTASH_IMPLEMENTATION diff --git a/source/engine/thirdparty/sokol/tests/ext/nuklear.c b/source/engine/thirdparty/sokol/tests/ext/nuklear.c deleted file mode 100644 index 52712f3..0000000 --- a/source/engine/thirdparty/sokol/tests/ext/nuklear.c +++ /dev/null @@ -1,33 +0,0 @@ -// include nuklear.h before the sokol_nuklear.h implementation -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_IMPLEMENTATION - -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Wunknown-warning-option" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wsign-conversion" -#pragma GCC diagnostic ignored "-Wnull-pointer-subtraction" -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#pragma GCC diagnostic ignored "-Wsign-conversion" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // sprintf,fopen,localtime: This function or variable may be unsafe -#pragma warning(disable:4127) // conditional expression is constant -#pragma warning(disable:4100) // unreferenced formal parameter -#pragma warning(disable:4701) // potentially uninitialized local variable used -#endif -#include "nuklear.h" -#if defined(_MSC_VER) -#pragma warning(pop) -#endif diff --git a/source/engine/thirdparty/sokol/tests/ext/nuklear.h b/source/engine/thirdparty/sokol/tests/ext/nuklear.h deleted file mode 100644 index 6855f6f..0000000 --- a/source/engine/thirdparty/sokol/tests/ext/nuklear.h +++ /dev/null @@ -1,29499 +0,0 @@ -/* -/// # Nuklear -/// ![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif) -/// -/// ## Contents -/// 1. About section -/// 2. Highlights section -/// 3. Features section -/// 4. Usage section -/// 1. Flags section -/// 2. Constants section -/// 3. Dependencies section -/// 5. Example section -/// 6. API section -/// 1. Context section -/// 2. Input section -/// 3. Drawing section -/// 4. Window section -/// 5. Layouting section -/// 6. Groups section -/// 7. Tree section -/// 8. Properties section -/// 7. License section -/// 8. Changelog section -/// 9. Gallery section -/// 10. Credits section -/// -/// ## About -/// This is a minimal state immediate mode graphical user interface toolkit -/// written in ANSI C and licensed under public domain. It was designed as a simple -/// embeddable user interface for application and does not have any dependencies, -/// a default renderbackend or OS window and input handling but instead provides a very modular -/// library approach by using simple input state for input and draw -/// commands describing primitive shapes as output. So instead of providing a -/// layered library that tries to abstract over a number of platform and -/// render backends it only focuses on the actual UI. -/// -/// ## Highlights -/// - Graphical user interface toolkit -/// - Single header library -/// - Written in C89 (a.k.a. ANSI C or ISO C90) -/// - Small codebase (~18kLOC) -/// - Focus on portability, efficiency and simplicity -/// - No dependencies (not even the standard library if not wanted) -/// - Fully skinnable and customizable -/// - Low memory footprint with total memory control if needed or wanted -/// - UTF-8 support -/// - No global or hidden state -/// - Customizable library modules (you can compile and use only what you need) -/// - Optional font baker and vertex buffer output -/// -/// ## Features -/// - Absolutely no platform dependent code -/// - Memory management control ranging from/to -/// - Ease of use by allocating everything from standard library -/// - Control every byte of memory inside the library -/// - Font handling control ranging from/to -/// - Use your own font implementation for everything -/// - Use this libraries internal font baking and handling API -/// - Drawing output control ranging from/to -/// - Simple shapes for more high level APIs which already have drawing capabilities -/// - Hardware accessible anti-aliased vertex buffer output -/// - Customizable colors and properties ranging from/to -/// - Simple changes to color by filling a simple color table -/// - Complete control with ability to use skinning to decorate widgets -/// - Bendable UI library with widget ranging from/to -/// - Basic widgets like buttons, checkboxes, slider, ... -/// - Advanced widget like abstract comboboxes, contextual menus,... -/// - Compile time configuration to only compile what you need -/// - Subset which can be used if you do not want to link or use the standard library -/// - Can be easily modified to only update on user input instead of frame updates -/// -/// ## Usage -/// This library is self contained in one single header file and can be used either -/// in header only mode or in implementation mode. The header only mode is used -/// by default when included and allows including this header in other headers -/// and does not contain the actual implementation.

-/// -/// The implementation mode requires to define the preprocessor macro -/// NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C -/// #define NK_IMPLEMENTATION -/// #include "nuklear.h" -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Also optionally define the symbols listed in the section "OPTIONAL DEFINES" -/// below in header and implementation mode if you want to use additional functionality -/// or need more control over the library. -/// -/// !!! WARNING -/// Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions. -/// -/// ### Flags -/// Flag | Description -/// --------------------------------|------------------------------------------ -/// NK_PRIVATE | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation -/// NK_INCLUDE_FIXED_TYPES | If defined it will include header `` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself. -/// NK_INCLUDE_DEFAULT_ALLOCATOR | If defined it will include header `` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management. -/// NK_INCLUDE_STANDARD_IO | If defined it will include header `` and provide additional functions depending on file loading. -/// NK_INCLUDE_STANDARD_VARARGS | If defined it will include header and provide additional functions depending on file loading. -/// NK_INCLUDE_STANDARD_BOOL | If defined it will include header `` for nk_bool otherwise nuklear defines nk_bool as int. -/// NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,... -/// NK_INCLUDE_FONT_BAKING | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it. -/// NK_INCLUDE_DEFAULT_FONT | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font -/// NK_INCLUDE_COMMAND_USERDATA | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures. -/// NK_BUTTON_TRIGGER_ON_RELEASE | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released. -/// NK_ZERO_COMMAND_MEMORY | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame. -/// NK_UINT_DRAW_INDEX | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit -/// NK_KEYSTATE_BASED_INPUT | Define this if your backend uses key state for each frame rather than key press/release events -/// -/// !!! WARNING -/// The following flags will pull in the standard C library: -/// - NK_INCLUDE_DEFAULT_ALLOCATOR -/// - NK_INCLUDE_STANDARD_IO -/// - NK_INCLUDE_STANDARD_VARARGS -/// -/// !!! WARNING -/// The following flags if defined need to be defined for both header and implementation: -/// - NK_INCLUDE_FIXED_TYPES -/// - NK_INCLUDE_DEFAULT_ALLOCATOR -/// - NK_INCLUDE_STANDARD_VARARGS -/// - NK_INCLUDE_STANDARD_BOOL -/// - NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/// - NK_INCLUDE_FONT_BAKING -/// - NK_INCLUDE_DEFAULT_FONT -/// - NK_INCLUDE_STANDARD_VARARGS -/// - NK_INCLUDE_COMMAND_USERDATA -/// - NK_UINT_DRAW_INDEX -/// -/// ### Constants -/// Define | Description -/// --------------------------------|--------------------------------------- -/// NK_BUFFER_DEFAULT_INITIAL_SIZE | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it. -/// NK_MAX_NUMBER_BUFFER | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient. -/// NK_INPUT_MAX | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient. -/// -/// !!! WARNING -/// The following constants if defined need to be defined for both header and implementation: -/// - NK_MAX_NUMBER_BUFFER -/// - NK_BUFFER_DEFAULT_INITIAL_SIZE -/// - NK_INPUT_MAX -/// -/// ### Dependencies -/// Function | Description -/// ------------|--------------------------------------------------------------- -/// NK_ASSERT | If you don't define this, nuklear will use with assert(). -/// NK_MEMSET | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version. -/// NK_MEMCPY | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version. -/// NK_SQRT | You can define this to 'sqrt' or your own sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version. -/// NK_SIN | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation. -/// NK_COS | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation. -/// NK_STRTOD | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!). -/// NK_DTOA | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!). -/// NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe. -/// -/// !!! WARNING -/// The following dependencies will pull in the standard C library if not redefined: -/// - NK_ASSERT -/// -/// !!! WARNING -/// The following dependencies if defined need to be defined for both header and implementation: -/// - NK_ASSERT -/// -/// !!! WARNING -/// The following dependencies if defined need to be defined only for the implementation part: -/// - NK_MEMSET -/// - NK_MEMCPY -/// - NK_SQRT -/// - NK_SIN -/// - NK_COS -/// - NK_STRTOD -/// - NK_DTOA -/// - NK_VSNPRINTF -/// -/// ## Example -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// // init gui state -/// enum {EASY, HARD}; -/// static int op = EASY; -/// static float value = 0.6f; -/// static int i = 20; -/// struct nk_context ctx; -/// -/// nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font); -/// if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220), -/// NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { -/// // fixed widget pixel width -/// nk_layout_row_static(&ctx, 30, 80, 1); -/// if (nk_button_label(&ctx, "button")) { -/// // event handling -/// } -/// -/// // fixed widget window ratio width -/// nk_layout_row_dynamic(&ctx, 30, 2); -/// if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY; -/// if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD; -/// -/// // custom widget pixel width -/// nk_layout_row_begin(&ctx, NK_STATIC, 30, 2); -/// { -/// nk_layout_row_push(&ctx, 50); -/// nk_label(&ctx, "Volume:", NK_TEXT_LEFT); -/// nk_layout_row_push(&ctx, 110); -/// nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f); -/// } -/// nk_layout_row_end(&ctx); -/// } -/// nk_end(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// ![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png) -/// -/// ## API -/// -*/ -#ifndef NK_SINGLE_FILE - #define NK_SINGLE_FILE -#endif - -#ifndef NK_NUKLEAR_H_ -#define NK_NUKLEAR_H_ - -#ifdef __cplusplus -extern "C" { -#endif -/* - * ============================================================== - * - * CONSTANTS - * - * =============================================================== - */ -#define NK_UNDEFINED (-1.0f) -#define NK_UTF_INVALID 0xFFFD /* internal invalid utf8 rune */ -#define NK_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/ -#ifndef NK_INPUT_MAX - #define NK_INPUT_MAX 16 -#endif -#ifndef NK_MAX_NUMBER_BUFFER - #define NK_MAX_NUMBER_BUFFER 64 -#endif -#ifndef NK_SCROLLBAR_HIDING_TIMEOUT - #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f -#endif -/* - * ============================================================== - * - * HELPER - * - * =============================================================== - */ -#ifndef NK_API - #ifdef NK_PRIVATE - #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L)) - #define NK_API static inline - #elif defined(__cplusplus) - #define NK_API static inline - #else - #define NK_API static - #endif - #else - #define NK_API extern - #endif -#endif -#ifndef NK_LIB - #ifdef NK_SINGLE_FILE - #define NK_LIB static - #else - #define NK_LIB extern - #endif -#endif - -#define NK_INTERN static -#define NK_STORAGE static -#define NK_GLOBAL static - -#define NK_FLAG(x) (1 << (x)) -#define NK_STRINGIFY(x) #x -#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x) -#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2 -#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2) -#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2) - -#ifdef _MSC_VER - #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__) -#else - #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__) -#endif - -#ifndef NK_STATIC_ASSERT - #define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1] -#endif - -#ifndef NK_FILE_LINE -#ifdef _MSC_VER - #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__) -#else - #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__) -#endif -#endif - -#define NK_MIN(a,b) ((a) < (b) ? (a) : (b)) -#define NK_MAX(a,b) ((a) < (b) ? (b) : (a)) -#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i)) - -#ifdef NK_INCLUDE_STANDARD_VARARGS - #include - #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */ - #include - #define NK_PRINTF_FORMAT_STRING _Printf_format_string_ - #else - #define NK_PRINTF_FORMAT_STRING - #endif - #if defined(__GNUC__) - #define NK_PRINTF_VARARG_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, fmtargnumber+1))) - #define NK_PRINTF_VALIST_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, 0))) - #else - #define NK_PRINTF_VARARG_FUNC(fmtargnumber) - #define NK_PRINTF_VALIST_FUNC(fmtargnumber) - #endif -#endif - -/* - * =============================================================== - * - * BASIC - * - * =============================================================== - */ -#ifdef NK_INCLUDE_FIXED_TYPES - #include - #define NK_INT8 int8_t - #define NK_UINT8 uint8_t - #define NK_INT16 int16_t - #define NK_UINT16 uint16_t - #define NK_INT32 int32_t - #define NK_UINT32 uint32_t - #define NK_SIZE_TYPE uintptr_t - #define NK_POINTER_TYPE uintptr_t -#else - #ifndef NK_INT8 - #define NK_INT8 signed char - #endif - #ifndef NK_UINT8 - #define NK_UINT8 unsigned char - #endif - #ifndef NK_INT16 - #define NK_INT16 signed short - #endif - #ifndef NK_UINT16 - #define NK_UINT16 unsigned short - #endif - #ifndef NK_INT32 - #if defined(_MSC_VER) - #define NK_INT32 __int32 - #else - #define NK_INT32 signed int - #endif - #endif - #ifndef NK_UINT32 - #if defined(_MSC_VER) - #define NK_UINT32 unsigned __int32 - #else - #define NK_UINT32 unsigned int - #endif - #endif - #ifndef NK_SIZE_TYPE - #if defined(_WIN64) && defined(_MSC_VER) - #define NK_SIZE_TYPE unsigned __int64 - #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - #define NK_SIZE_TYPE unsigned __int32 - #elif defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(__ppc64__) - #define NK_SIZE_TYPE unsigned long - #else - #define NK_SIZE_TYPE unsigned int - #endif - #else - #define NK_SIZE_TYPE unsigned long - #endif - #endif - #ifndef NK_POINTER_TYPE - #if defined(_WIN64) && defined(_MSC_VER) - #define NK_POINTER_TYPE unsigned __int64 - #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - #define NK_POINTER_TYPE unsigned __int32 - #elif defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(__ppc64__) - #define NK_POINTER_TYPE unsigned long - #else - #define NK_POINTER_TYPE unsigned int - #endif - #else - #define NK_POINTER_TYPE unsigned long - #endif - #endif -#endif - -#ifndef NK_BOOL - #ifdef NK_INCLUDE_STANDARD_BOOL - #include - #define NK_BOOL bool - #else - #define NK_BOOL int /* could be char, use int for drop-in replacement backwards compatibility */ - #endif -#endif - -typedef NK_INT8 nk_char; -typedef NK_UINT8 nk_uchar; -typedef NK_UINT8 nk_byte; -typedef NK_INT16 nk_short; -typedef NK_UINT16 nk_ushort; -typedef NK_INT32 nk_int; -typedef NK_UINT32 nk_uint; -typedef NK_SIZE_TYPE nk_size; -typedef NK_POINTER_TYPE nk_ptr; -typedef NK_BOOL nk_bool; - -typedef nk_uint nk_hash; -typedef nk_uint nk_flags; -typedef nk_uint nk_rune; - -/* Make sure correct type size: - * This will fire with a negative subscript error if the type sizes - * are set incorrectly by the compiler, and compile out if not */ -NK_STATIC_ASSERT(sizeof(nk_short) == 2); -NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); -NK_STATIC_ASSERT(sizeof(nk_uint) == 4); -NK_STATIC_ASSERT(sizeof(nk_int) == 4); -NK_STATIC_ASSERT(sizeof(nk_byte) == 1); -NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); -NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); -NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*)); -#ifdef NK_INCLUDE_STANDARD_BOOL -NK_STATIC_ASSERT(sizeof(nk_bool) == sizeof(bool)); -#else -NK_STATIC_ASSERT(sizeof(nk_bool) >= 2); -#endif - -/* ============================================================================ - * - * API - * - * =========================================================================== */ -struct nk_buffer; -struct nk_allocator; -struct nk_command_buffer; -struct nk_draw_command; -struct nk_convert_config; -struct nk_style_item; -struct nk_text_edit; -struct nk_draw_list; -struct nk_user_font; -struct nk_panel; -struct nk_context; -struct nk_draw_vertex_layout_element; -struct nk_style_button; -struct nk_style_toggle; -struct nk_style_selectable; -struct nk_style_slide; -struct nk_style_progress; -struct nk_style_scrollbar; -struct nk_style_edit; -struct nk_style_property; -struct nk_style_chart; -struct nk_style_combo; -struct nk_style_tab; -struct nk_style_window_header; -struct nk_style_window; - -enum {nk_false, nk_true}; -struct nk_color {nk_byte r,g,b,a;}; -struct nk_colorf {float r,g,b,a;}; -struct nk_vec2 {float x,y;}; -struct nk_vec2i {short x, y;}; -struct nk_rect {float x,y,w,h;}; -struct nk_recti {short x,y,w,h;}; -typedef char nk_glyph[NK_UTF_SIZE]; -typedef union {void *ptr; int id;} nk_handle; -struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];}; -struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;}; -struct nk_scroll {nk_uint x, y;}; - -enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT}; -enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER}; -enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true}; -enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL}; -enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true}; -enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true}; -enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX}; -enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02}; -enum nk_color_format {NK_RGB, NK_RGBA}; -enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; -enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; -enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; - -typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); -typedef void (*nk_plugin_free)(nk_handle, void *old); -typedef nk_bool(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode); -typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*); -typedef void(*nk_plugin_copy)(nk_handle, const char*, int len); - -struct nk_allocator { - nk_handle userdata; - nk_plugin_alloc alloc; - nk_plugin_free free; -}; -enum nk_symbol_type { - NK_SYMBOL_NONE, - NK_SYMBOL_X, - NK_SYMBOL_UNDERSCORE, - NK_SYMBOL_CIRCLE_SOLID, - NK_SYMBOL_CIRCLE_OUTLINE, - NK_SYMBOL_RECT_SOLID, - NK_SYMBOL_RECT_OUTLINE, - NK_SYMBOL_TRIANGLE_UP, - NK_SYMBOL_TRIANGLE_DOWN, - NK_SYMBOL_TRIANGLE_LEFT, - NK_SYMBOL_TRIANGLE_RIGHT, - NK_SYMBOL_PLUS, - NK_SYMBOL_MINUS, - NK_SYMBOL_MAX -}; -/* ============================================================================= - * - * CONTEXT - * - * =============================================================================*/ -/*/// ### Context -/// Contexts are the main entry point and the majestro of nuklear and contain all required state. -/// They are used for window, memory, input, style, stack, commands and time management and need -/// to be passed into all nuklear GUI specific functions. -/// -/// #### Usage -/// To use a context it first has to be initialized which can be achieved by calling -/// one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. -/// Each takes in a font handle and a specific way of handling memory. Memory control -/// hereby ranges from standard library to just specifying a fixed sized block of memory -/// which nuklear has to manage itself from. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // [...] -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------------------- -/// __nk_init_default__ | Initializes context with standard library memory allocation (malloc,free) -/// __nk_init_fixed__ | Initializes context from single fixed size memory block -/// __nk_init__ | Initializes context with memory allocator callbacks for alloc and free -/// __nk_init_custom__ | Initializes context from two buffers. One for draw commands the other for window/panel/table allocations -/// __nk_clear__ | Called at the end of the frame to reset and prepare the context for the next frame -/// __nk_free__ | Shutdown and free all memory allocated inside the context -/// __nk_set_user_data__| Utility function to pass user data to draw command - */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -/*/// #### nk_init_default -/// Initializes a `nk_context` struct with a default standard library allocator. -/// Should be used if you don't want to be bothered with memory management in nuklear. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init_default(struct nk_context *ctx, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|--------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -/// -*/ -NK_API nk_bool nk_init_default(struct nk_context*, const struct nk_user_font*); -#endif -/*/// #### nk_init_fixed -/// Initializes a `nk_context` struct from single fixed size memory block -/// Should be used if you want complete control over nuklear's memory management. -/// Especially recommended for system with little memory or systems with virtual memory. -/// For the later case you can just allocate for example 16MB of virtual memory -/// and only the required amount of memory will actually be committed. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// !!! Warning -/// make sure the passed memory block is aligned correctly for `nk_draw_commands`. -/// -/// Parameter | Description -/// ------------|-------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __memory__ | Must point to a previously allocated memory block -/// __size__ | Must contain the total size of __memory__ -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -*/ -NK_API nk_bool nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*); -/*/// #### nk_init -/// Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate -/// memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation -/// interface to nuklear. Can be useful for cases like monitoring memory consumption. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init(struct nk_context *ctx, struct nk_allocator *alloc, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|--------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __alloc__ | Must point to a previously allocated memory allocator -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -*/ -NK_API nk_bool nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*); -/*/// #### nk_init_custom -/// Initializes a `nk_context` struct from two different either fixed or growing -/// buffers. The first buffer is for allocating draw commands while the second buffer is -/// used for allocating windows, panels and state tables. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|--------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __cmds__ | Must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into -/// __pool__ | Must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -*/ -NK_API nk_bool nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*); -/*/// #### nk_clear -/// Resets the context state at the end of the frame. This includes mostly -/// garbage collector tasks like removing windows or table not called and therefore -/// used anymore. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_clear(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_clear(struct nk_context*); -/*/// #### nk_free -/// Frees all memory allocated by nuklear. Not needed if context was -/// initialized with `nk_init_fixed`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_free(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_free(struct nk_context*); -#ifdef NK_INCLUDE_COMMAND_USERDATA -/*/// #### nk_set_user_data -/// Sets the currently passed userdata passed down into each draw command. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_set_user_data(struct nk_context *ctx, nk_handle data); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|-------------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __data__ | Handle with either pointer or index to be passed into every draw commands -*/ -NK_API void nk_set_user_data(struct nk_context*, nk_handle handle); -#endif -/* ============================================================================= - * - * INPUT - * - * =============================================================================*/ -/*/// ### Input -/// The input API is responsible for holding the current input state composed of -/// mouse, key and text input states. -/// It is worth noting that no direct OS or window handling is done in nuklear. -/// Instead all input state has to be provided by platform specific code. This on one hand -/// expects more work from the user and complicates usage but on the other hand -/// provides simple abstraction over a big number of platforms, libraries and other -/// already provided functionality. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// // [...] -/// } -/// } nk_input_end(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Usage -/// Input state needs to be provided to nuklear by first calling `nk_input_begin` -/// which resets internal state like delta mouse position and button transistions. -/// After `nk_input_begin` all current input state needs to be provided. This includes -/// mouse motion, button and key pressed and released, text input and scrolling. -/// Both event- or state-based input handling are supported by this API -/// and should work without problems. Finally after all input state has been -/// mirrored `nk_input_end` needs to be called to finish input process. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// // [...] -/// } -/// } -/// nk_input_end(&ctx); -/// // [...] -/// nk_clear(&ctx); -/// } nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------------------- -/// __nk_input_begin__ | Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls -/// __nk_input_motion__ | Mirrors mouse cursor position -/// __nk_input_key__ | Mirrors key state with either pressed or released -/// __nk_input_button__ | Mirrors mouse button state with either pressed or released -/// __nk_input_scroll__ | Mirrors mouse scroll values -/// __nk_input_char__ | Adds a single ASCII text character into an internal text buffer -/// __nk_input_glyph__ | Adds a single multi-byte UTF-8 character into an internal text buffer -/// __nk_input_unicode__| Adds a single unicode rune into an internal text buffer -/// __nk_input_end__ | Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call -*/ -enum nk_keys { - NK_KEY_NONE, - NK_KEY_SHIFT, - NK_KEY_CTRL, - NK_KEY_DEL, - NK_KEY_ENTER, - NK_KEY_TAB, - NK_KEY_BACKSPACE, - NK_KEY_COPY, - NK_KEY_CUT, - NK_KEY_PASTE, - NK_KEY_UP, - NK_KEY_DOWN, - NK_KEY_LEFT, - NK_KEY_RIGHT, - /* Shortcuts: text field */ - NK_KEY_TEXT_INSERT_MODE, - NK_KEY_TEXT_REPLACE_MODE, - NK_KEY_TEXT_RESET_MODE, - NK_KEY_TEXT_LINE_START, - NK_KEY_TEXT_LINE_END, - NK_KEY_TEXT_START, - NK_KEY_TEXT_END, - NK_KEY_TEXT_UNDO, - NK_KEY_TEXT_REDO, - NK_KEY_TEXT_SELECT_ALL, - NK_KEY_TEXT_WORD_LEFT, - NK_KEY_TEXT_WORD_RIGHT, - /* Shortcuts: scrollbar */ - NK_KEY_SCROLL_START, - NK_KEY_SCROLL_END, - NK_KEY_SCROLL_DOWN, - NK_KEY_SCROLL_UP, - NK_KEY_MAX -}; -enum nk_buttons { - NK_BUTTON_LEFT, - NK_BUTTON_MIDDLE, - NK_BUTTON_RIGHT, - NK_BUTTON_DOUBLE, - NK_BUTTON_MAX -}; -/*/// #### nk_input_begin -/// Begins the input mirroring process by resetting text, scroll -/// mouse, previous mouse position and movement as well as key state transitions, -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_begin(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_input_begin(struct nk_context*); -/*/// #### nk_input_motion -/// Mirrors current mouse position to nuklear -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_motion(struct nk_context *ctx, int x, int y); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __x__ | Must hold an integer describing the current mouse cursor x-position -/// __y__ | Must hold an integer describing the current mouse cursor y-position -*/ -NK_API void nk_input_motion(struct nk_context*, int x, int y); -/*/// #### nk_input_key -/// Mirrors the state of a specific key to nuklear -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_key(struct nk_context*, enum nk_keys key, nk_bool down); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __key__ | Must be any value specified in enum `nk_keys` that needs to be mirrored -/// __down__ | Must be 0 for key is up and 1 for key is down -*/ -NK_API void nk_input_key(struct nk_context*, enum nk_keys, nk_bool down); -/*/// #### nk_input_button -/// Mirrors the state of a specific mouse button to nuklear -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, nk_bool down); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __btn__ | Must be any value specified in enum `nk_buttons` that needs to be mirrored -/// __x__ | Must contain an integer describing mouse cursor x-position on click up/down -/// __y__ | Must contain an integer describing mouse cursor y-position on click up/down -/// __down__ | Must be 0 for key is up and 1 for key is down -*/ -NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, nk_bool down); -/*/// #### nk_input_scroll -/// Copies the last mouse scroll value to nuklear. Is generally -/// a scroll value. So does not have to come from mouse and could also originate -/// TODO finish this sentence -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __val__ | vector with both X- as well as Y-scroll value -*/ -NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val); -/*/// #### nk_input_char -/// Copies a single ASCII character into an internal text buffer -/// This is basically a helper function to quickly push ASCII characters into -/// nuklear. -/// -/// !!! Note -/// Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_char(struct nk_context *ctx, char c); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __c__ | Must be a single ASCII character preferable one that can be printed -*/ -NK_API void nk_input_char(struct nk_context*, char); -/*/// #### nk_input_glyph -/// Converts an encoded unicode rune into UTF-8 and copies the result into an -/// internal text buffer. -/// -/// !!! Note -/// Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_glyph(struct nk_context *ctx, const nk_glyph g); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __g__ | UTF-32 unicode codepoint -*/ -NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); -/*/// #### nk_input_unicode -/// Converts a unicode rune into UTF-8 and copies the result -/// into an internal text buffer. -/// !!! Note -/// Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_unicode(struct nk_context*, nk_rune rune); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __rune__ | UTF-32 unicode codepoint -*/ -NK_API void nk_input_unicode(struct nk_context*, nk_rune); -/*/// #### nk_input_end -/// End the input mirroring process by resetting mouse grabbing -/// state to ensure the mouse cursor is not grabbed indefinitely. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_end(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_input_end(struct nk_context*); -/* ============================================================================= - * - * DRAWING - * - * =============================================================================*/ -/*/// ### Drawing -/// This library was designed to be render backend agnostic so it does -/// not draw anything to screen directly. Instead all drawn shapes, widgets -/// are made of, are buffered into memory and make up a command queue. -/// Each frame therefore fills the command buffer with draw commands -/// that then need to be executed by the user and his own render backend. -/// After that the command buffer needs to be cleared and a new frame can be -/// started. It is probably important to note that the command buffer is the main -/// drawing API and the optional vertex buffer API only takes this format and -/// converts it into a hardware accessible format. -/// -/// #### Usage -/// To draw all draw commands accumulated over a frame you need your own render -/// backend able to draw a number of 2D primitives. This includes at least -/// filled and stroked rectangles, circles, text, lines, triangles and scissors. -/// As soon as this criterion is met you can iterate over each draw command -/// and execute each draw command in a interpreter like fashion: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case //...: -/// //[...] -/// } -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// In program flow context draw commands need to be executed after input has been -/// gathered and the complete UI with windows and their contained widgets have -/// been executed and before calling `nk_clear` which frees all previously -/// allocated draw commands. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// [...] -/// } -/// } -/// nk_input_end(&ctx); -/// // -/// // [...] -/// // -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// You probably noticed that you have to draw all of the UI each frame which is -/// quite wasteful. While the actual UI updating loop is quite fast rendering -/// without actually needing it is not. So there are multiple things you could do. -/// -/// First is only update on input. This of course is only an option if your -/// application only depends on the UI and does not require any outside calculations. -/// If you actually only update on input make sure to update the UI two times each -/// frame and call `nk_clear` directly after the first pass and only draw in -/// the second pass. In addition it is recommended to also add additional timers -/// to make sure the UI is not drawn more than a fixed number of frames per second. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // [...wait for input ] -/// // [...do two UI passes ...] -/// do_ui(...) -/// nk_clear(&ctx); -/// do_ui(...) -/// // -/// // draw -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// //[...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// The second probably more applicable trick is to only draw if anything changed. -/// It is not really useful for applications with continuous draw loop but -/// quite useful for desktop applications. To actually get nuklear to only -/// draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and -/// allocate a memory buffer that will store each unique drawing output. -/// After each frame you compare the draw command memory inside the library -/// with your allocated buffer by memcmp. If memcmp detects differences -/// you have to copy the command buffer into the allocated buffer -/// and then draw like usual (this example uses fixed memory but you could -/// use dynamically allocated memory). -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// //[... other defines ...] -/// #define NK_ZERO_COMMAND_MEMORY -/// #include "nuklear.h" -/// // -/// // setup context -/// struct nk_context ctx; -/// void *last = calloc(1,64*1024); -/// void *buf = calloc(1,64*1024); -/// nk_init_fixed(&ctx, buf, 64*1024); -/// // -/// // loop -/// while (1) { -/// // [...input...] -/// // [...ui...] -/// void *cmds = nk_buffer_memory(&ctx.memory); -/// if (memcmp(cmds, last, ctx.memory.allocated)) { -/// memcpy(last,cmds,ctx.memory.allocated); -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -/// } -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Finally while using draw commands makes sense for higher abstracted platforms like -/// X11 and Win32 or drawing libraries it is often desirable to use graphics -/// hardware directly. Therefore it is possible to just define -/// `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. -/// To access the vertex output you first have to convert all draw commands into -/// vertexes by calling `nk_convert` which takes in your preferred vertex format. -/// After successfully converting all draw commands just iterate over and execute all -/// vertex draw commands: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// // fill configuration -/// struct your_vertex -/// { -/// float pos[2]; // important to keep it to 2 floats -/// float uv[2]; -/// unsigned char col[4]; -/// }; -/// struct nk_convert_config cfg = {}; -/// static const struct nk_draw_vertex_layout_element vertex_layout[] = { -/// {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)}, -/// {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)}, -/// {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)}, -/// {NK_VERTEX_LAYOUT_END} -/// }; -/// cfg.shape_AA = NK_ANTI_ALIASING_ON; -/// cfg.line_AA = NK_ANTI_ALIASING_ON; -/// cfg.vertex_layout = vertex_layout; -/// cfg.vertex_size = sizeof(struct your_vertex); -/// cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex); -/// cfg.circle_segment_count = 22; -/// cfg.curve_segment_count = 22; -/// cfg.arc_segment_count = 22; -/// cfg.global_alpha = 1.0f; -/// cfg.null = dev->null; -/// // -/// // setup buffers and convert -/// struct nk_buffer cmds, verts, idx; -/// nk_buffer_init_default(&cmds); -/// nk_buffer_init_default(&verts); -/// nk_buffer_init_default(&idx); -/// nk_convert(&ctx, &cmds, &verts, &idx, &cfg); -/// // -/// // draw -/// nk_draw_foreach(cmd, &ctx, &cmds) { -/// if (!cmd->elem_count) continue; -/// //[...] -/// } -/// nk_buffer_free(&cms); -/// nk_buffer_free(&verts); -/// nk_buffer_free(&idx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------------------- -/// __nk__begin__ | Returns the first draw command in the context draw command list to be drawn -/// __nk__next__ | Increments the draw command iterator to the next command inside the context draw command list -/// __nk_foreach__ | Iterates over each draw command inside the context draw command list -/// __nk_convert__ | Converts from the abstract draw commands list into a hardware accessible vertex format -/// __nk_draw_begin__ | Returns the first vertex command in the context vertex draw list to be executed -/// __nk__draw_next__ | Increments the vertex command iterator to the next command inside the context vertex command list -/// __nk__draw_end__ | Returns the end of the vertex draw list -/// __nk_draw_foreach__ | Iterates over each vertex draw command inside the vertex draw list -*/ -enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON}; -enum nk_convert_result { - NK_CONVERT_SUCCESS = 0, - NK_CONVERT_INVALID_PARAM = 1, - NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1), - NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2), - NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3) -}; -struct nk_draw_null_texture { - nk_handle texture; /* texture handle to a texture with a white pixel */ - struct nk_vec2 uv; /* coordinates to a white pixel in the texture */ -}; -struct nk_convert_config { - float global_alpha; /* global alpha value */ - enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */ - enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */ - unsigned circle_segment_count; /* number of segments used for circles: default to 22 */ - unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */ - unsigned curve_segment_count; /* number of segments used for curves: default to 22 */ - struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ - const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ - nk_size vertex_size; /* sizeof one vertex for vertex packing */ - nk_size vertex_alignment; /* vertex alignment: Can be obtained by NK_ALIGNOF */ -}; -/*/// #### nk__begin -/// Returns a draw command list iterator to iterate all draw -/// commands accumulated over one frame. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_command* nk__begin(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | must point to an previously initialized `nk_context` struct at the end of a frame -/// -/// Returns draw command pointer pointing to the first command inside the draw command list -*/ -NK_API const struct nk_command* nk__begin(struct nk_context*); -/*/// #### nk__next -/// Returns draw command pointer pointing to the next command inside the draw command list -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __cmd__ | Must point to an previously a draw command either returned by `nk__begin` or `nk__next` -/// -/// Returns draw command pointer pointing to the next command inside the draw command list -*/ -NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -/*/// #### nk_foreach -/// Iterates over each draw command inside the context draw command list -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_foreach(c, ctx) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __cmd__ | Command pointer initialized to NULL -/// -/// Iterates over each draw command inside the context draw command list -*/ -#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c)) -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/*/// #### nk_convert -/// Converts all internal draw commands into vertex draw commands and fills -/// three buffers with vertexes, vertex draw commands and vertex indices. The vertex format -/// as well as some other configuration values have to be configured by filling out a -/// `nk_convert_config` struct. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, -/// struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __cmds__ | Must point to a previously initialized buffer to hold converted vertex draw commands -/// __vertices__| Must point to a previously initialized buffer to hold all produced vertices -/// __elements__| Must point to a previously initialized buffer to hold all produced vertex indices -/// __config__ | Must point to a filled out `nk_config` struct to configure the conversion process -/// -/// Returns one of enum nk_convert_result error codes -/// -/// Parameter | Description -/// --------------------------------|----------------------------------------------------------- -/// NK_CONVERT_SUCCESS | Signals a successful draw command to vertex buffer conversion -/// NK_CONVERT_INVALID_PARAM | An invalid argument was passed in the function call -/// NK_CONVERT_COMMAND_BUFFER_FULL | The provided buffer for storing draw commands is full or failed to allocate more memory -/// NK_CONVERT_VERTEX_BUFFER_FULL | The provided buffer for storing vertices is full or failed to allocate more memory -/// NK_CONVERT_ELEMENT_BUFFER_FULL | The provided buffer for storing indicies is full or failed to allocate more memory -*/ -NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); -/*/// #### nk__draw_begin -/// Returns a draw vertex command buffer iterator to iterate over the vertex draw command buffer -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// -/// Returns vertex draw command pointer pointing to the first command inside the vertex draw command buffer -*/ -NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -/*/// #### nk__draw_end -/// Returns the vertex draw command at the end of the vertex draw command buffer -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_draw_command* nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buf); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// -/// Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer -*/ -NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); -/*/// #### nk__draw_next -/// Increments the vertex draw command buffer iterator -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __cmd__ | Must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// -/// Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer -*/ -NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -/*/// #### nk_draw_foreach -/// Iterates over each vertex draw command inside a vertex draw command buffer -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_draw_foreach(cmd,ctx, b) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __cmd__ | `nk_draw_command`iterator set to NULL -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -*/ -#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx)) -#endif -/* ============================================================================= - * - * WINDOW - * - * ============================================================================= -/// ### Window -/// Windows are the main persistent state used inside nuklear and are life time -/// controlled by simply "retouching" (i.e. calling) each window each frame. -/// All widgets inside nuklear can only be added inside the function pair `nk_begin_xxx` -/// and `nk_end`. Calling any widgets outside these two functions will result in an -/// assert in debug or no state change in release mode.

-/// -/// Each window holds frame persistent state like position, size, flags, state tables, -/// and some garbage collected internal persistent widget state. Each window -/// is linked into a window stack list which determines the drawing and overlapping -/// order. The topmost window thereby is the currently active window.

-/// -/// To change window position inside the stack occurs either automatically by -/// user input by being clicked on or programmatically by calling `nk_window_focus`. -/// Windows by default are visible unless explicitly being defined with flag -/// `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag -/// `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling -/// `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.

-/// -/// #### Usage -/// To create and keep a window you have to call one of the two `nk_begin_xxx` -/// functions to start window declarations and `nk_end` at the end. Furthermore it -/// is recommended to check the return value of `nk_begin_xxx` and only process -/// widgets inside the window if the value is not 0. Either way you have to call -/// `nk_end` at the end of window declarations. Furthermore, do not attempt to -/// nest `nk_begin_xxx` calls which will hopefully result in an assert or if not -/// in a segmentation fault. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // [... widgets ...] -/// } -/// nk_end(ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// In the grand concept window and widget declarations need to occur after input -/// handling and before drawing to screen. Not doing so can result in higher -/// latency or at worst invalid behavior. Furthermore make sure that `nk_clear` -/// is called at the end of the frame. While nuklear's default platform backends -/// already call `nk_clear` for you if you write your own backend not calling -/// `nk_clear` can cause asserts or even worse undefined behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// nk_input_xxx(...); -/// } -/// } -/// nk_input_end(&ctx); -/// -/// if (nk_begin_xxx(...) { -/// //[...] -/// } -/// nk_end(ctx); -/// -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case //...: -/// //[...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// ------------------------------------|---------------------------------------- -/// nk_begin | Starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed -/// nk_begin_titled | Extended window start with separated title and identifier to allow multiple windows with same name but not title -/// nk_end | Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup -// -/// nk_window_find | Finds and returns the window with give name -/// nk_window_get_bounds | Returns a rectangle with screen position and size of the currently processed window. -/// nk_window_get_position | Returns the position of the currently processed window -/// nk_window_get_size | Returns the size with width and height of the currently processed window -/// nk_window_get_width | Returns the width of the currently processed window -/// nk_window_get_height | Returns the height of the currently processed window -/// nk_window_get_panel | Returns the underlying panel which contains all processing state of the current window -/// nk_window_get_content_region | Returns the position and size of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_content_region_min | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_content_region_max | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_content_region_size | Returns the size of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_canvas | Returns the draw command buffer. Can be used to draw custom widgets -/// nk_window_get_scroll | Gets the scroll offset of the current window -/// nk_window_has_focus | Returns if the currently processed window is currently active -/// nk_window_is_collapsed | Returns if the window with given name is currently minimized/collapsed -/// nk_window_is_closed | Returns if the currently processed window was closed -/// nk_window_is_hidden | Returns if the currently processed window was hidden -/// nk_window_is_active | Same as nk_window_has_focus for some reason -/// nk_window_is_hovered | Returns if the currently processed window is currently being hovered by mouse -/// nk_window_is_any_hovered | Return if any window currently hovered -/// nk_item_is_any_active | Returns if any window or widgets is currently hovered or active -// -/// nk_window_set_bounds | Updates position and size of the currently processed window -/// nk_window_set_position | Updates position of the currently process window -/// nk_window_set_size | Updates the size of the currently processed window -/// nk_window_set_focus | Set the currently processed window as active window -/// nk_window_set_scroll | Sets the scroll offset of the current window -// -/// nk_window_close | Closes the window with given window name which deletes the window at the end of the frame -/// nk_window_collapse | Collapses the window with given window name -/// nk_window_collapse_if | Collapses the window with given window name if the given condition was met -/// nk_window_show | Hides a visible or reshows a hidden window -/// nk_window_show_if | Hides/shows a window depending on condition -*/ -/* -/// #### nk_panel_flags -/// Flag | Description -/// ----------------------------|---------------------------------------- -/// NK_WINDOW_BORDER | Draws a border around the window to visually separate window from the background -/// NK_WINDOW_MOVABLE | The movable flag indicates that a window can be moved by user input or by dragging the window header -/// NK_WINDOW_SCALABLE | The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window -/// NK_WINDOW_CLOSABLE | Adds a closable icon into the header -/// NK_WINDOW_MINIMIZABLE | Adds a minimize icon into the header -/// NK_WINDOW_NO_SCROLLBAR | Removes the scrollbar from the window -/// NK_WINDOW_TITLE | Forces a header at the top at the window showing the title -/// NK_WINDOW_SCROLL_AUTO_HIDE | Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame -/// NK_WINDOW_BACKGROUND | Always keep window in the background -/// NK_WINDOW_SCALE_LEFT | Puts window scaler in the left-bottom corner instead right-bottom -/// NK_WINDOW_NO_INPUT | Prevents window of scaling, moving or getting focus -/// -/// #### nk_collapse_states -/// State | Description -/// ----------------|----------------------------------------------------------- -/// __NK_MINIMIZED__| UI section is collased and not visibile until maximized -/// __NK_MAXIMIZED__| UI section is extended and visibile until minimized -///

-*/ -enum nk_panel_flags { - NK_WINDOW_BORDER = NK_FLAG(0), - NK_WINDOW_MOVABLE = NK_FLAG(1), - NK_WINDOW_SCALABLE = NK_FLAG(2), - NK_WINDOW_CLOSABLE = NK_FLAG(3), - NK_WINDOW_MINIMIZABLE = NK_FLAG(4), - NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), - NK_WINDOW_TITLE = NK_FLAG(6), - NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), - NK_WINDOW_BACKGROUND = NK_FLAG(8), - NK_WINDOW_SCALE_LEFT = NK_FLAG(9), - NK_WINDOW_NO_INPUT = NK_FLAG(10) -}; -/*/// #### nk_begin -/// Starts a new window; needs to be called every frame for every -/// window (unless hidden) or otherwise the window gets removed -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __title__ | Window title and identifier. Needs to be persistent over frames to identify the window -/// __bounds__ | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different window behaviors -/// -/// Returns `true(1)` if the window can be filled up with widgets from this point -/// until `nk_end` or `false(0)` otherwise for example if minimized -*/ -NK_API nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -/*/// #### nk_begin_titled -/// Extended window start with separated title and identifier to allow multiple -/// windows with same title but not name -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Window identifier. Needs to be persistent over frames to identify the window -/// __title__ | Window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set -/// __bounds__ | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different window behaviors -/// -/// Returns `true(1)` if the window can be filled up with widgets from this point -/// until `nk_end` or `false(0)` otherwise for example if minimized -*/ -NK_API nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -/*/// #### nk_end -/// Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup. -/// All widget calls after this functions will result in asserts or no state changes -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_end(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -*/ -NK_API void nk_end(struct nk_context *ctx); -/*/// #### nk_window_find -/// Finds and returns a window from passed name -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Window identifier -/// -/// Returns a `nk_window` struct pointing to the identified window or NULL if -/// no window with the given name was found -*/ -NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); -/*/// #### nk_window_get_bounds -/// Returns a rectangle with screen position and size of the currently processed window -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a `nk_rect` struct with window upper left window position and size -*/ -NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); -/*/// #### nk_window_get_position -/// Returns the position of the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a `nk_vec2` struct with window upper left position -*/ -NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); -/*/// #### nk_window_get_size -/// Returns the size with width and height of the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_size(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a `nk_vec2` struct with window width and height -*/ -NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*); -/*/// #### nk_window_get_width -/// Returns the width of the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_window_get_width(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns the current window width -*/ -NK_API float nk_window_get_width(const struct nk_context*); -/*/// #### nk_window_get_height -/// Returns the height of the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_window_get_height(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns the current window height -*/ -NK_API float nk_window_get_height(const struct nk_context*); -/*/// #### nk_window_get_panel -/// Returns the underlying panel which contains all processing state of the current window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// !!! WARNING -/// Do not keep the returned panel pointer around, it is only valid until `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_panel* nk_window_get_panel(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a pointer to window internal `nk_panel` state. -*/ -NK_API struct nk_panel* nk_window_get_panel(struct nk_context*); -/*/// #### nk_window_get_content_region -/// Returns the position and size of the currently visible and non-clipped space -/// inside the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_window_get_content_region(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `nk_rect` struct with screen position and size (no scrollbar offset) -/// of the visible space inside the current window -*/ -NK_API struct nk_rect nk_window_get_content_region(struct nk_context*); -/*/// #### nk_window_get_content_region_min -/// Returns the upper left position of the currently visible and non-clipped -/// space inside the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_content_region_min(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// returns `nk_vec2` struct with upper left screen position (no scrollbar offset) -/// of the visible space inside the current window -*/ -NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*); -/*/// #### nk_window_get_content_region_max -/// Returns the lower right screen position of the currently visible and -/// non-clipped space inside the currently processed window. -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_content_region_max(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `nk_vec2` struct with lower right screen position (no scrollbar offset) -/// of the visible space inside the current window -*/ -NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*); -/*/// #### nk_window_get_content_region_size -/// Returns the size of the currently visible and non-clipped space inside the -/// currently processed window -/// -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_content_region_size(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `nk_vec2` struct with size the visible space inside the current window -*/ -NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*); -/*/// #### nk_window_get_canvas -/// Returns the draw command buffer. Can be used to draw custom widgets -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// !!! WARNING -/// Do not keep the returned command buffer pointer around it is only valid until `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_command_buffer* nk_window_get_canvas(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a pointer to window internal `nk_command_buffer` struct used as -/// drawing canvas. Can be used to do custom drawing. -*/ -NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*); -/*/// #### nk_window_get_scroll -/// Gets the scroll offset for the current window -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// -------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __offset_x__ | A pointer to the x offset output (or NULL to ignore) -/// __offset_y__ | A pointer to the y offset output (or NULL to ignore) -*/ -NK_API void nk_window_get_scroll(struct nk_context*, nk_uint *offset_x, nk_uint *offset_y); -/*/// #### nk_window_has_focus -/// Returns if the currently processed window is currently active -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_has_focus(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `false(0)` if current window is not active or `true(1)` if it is -*/ -NK_API nk_bool nk_window_has_focus(const struct nk_context*); -/*/// #### nk_window_is_hovered -/// Return if the current window is being hovered -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_hovered(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `true(1)` if current window is hovered or `false(0)` otherwise -*/ -NK_API nk_bool nk_window_is_hovered(struct nk_context*); -/*/// #### nk_window_is_collapsed -/// Returns if the window with given name is currently minimized/collapsed -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_collapsed(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is collapsed -/// -/// Returns `true(1)` if current window is minimized and `false(0)` if window not -/// found or is not minimized -*/ -NK_API nk_bool nk_window_is_collapsed(struct nk_context *ctx, const char *name); -/*/// #### nk_window_is_closed -/// Returns if the window with given name was closed by calling `nk_close` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_closed(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is closed -/// -/// Returns `true(1)` if current window was closed or `false(0)` window not found or not closed -*/ -NK_API nk_bool nk_window_is_closed(struct nk_context*, const char*); -/*/// #### nk_window_is_hidden -/// Returns if the window with given name is hidden -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_hidden(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is hidden -/// -/// Returns `true(1)` if current window is hidden or `false(0)` window not found or visible -*/ -NK_API nk_bool nk_window_is_hidden(struct nk_context*, const char*); -/*/// #### nk_window_is_active -/// Same as nk_window_has_focus for some reason -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_active(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is active -/// -/// Returns `true(1)` if current window is active or `false(0)` window not found or not active -*/ -NK_API nk_bool nk_window_is_active(struct nk_context*, const char*); -/*/// #### nk_window_is_any_hovered -/// Returns if the any window is being hovered -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_any_hovered(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `true(1)` if any window is hovered or `false(0)` otherwise -*/ -NK_API nk_bool nk_window_is_any_hovered(struct nk_context*); -/*/// #### nk_item_is_any_active -/// Returns if the any window is being hovered or any widget is currently active. -/// Can be used to decide if input should be processed by UI or your specific input handling. -/// Example could be UI and 3D camera to move inside a 3D space. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_item_is_any_active(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `true(1)` if any window is hovered or any item is active or `false(0)` otherwise -*/ -NK_API nk_bool nk_item_is_any_active(struct nk_context*); -/*/// #### nk_window_set_bounds -/// Updates position and size of window with passed in name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to modify both position and size -/// __bounds__ | Must point to a `nk_rect` struct with the new position and size -*/ -NK_API void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds); -/*/// #### nk_window_set_position -/// Updates position of window with passed name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to modify both position -/// __pos__ | Must point to a `nk_vec2` struct with the new position -*/ -NK_API void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos); -/*/// #### nk_window_set_size -/// Updates size of window with passed in name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to modify both window size -/// __size__ | Must point to a `nk_vec2` struct with new window size -*/ -NK_API void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2); -/*/// #### nk_window_set_focus -/// Sets the window with given name as active -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_focus(struct nk_context*, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to set focus on -*/ -NK_API void nk_window_set_focus(struct nk_context*, const char *name); -/*/// #### nk_window_set_scroll -/// Sets the scroll offset for the current window -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// -------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __offset_x__ | The x offset to scroll to -/// __offset_y__ | The y offset to scroll to -*/ -NK_API void nk_window_set_scroll(struct nk_context*, nk_uint offset_x, nk_uint offset_y); -/*/// #### nk_window_close -/// Closes a window and marks it for being freed at the end of the frame -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_close(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to close -*/ -NK_API void nk_window_close(struct nk_context *ctx, const char *name); -/*/// #### nk_window_collapse -/// Updates collapse state of a window with given name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to close -/// __state__ | value out of nk_collapse_states section -*/ -NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); -/*/// #### nk_window_collapse_if -/// Updates collapse state of a window with given name if given condition is met -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to either collapse or maximize -/// __state__ | value out of nk_collapse_states section the window should be put into -/// __cond__ | condition that has to be met to actually commit the collapse state change -*/ -NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -/*/// #### nk_window_show -/// updates visibility state of a window with given name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to either collapse or maximize -/// __state__ | state with either visible or hidden to modify the window with -*/ -NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -/*/// #### nk_window_show_if -/// Updates visibility state of a window with given name if a given condition is met -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to either hide or show -/// __state__ | state with either visible or hidden to modify the window with -/// __cond__ | condition that has to be met to actually commit the visbility state change -*/ -NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); -/* ============================================================================= - * - * LAYOUT - * - * ============================================================================= -/// ### Layouting -/// Layouting in general describes placing widget inside a window with position and size. -/// While in this particular implementation there are five different APIs for layouting -/// each with different trade offs between control and ease of use.

-/// -/// All layouting methods in this library are based around the concept of a row. -/// A row has a height the window content grows by and a number of columns and each -/// layouting method specifies how each widget is placed inside the row. -/// After a row has been allocated by calling a layouting functions and then -/// filled with widgets will advance an internal pointer over the allocated row.

-/// -/// To actually define a layout you just call the appropriate layouting function -/// and each subsequent widget call will place the widget as specified. Important -/// here is that if you define more widgets then columns defined inside the layout -/// functions it will allocate the next row without you having to make another layouting

-/// call. -/// -/// Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API -/// is that you have to define the row height for each. However the row height -/// often depends on the height of the font.

-/// -/// To fix that internally nuklear uses a minimum row height that is set to the -/// height plus padding of currently active font and overwrites the row height -/// value if zero.

-/// -/// If you manually want to change the minimum row height then -/// use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to -/// reset it back to be derived from font height.

-/// -/// Also if you change the font in nuklear it will automatically change the minimum -/// row height for you and. This means if you change the font but still want -/// a minimum row height smaller than the font you have to repush your value.

-/// -/// For actually more advanced UI I would even recommend using the `nk_layout_space_xxx` -/// layouting method in combination with a cassowary constraint solver (there are -/// some versions on github with permissive license model) to take over all control over widget -/// layouting yourself. However for quick and dirty layouting using all the other layouting -/// functions should be fine. -/// -/// #### Usage -/// 1. __nk_layout_row_dynamic__

-/// The easiest layouting function is `nk_layout_row_dynamic`. It provides each -/// widgets with same horizontal space inside the row and dynamically grows -/// if the owning window grows in width. So the number of columns dictates -/// the size of each widget dynamically by formula: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// widget_width = (window_width - padding - spacing) * (1/colum_count) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Just like all other layouting APIs if you define more widget than columns this -/// library will allocate a new row and keep all layouting parameters previously -/// defined. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // first row with height: 30 composed of two widgets -/// nk_layout_row_dynamic(&ctx, 30, 2); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // second row with same parameter as defined above -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // third row uses 0 for height which will use auto layouting -/// nk_layout_row_dynamic(&ctx, 0, 2); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 2. __nk_layout_row_static__

-/// Another easy layouting function is `nk_layout_row_static`. It provides each -/// widget with same horizontal pixel width inside the row and does not grow -/// if the owning window scales smaller or bigger. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // first row with height: 30 composed of two widgets with width: 80 -/// nk_layout_row_static(&ctx, 30, 80, 2); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // second row with same parameter as defined above -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // third row uses 0 for height which will use auto layouting -/// nk_layout_row_static(&ctx, 0, 80, 2); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 3. __nk_layout_row_xxx__

-/// A little bit more advanced layouting API are functions `nk_layout_row_begin`, -/// `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly -/// specify each column pixel or window ratio in a row. It supports either -/// directly setting per column pixel width or widget window ratio but not -/// both. Furthermore it is a immediate mode API so each value is directly -/// pushed before calling a widget. Therefore the layout is not automatically -/// repeating like the last two layouting functions. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // first row with height: 25 composed of two widgets with width 60 and 40 -/// nk_layout_row_begin(ctx, NK_STATIC, 25, 2); -/// nk_layout_row_push(ctx, 60); -/// nk_widget(...); -/// nk_layout_row_push(ctx, 40); -/// nk_widget(...); -/// nk_layout_row_end(ctx); -/// // -/// // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75 -/// nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2); -/// nk_layout_row_push(ctx, 0.25f); -/// nk_widget(...); -/// nk_layout_row_push(ctx, 0.75f); -/// nk_widget(...); -/// nk_layout_row_end(ctx); -/// // -/// // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75 -/// nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2); -/// nk_layout_row_push(ctx, 0.25f); -/// nk_widget(...); -/// nk_layout_row_push(ctx, 0.75f); -/// nk_widget(...); -/// nk_layout_row_end(ctx); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 4. __nk_layout_row__

-/// The array counterpart to API nk_layout_row_xxx is the single nk_layout_row -/// functions. Instead of pushing either pixel or window ratio for every widget -/// it allows to define it by array. The trade of for less control is that -/// `nk_layout_row` is automatically repeating. Otherwise the behavior is the -/// same. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // two rows with height: 30 composed of two widgets with width 60 and 40 -/// const float size[] = {60,40}; -/// nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75 -/// const float ratio[] = {0.25, 0.75}; -/// nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75 -/// const float ratio[] = {0.25, 0.75}; -/// nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 5. __nk_layout_row_template_xxx__

-/// The most complex and second most flexible API is a simplified flexbox version without -/// line wrapping and weights for dynamic widgets. It is an immediate mode API but -/// unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called -/// before calling the templated widgets. -/// The row template layout has three different per widget size specifier. The first -/// one is the `nk_layout_row_template_push_static` with fixed widget pixel width. -/// They do not grow if the row grows and will always stay the same. -/// The second size specifier is `nk_layout_row_template_push_variable` -/// which defines a minimum widget size but it also can grow if more space is available -/// not taken by other widgets. -/// Finally there are dynamic widgets with `nk_layout_row_template_push_dynamic` -/// which are completely flexible and unlike variable widgets can even shrink -/// to zero if not enough space is provided. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // two rows with height: 30 composed of three widgets -/// nk_layout_row_template_begin(ctx, 30); -/// nk_layout_row_template_push_dynamic(ctx); -/// nk_layout_row_template_push_variable(ctx, 80); -/// nk_layout_row_template_push_static(ctx, 80); -/// nk_layout_row_template_end(ctx); -/// // -/// // first row -/// nk_widget(...); // dynamic widget can go to zero if not enough space -/// nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space -/// nk_widget(...); // static widget with fixed 80 pixel width -/// // -/// // second row same layout -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 6. __nk_layout_space_xxx__

-/// Finally the most flexible API directly allows you to place widgets inside the -/// window. The space layout API is an immediate mode API which does not support -/// row auto repeat and directly sets position and size of a widget. Position -/// and size hereby can be either specified as ratio of allocated space or -/// allocated space local position and pixel size. Since this API is quite -/// powerful there are a number of utility functions to get the available space -/// and convert between local allocated space and screen space. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) -/// nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX); -/// nk_layout_space_push(ctx, nk_rect(0,0,150,200)); -/// nk_widget(...); -/// nk_layout_space_push(ctx, nk_rect(200,200,100,200)); -/// nk_widget(...); -/// nk_layout_space_end(ctx); -/// // -/// // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) -/// nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX); -/// nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1)); -/// nk_widget(...); -/// nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1)); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// ----------------------------------------|------------------------------------ -/// nk_layout_set_min_row_height | Set the currently used minimum row height to a specified value -/// nk_layout_reset_min_row_height | Resets the currently used minimum row height to font height -/// nk_layout_widget_bounds | Calculates current width a static layout row can fit inside a window -/// nk_layout_ratio_from_pixel | Utility functions to calculate window ratio from pixel size -// -/// nk_layout_row_dynamic | Current layout is divided into n same sized growing columns -/// nk_layout_row_static | Current layout is divided into n same fixed sized columns -/// nk_layout_row_begin | Starts a new row with given height and number of columns -/// nk_layout_row_push | Pushes another column with given size or window ratio -/// nk_layout_row_end | Finished previously started row -/// nk_layout_row | Specifies row columns in array as either window ratio or size -// -/// nk_layout_row_template_begin | Begins the row template declaration -/// nk_layout_row_template_push_dynamic | Adds a dynamic column that dynamically grows and can go to zero if not enough space -/// nk_layout_row_template_push_variable | Adds a variable column that dynamically grows but does not shrink below specified pixel width -/// nk_layout_row_template_push_static | Adds a static column that does not grow and will always have the same size -/// nk_layout_row_template_end | Marks the end of the row template -// -/// nk_layout_space_begin | Begins a new layouting space that allows to specify each widgets position and size -/// nk_layout_space_push | Pushes position and size of the next widget in own coordinate space either as pixel or ratio -/// nk_layout_space_end | Marks the end of the layouting space -// -/// nk_layout_space_bounds | Callable after nk_layout_space_begin and returns total space allocated -/// nk_layout_space_to_screen | Converts vector from nk_layout_space coordinate space into screen space -/// nk_layout_space_to_local | Converts vector from screen space into nk_layout_space coordinates -/// nk_layout_space_rect_to_screen | Converts rectangle from nk_layout_space coordinate space into screen space -/// nk_layout_space_rect_to_local | Converts rectangle from screen space into nk_layout_space coordinates -*/ -/*/// #### nk_layout_set_min_row_height -/// Sets the currently used minimum row height. -/// !!! WARNING -/// The passed height needs to include both your preferred row height -/// as well as padding. No internal padding is added. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_set_min_row_height(struct nk_context*, float height); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | New minimum row height to be used for auto generating the row height -*/ -NK_API void nk_layout_set_min_row_height(struct nk_context*, float height); -/*/// #### nk_layout_reset_min_row_height -/// Reset the currently used minimum row height back to `font_height + text_padding + padding` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_reset_min_row_height(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -*/ -NK_API void nk_layout_reset_min_row_height(struct nk_context*); -/*/// #### nk_layout_widget_bounds -/// Returns the width of the next row allocate by one of the layouting functions -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_widget_bounds(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// -/// Return `nk_rect` with both position and size of the next row -*/ -NK_API struct nk_rect nk_layout_widget_bounds(struct nk_context*); -/*/// #### nk_layout_ratio_from_pixel -/// Utility functions to calculate window ratio from pixel size -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __pixel__ | Pixel_width to convert to window ratio -/// -/// Returns `nk_rect` with both position and size of the next row -*/ -NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); -/*/// #### nk_layout_row_dynamic -/// Sets current row layout to share horizontal space -/// between @cols number of widgets evenly. Once called all subsequent widget -/// calls greater than @cols will allocate a new row with same layout. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); -/*/// #### nk_layout_row_static -/// Sets current row layout to fill @cols number of widgets -/// in row with same @item_width horizontal size. Once called all subsequent widget -/// calls greater than @cols will allocate a new row with same layout. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __width__ | Holds pixel width of each widget in the row -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); -/*/// #### nk_layout_row_begin -/// Starts a new dynamic or fixed row with given height and columns. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __fmt__ | either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -/// __height__ | holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); -/*/// #### nk_layout_row_push -/// Specifies either window ratio or width of a single column -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_push(struct nk_context*, float value); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __value__ | either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call -*/ -NK_API void nk_layout_row_push(struct nk_context*, float value); -/*/// #### nk_layout_row_end -/// Finished previously started row -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -*/ -NK_API void nk_layout_row_end(struct nk_context*); -/*/// #### nk_layout_row -/// Specifies row columns in array as either window ratio or size -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __fmt__ | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); -/*/// #### nk_layout_row_template_begin -/// Begins the row template declaration -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_begin(struct nk_context*, float row_height); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -*/ -NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height); -/*/// #### nk_layout_row_template_push_dynamic -/// Adds a dynamic column that dynamically grows and can go to zero if not enough space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_push_dynamic(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -*/ -NK_API void nk_layout_row_template_push_dynamic(struct nk_context*); -/*/// #### nk_layout_row_template_push_variable -/// Adds a variable column that dynamically grows but does not shrink below specified pixel width -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __width__ | Holds the minimum pixel width the next column must always be -*/ -NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -/*/// #### nk_layout_row_template_push_static -/// Adds a static column that does not grow and will always have the same size -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_push_static(struct nk_context*, float width); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __width__ | Holds the absolute pixel width value the next column must be -*/ -NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); -/*/// #### nk_layout_row_template_end -/// Marks the end of the row template -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -*/ -NK_API void nk_layout_row_template_end(struct nk_context*); -/*/// #### nk_layout_space_begin -/// Begins a new layouting space that allows to specify each widgets position and size. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __fmt__ | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widgets inside row -*/ -NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -/*/// #### nk_layout_space_push -/// Pushes position and size of the next widget in own coordinate space either as pixel or ratio -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_space_push(struct nk_context *ctx, struct nk_rect bounds); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __bounds__ | Position and size in laoyut space local coordinates -*/ -NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect bounds); -/*/// #### nk_layout_space_end -/// Marks the end of the layout space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_space_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -*/ -NK_API void nk_layout_space_end(struct nk_context*); -/*/// #### nk_layout_space_bounds -/// Utility function to calculate total space allocated for `nk_layout_space` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_space_bounds(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// -/// Returns `nk_rect` holding the total space allocated -*/ -NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); -/*/// #### nk_layout_space_to_screen -/// Converts vector from nk_layout_space coordinate space into screen space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __vec__ | Position to convert from layout space into screen coordinate space -/// -/// Returns transformed `nk_vec2` in screen space coordinates -*/ -NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -/*/// #### nk_layout_space_to_local -/// Converts vector from layout space into screen space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __vec__ | Position to convert from screen space into layout coordinate space -/// -/// Returns transformed `nk_vec2` in layout space coordinates -*/ -NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -/*/// #### nk_layout_space_rect_to_screen -/// Converts rectangle from screen space into layout space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __bounds__ | Rectangle to convert from layout space into screen space -/// -/// Returns transformed `nk_rect` in screen space coordinates -*/ -NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -/*/// #### nk_layout_space_rect_to_local -/// Converts rectangle from layout space into screen space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __bounds__ | Rectangle to convert from layout space into screen space -/// -/// Returns transformed `nk_rect` in layout space coordinates -*/ -NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -/* ============================================================================= - * - * GROUP - * - * ============================================================================= -/// ### Groups -/// Groups are basically windows inside windows. They allow to subdivide space -/// in a window to layout widgets as a group. Almost all more complex widget -/// layouting requirements can be solved using groups and basic layouting -/// fuctionality. Groups just like windows are identified by an unique name and -/// internally keep track of scrollbar offsets by default. However additional -/// versions are provided to directly manage the scrollbar. -/// -/// #### Usage -/// To create a group you have to call one of the three `nk_group_begin_xxx` -/// functions to start group declarations and `nk_group_end` at the end. Furthermore it -/// is required to check the return value of `nk_group_begin_xxx` and only process -/// widgets inside the window if the value is not 0. -/// Nesting groups is possible and even encouraged since many layouting schemes -/// can only be achieved by nesting. Groups, unlike windows, need `nk_group_end` -/// to be only called if the corosponding `nk_group_begin_xxx` call does not return 0: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_group_begin_xxx(ctx, ...) { -/// // [... widgets ...] -/// nk_group_end(ctx); -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// In the grand concept groups can be called after starting a window -/// with `nk_begin_xxx` and before calling `nk_end`: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // Input -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// nk_input_xxx(...); -/// } -/// } -/// nk_input_end(&ctx); -/// // -/// // Window -/// if (nk_begin_xxx(...) { -/// // [...widgets...] -/// nk_layout_row_dynamic(...); -/// if (nk_group_begin_xxx(ctx, ...) { -/// //[... widgets ...] -/// nk_group_end(ctx); -/// } -/// } -/// nk_end(ctx); -/// // -/// // Draw -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// #### Reference -/// Function | Description -/// --------------------------------|------------------------------------------- -/// nk_group_begin | Start a new group with internal scrollbar handling -/// nk_group_begin_titled | Start a new group with separeted name and title and internal scrollbar handling -/// nk_group_end | Ends a group. Should only be called if nk_group_begin returned non-zero -/// nk_group_scrolled_offset_begin | Start a new group with manual separated handling of scrollbar x- and y-offset -/// nk_group_scrolled_begin | Start a new group with manual scrollbar handling -/// nk_group_scrolled_end | Ends a group with manual scrollbar handling. Should only be called if nk_group_begin returned non-zero -/// nk_group_get_scroll | Gets the scroll offset for the given group -/// nk_group_set_scroll | Sets the scroll offset for the given group -*/ -/*/// #### nk_group_begin -/// Starts a new widget group. Requires a previous layouting function to specify a pos/size. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_begin(struct nk_context*, const char *title, nk_flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __title__ | Must be an unique identifier for this group that is also used for the group header -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different group behaviors -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags); -/*/// #### nk_group_begin_titled -/// Starts a new widget group. Requires a previous layouting function to specify a pos/size. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __id__ | Must be an unique identifier for this group -/// __title__ | Group header title -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different group behaviors -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags); -/*/// #### nk_group_end -/// Ends a widget group -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_group_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -*/ -NK_API void nk_group_end(struct nk_context*); -/*/// #### nk_group_scrolled_offset_begin -/// starts a new widget group. requires a previous layouting function to specify -/// a size. Does not keep track of scrollbar. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __x_offset__| Scrollbar x-offset to offset all widgets inside the group horizontally. -/// __y_offset__| Scrollbar y-offset to offset all widgets inside the group vertically -/// __title__ | Window unique group title used to both identify and display in the group header -/// __flags__ | Window flags from the nk_panel_flags section -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags); -/*/// #### nk_group_scrolled_begin -/// Starts a new widget group. requires a previous -/// layouting function to specify a size. Does not keep track of scrollbar. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __off__ | Both x- and y- scroll offset. Allows for manual scrollbar control -/// __title__ | Window unique group title used to both identify and display in the group header -/// __flags__ | Window flags from nk_panel_flags section -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags); -/*/// #### nk_group_scrolled_end -/// Ends a widget group after calling nk_group_scrolled_offset_begin or nk_group_scrolled_begin. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_group_scrolled_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -*/ -NK_API void nk_group_scrolled_end(struct nk_context*); -/*/// #### nk_group_get_scroll -/// Gets the scroll position of the given group. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// -------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __id__ | The id of the group to get the scroll position of -/// __x_offset__ | A pointer to the x offset output (or NULL to ignore) -/// __y_offset__ | A pointer to the y offset output (or NULL to ignore) -*/ -NK_API void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset); -/*/// #### nk_group_set_scroll -/// Sets the scroll position of the given group. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// -------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __id__ | The id of the group to scroll -/// __x_offset__ | The x offset to scroll to -/// __y_offset__ | The y offset to scroll to -*/ -NK_API void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset); -/* ============================================================================= - * - * TREE - * - * ============================================================================= -/// ### Tree -/// Trees represent two different concept. First the concept of a collapsable -/// UI section that can be either in a hidden or visibile state. They allow the UI -/// user to selectively minimize the current set of visible UI to comprehend. -/// The second concept are tree widgets for visual UI representation of trees.

-/// -/// Trees thereby can be nested for tree representations and multiple nested -/// collapsable UI sections. All trees are started by calling of the -/// `nk_tree_xxx_push_tree` functions and ended by calling one of the -/// `nk_tree_xxx_pop_xxx()` functions. Each starting functions takes a title label -/// and optionally an image to be displayed and the initial collapse state from -/// the nk_collapse_states section.

-/// -/// The runtime state of the tree is either stored outside the library by the caller -/// or inside which requires a unique ID. The unique ID can either be generated -/// automatically from `__FILE__` and `__LINE__` with function `nk_tree_push`, -/// by `__FILE__` and a user provided ID generated for example by loop index with -/// function `nk_tree_push_id` or completely provided from outside by user with -/// function `nk_tree_push_hashed`. -/// -/// #### Usage -/// To create a tree you have to call one of the seven `nk_tree_xxx_push_xxx` -/// functions to start a collapsable UI section and `nk_tree_xxx_pop` to mark the -/// end. -/// Each starting function will either return `false(0)` if the tree is collapsed -/// or hidden and therefore does not need to be filled with content or `true(1)` -/// if visible and required to be filled. -/// -/// !!! Note -/// The tree header does not require and layouting function and instead -/// calculates a auto height based on the currently used font size -/// -/// The tree ending functions only need to be called if the tree content is -/// actually visible. So make sure the tree push function is guarded by `if` -/// and the pop call is only taken if the tree is visible. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_tree_push(ctx, NK_TREE_TAB, "Tree", NK_MINIMIZED)) { -/// nk_layout_row_dynamic(...); -/// nk_widget(...); -/// nk_tree_pop(ctx); -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// ----------------------------|------------------------------------------- -/// nk_tree_push | Start a collapsable UI section with internal state management -/// nk_tree_push_id | Start a collapsable UI section with internal state management callable in a look -/// nk_tree_push_hashed | Start a collapsable UI section with internal state management with full control over internal unique ID use to store state -/// nk_tree_image_push | Start a collapsable UI section with image and label header -/// nk_tree_image_push_id | Start a collapsable UI section with image and label header and internal state management callable in a look -/// nk_tree_image_push_hashed | Start a collapsable UI section with image and label header and internal state management with full control over internal unique ID use to store state -/// nk_tree_pop | Ends a collapsable UI section -// -/// nk_tree_state_push | Start a collapsable UI section with external state management -/// nk_tree_state_image_push | Start a collapsable UI section with image and label header and external state management -/// nk_tree_state_pop | Ends a collapsabale UI section -/// -/// #### nk_tree_type -/// Flag | Description -/// ----------------|---------------------------------------- -/// NK_TREE_NODE | Highlighted tree header to mark a collapsable UI section -/// NK_TREE_TAB | Non-highighted tree header closer to tree representations -*/ -/*/// #### nk_tree_push -/// Starts a collapsable UI section with internal state management -/// !!! WARNING -/// To keep track of the runtime tree collapsable state this function uses -/// defines `__FILE__` and `__LINE__` to generate a unique ID. If you want -/// to call this function in a loop please use `nk_tree_push_id` or -/// `nk_tree_push_hashed` instead. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_push(ctx, type, title, state) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -/*/// #### nk_tree_push_id -/// Starts a collapsable UI section with internal state management callable in a look -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_push_id(ctx, type, title, state, id) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __id__ | Loop counter index if this function is called in a loop -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -/*/// #### nk_tree_push_hashed -/// Start a collapsable UI section with internal state management with full -/// control over internal unique ID used to store state -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __hash__ | Memory block or string to generate the ID from -/// __len__ | Size of passed memory block or string in __hash__ -/// __seed__ | Seeding value if this function is called in a loop or default to `0` -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/*/// #### nk_tree_image_push -/// Start a collapsable UI section with image and label header -/// !!! WARNING -/// To keep track of the runtime tree collapsable state this function uses -/// defines `__FILE__` and `__LINE__` to generate a unique ID. If you want -/// to call this function in a loop please use `nk_tree_image_push_id` or -/// `nk_tree_image_push_hashed` instead. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_image_push(ctx, type, img, title, state) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __img__ | Image to display inside the header on the left of the label -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -/*/// #### nk_tree_image_push_id -/// Start a collapsable UI section with image and label header and internal state -/// management callable in a look -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_image_push_id(ctx, type, img, title, state, id) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __img__ | Image to display inside the header on the left of the label -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __id__ | Loop counter index if this function is called in a loop -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -/*/// #### nk_tree_image_push_hashed -/// Start a collapsable UI section with internal state management with full -/// control over internal unique ID used to store state -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __img__ | Image to display inside the header on the left of the label -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __hash__ | Memory block or string to generate the ID from -/// __len__ | Size of passed memory block or string in __hash__ -/// __seed__ | Seeding value if this function is called in a loop or default to `0` -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/*/// #### nk_tree_pop -/// Ends a collapsabale UI section -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_tree_pop(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -*/ -NK_API void nk_tree_pop(struct nk_context*); -/*/// #### nk_tree_state_push -/// Start a collapsable UI section with external state management -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Persistent state to update -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -/*/// #### nk_tree_state_image_push -/// Start a collapsable UI section with image and label header and external state management -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -/// __img__ | Image to display inside the header on the left of the label -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Persistent state to update -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -/*/// #### nk_tree_state_pop -/// Ends a collapsabale UI section -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_tree_state_pop(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -*/ -NK_API void nk_tree_state_pop(struct nk_context*); - -#define nk_tree_element_push(ctx, type, title, state, sel) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -#define nk_tree_element_push_id(ctx, type, title, state, sel, id) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -NK_API nk_bool nk_tree_element_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len, int seed); -NK_API nk_bool nk_tree_element_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len,int seed); -NK_API void nk_tree_element_pop(struct nk_context*); - -/* ============================================================================= - * - * LIST VIEW - * - * ============================================================================= */ -struct nk_list_view { -/* public: */ - int begin, end, count; -/* private: */ - int total_height; - struct nk_context *ctx; - nk_uint *scroll_pointer; - nk_uint scroll_value; -}; -NK_API nk_bool nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count); -NK_API void nk_list_view_end(struct nk_list_view*); -/* ============================================================================= - * - * WIDGET - * - * ============================================================================= */ -enum nk_widget_layout_states { - NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */ - NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */ - NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */ -}; -enum nk_widget_states { - NK_WIDGET_STATE_MODIFIED = NK_FLAG(1), - NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */ - NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */ - NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */ - NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */ - NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */ -}; -NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*); -NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2); -NK_API struct nk_rect nk_widget_bounds(struct nk_context*); -NK_API struct nk_vec2 nk_widget_position(struct nk_context*); -NK_API struct nk_vec2 nk_widget_size(struct nk_context*); -NK_API float nk_widget_width(struct nk_context*); -NK_API float nk_widget_height(struct nk_context*); -NK_API nk_bool nk_widget_is_hovered(struct nk_context*); -NK_API nk_bool nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons); -NK_API nk_bool nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, nk_bool down); -NK_API void nk_spacing(struct nk_context*, int cols); -/* ============================================================================= - * - * TEXT - * - * ============================================================================= */ -enum nk_text_align { - NK_TEXT_ALIGN_LEFT = 0x01, - NK_TEXT_ALIGN_CENTERED = 0x02, - NK_TEXT_ALIGN_RIGHT = 0x04, - NK_TEXT_ALIGN_TOP = 0x08, - NK_TEXT_ALIGN_MIDDLE = 0x10, - NK_TEXT_ALIGN_BOTTOM = 0x20 -}; -enum nk_text_alignment { - NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT, - NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED, - NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT -}; -NK_API void nk_text(struct nk_context*, const char*, int, nk_flags); -NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color); -NK_API void nk_text_wrap(struct nk_context*, const char*, int); -NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color); -NK_API void nk_label(struct nk_context*, const char*, nk_flags align); -NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color); -NK_API void nk_label_wrap(struct nk_context*, const char*); -NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color); -NK_API void nk_image(struct nk_context*, struct nk_image); -NK_API void nk_image_color(struct nk_context*, struct nk_image, struct nk_color); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void nk_labelf(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(3); -NK_API void nk_labelf_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(4); -NK_API void nk_labelf_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(2); -NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(3); -NK_API void nk_labelfv(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3); -NK_API void nk_labelfv_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); -NK_API void nk_labelfv_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); -NK_API void nk_labelfv_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3); -NK_API void nk_value_bool(struct nk_context*, const char *prefix, int); -NK_API void nk_value_int(struct nk_context*, const char *prefix, int); -NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int); -NK_API void nk_value_float(struct nk_context*, const char *prefix, float); -NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color); -#endif -/* ============================================================================= - * - * BUTTON - * - * ============================================================================= */ -NK_API nk_bool nk_button_text(struct nk_context*, const char *title, int len); -NK_API nk_bool nk_button_label(struct nk_context*, const char *title); -NK_API nk_bool nk_button_color(struct nk_context*, struct nk_color); -NK_API nk_bool nk_button_symbol(struct nk_context*, enum nk_symbol_type); -NK_API nk_bool nk_button_image(struct nk_context*, struct nk_image img); -NK_API nk_bool nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment); -NK_API nk_bool nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API nk_bool nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API nk_bool nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment); -NK_API nk_bool nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len); -NK_API nk_bool nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title); -NK_API nk_bool nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type); -NK_API nk_bool nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img); -NK_API nk_bool nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align); -NK_API nk_bool nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API nk_bool nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment); -NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior); -NK_API nk_bool nk_button_push_behavior(struct nk_context*, enum nk_button_behavior); -NK_API nk_bool nk_button_pop_behavior(struct nk_context*); -/* ============================================================================= - * - * CHECKBOX - * - * ============================================================================= */ -NK_API nk_bool nk_check_label(struct nk_context*, const char*, nk_bool active); -NK_API nk_bool nk_check_text(struct nk_context*, const char*, int, nk_bool active); -NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value); -NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value); -NK_API nk_bool nk_checkbox_label(struct nk_context*, const char*, nk_bool *active); -NK_API nk_bool nk_checkbox_text(struct nk_context*, const char*, int, nk_bool *active); -NK_API nk_bool nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value); -NK_API nk_bool nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value); -/* ============================================================================= - * - * RADIO BUTTON - * - * ============================================================================= */ -NK_API nk_bool nk_radio_label(struct nk_context*, const char*, nk_bool *active); -NK_API nk_bool nk_radio_text(struct nk_context*, const char*, int, nk_bool *active); -NK_API nk_bool nk_option_label(struct nk_context*, const char*, nk_bool active); -NK_API nk_bool nk_option_text(struct nk_context*, const char*, int, nk_bool active); -/* ============================================================================= - * - * SELECTABLE - * - * ============================================================================= */ -NK_API nk_bool nk_selectable_label(struct nk_context*, const char*, nk_flags align, nk_bool *value); -NK_API nk_bool nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, nk_bool *value); -NK_API nk_bool nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, nk_bool *value); -NK_API nk_bool nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, nk_bool *value); -NK_API nk_bool nk_selectable_symbol_label(struct nk_context*,enum nk_symbol_type, const char*, nk_flags align, nk_bool *value); -NK_API nk_bool nk_selectable_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool *value); - -NK_API nk_bool nk_select_label(struct nk_context*, const char*, nk_flags align, nk_bool value); -NK_API nk_bool nk_select_text(struct nk_context*, const char*, int, nk_flags align, nk_bool value); -NK_API nk_bool nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, nk_bool value); -NK_API nk_bool nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, nk_bool value); -NK_API nk_bool nk_select_symbol_label(struct nk_context*,enum nk_symbol_type, const char*, nk_flags align, nk_bool value); -NK_API nk_bool nk_select_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool value); - -/* ============================================================================= - * - * SLIDER - * - * ============================================================================= */ -NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step); -NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step); -NK_API nk_bool nk_slider_float(struct nk_context*, float min, float *val, float max, float step); -NK_API nk_bool nk_slider_int(struct nk_context*, int min, int *val, int max, int step); -/* ============================================================================= - * - * PROGRESSBAR - * - * ============================================================================= */ -NK_API nk_bool nk_progress(struct nk_context*, nk_size *cur, nk_size max, nk_bool modifyable); -NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, nk_bool modifyable); - -/* ============================================================================= - * - * COLOR PICKER - * - * ============================================================================= */ -NK_API struct nk_colorf nk_color_picker(struct nk_context*, struct nk_colorf, enum nk_color_format); -NK_API nk_bool nk_color_pick(struct nk_context*, struct nk_colorf*, enum nk_color_format); -/* ============================================================================= - * - * PROPERTIES - * - * ============================================================================= -/// ### Properties -/// Properties are the main value modification widgets in Nuklear. Changing a value -/// can be achieved by dragging, adding/removing incremental steps on button click -/// or by directly typing a number. -/// -/// #### Usage -/// Each property requires a unique name for identifaction that is also used for -/// displaying a label. If you want to use the same name multiple times make sure -/// add a '#' before your name. The '#' will not be shown but will generate a -/// unique ID. Each propery also takes in a minimum and maximum value. If you want -/// to make use of the complete number range of a type just use the provided -/// type limits from `limits.h`. For example `INT_MIN` and `INT_MAX` for -/// `nk_property_int` and `nk_propertyi`. In additional each property takes in -/// a increment value that will be added or subtracted if either the increment -/// decrement button is clicked. Finally there is a value for increment per pixel -/// dragged that is added or subtracted from the value. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int value = 0; -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // Input -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// nk_input_xxx(...); -/// } -/// } -/// nk_input_end(&ctx); -/// // -/// // Window -/// if (nk_begin_xxx(...) { -/// // Property -/// nk_layout_row_dynamic(...); -/// nk_property_int(ctx, "ID", INT_MIN, &value, INT_MAX, 1, 1); -/// } -/// nk_end(ctx); -/// // -/// // Draw -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------- -/// nk_property_int | Integer property directly modifing a passed in value -/// nk_property_float | Float property directly modifing a passed in value -/// nk_property_double | Double property directly modifing a passed in value -/// nk_propertyi | Integer property returning the modified int value -/// nk_propertyf | Float property returning the modified float value -/// nk_propertyd | Double property returning the modified double value -/// -*/ -/*/// #### nk_property_int -/// Integer property directly modifing a passed in value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_property_int(struct nk_context *ctx, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Integer pointer to be modified -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -*/ -NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -/*/// #### nk_property_float -/// Float property directly modifing a passed in value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_property_float(struct nk_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Float pointer to be modified -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -*/ -NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -/*/// #### nk_property_double -/// Double property directly modifing a passed in value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_property_double(struct nk_context *ctx, const char *name, double min, double *val, double max, double step, double inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Double pointer to be modified -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -*/ -NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel); -/*/// #### nk_propertyi -/// Integer property modifing a passed in value and returning the new value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, int max, int step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Current integer value to be modified and returned -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -/// -/// Returns the new modified integer value -*/ -NK_API nk_bool nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel); -/*/// #### nk_propertyf -/// Float property modifing a passed in value and returning the new value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_propertyf(struct nk_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Current float value to be modified and returned -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -/// -/// Returns the new modified float value -*/ -NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel); -/*/// #### nk_propertyd -/// Float property modifing a passed in value and returning the new value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_propertyd(struct nk_context *ctx, const char *name, double min, double val, double max, double step, double inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Current double value to be modified and returned -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -/// -/// Returns the new modified double value -*/ -NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel); -/* ============================================================================= - * - * TEXT EDIT - * - * ============================================================================= */ -enum nk_edit_flags { - NK_EDIT_DEFAULT = 0, - NK_EDIT_READ_ONLY = NK_FLAG(0), - NK_EDIT_AUTO_SELECT = NK_FLAG(1), - NK_EDIT_SIG_ENTER = NK_FLAG(2), - NK_EDIT_ALLOW_TAB = NK_FLAG(3), - NK_EDIT_NO_CURSOR = NK_FLAG(4), - NK_EDIT_SELECTABLE = NK_FLAG(5), - NK_EDIT_CLIPBOARD = NK_FLAG(6), - NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7), - NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8), - NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9), - NK_EDIT_MULTILINE = NK_FLAG(10), - NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11) -}; -enum nk_edit_types { - NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE, - NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, - NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD, - NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD -}; -enum nk_edit_events { - NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */ - NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */ - NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */ - NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */ - NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */ -}; -NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter); -NK_API void nk_edit_focus(struct nk_context*, nk_flags flags); -NK_API void nk_edit_unfocus(struct nk_context*); -/* ============================================================================= - * - * CHART - * - * ============================================================================= */ -NK_API nk_bool nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max); -NK_API nk_bool nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max); -NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value); -NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value); -NK_API nk_flags nk_chart_push(struct nk_context*, float); -NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int); -NK_API void nk_chart_end(struct nk_context*); -NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset); -NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset); -/* ============================================================================= - * - * POPUP - * - * ============================================================================= */ -NK_API nk_bool nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds); -NK_API void nk_popup_close(struct nk_context*); -NK_API void nk_popup_end(struct nk_context*); -NK_API void nk_popup_get_scroll(struct nk_context*, nk_uint *offset_x, nk_uint *offset_y); -NK_API void nk_popup_set_scroll(struct nk_context*, nk_uint offset_x, nk_uint offset_y); -/* ============================================================================= - * - * COMBOBOX - * - * ============================================================================= */ -NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size); -NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size); -/* ============================================================================= - * - * ABSTRACT COMBOBOX - * - * ============================================================================= */ -NK_API nk_bool nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size); -NK_API nk_bool nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size); -NK_API nk_bool nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API nk_bool nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment); -NK_API nk_bool nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API nk_bool nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment); -NK_API nk_bool nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API nk_bool nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_combo_close(struct nk_context*); -NK_API void nk_combo_end(struct nk_context*); -/* ============================================================================= - * - * CONTEXTUAL - * - * ============================================================================= */ -NK_API nk_bool nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds); -NK_API nk_bool nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API nk_bool nk_contextual_item_label(struct nk_context*, const char*, nk_flags align); -NK_API nk_bool nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API nk_bool nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API nk_bool nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API nk_bool nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_contextual_close(struct nk_context*); -NK_API void nk_contextual_end(struct nk_context*); -/* ============================================================================= - * - * TOOLTIP - * - * ============================================================================= */ -NK_API void nk_tooltip(struct nk_context*, const char*); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); -NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); -#endif -NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); -NK_API void nk_tooltip_end(struct nk_context*); -/* ============================================================================= - * - * MENU - * - * ============================================================================= */ -NK_API void nk_menubar_begin(struct nk_context*); -NK_API void nk_menubar_end(struct nk_context*); -NK_API nk_bool nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API nk_bool nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API nk_bool nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API nk_bool nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API nk_bool nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API nk_bool nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API nk_bool nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API nk_bool nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API void nk_menu_close(struct nk_context*); -NK_API void nk_menu_end(struct nk_context*); -/* ============================================================================= - * - * STYLE - * - * ============================================================================= */ -enum nk_style_colors { - NK_COLOR_TEXT, - NK_COLOR_WINDOW, - NK_COLOR_HEADER, - NK_COLOR_BORDER, - NK_COLOR_BUTTON, - NK_COLOR_BUTTON_HOVER, - NK_COLOR_BUTTON_ACTIVE, - NK_COLOR_TOGGLE, - NK_COLOR_TOGGLE_HOVER, - NK_COLOR_TOGGLE_CURSOR, - NK_COLOR_SELECT, - NK_COLOR_SELECT_ACTIVE, - NK_COLOR_SLIDER, - NK_COLOR_SLIDER_CURSOR, - NK_COLOR_SLIDER_CURSOR_HOVER, - NK_COLOR_SLIDER_CURSOR_ACTIVE, - NK_COLOR_PROPERTY, - NK_COLOR_EDIT, - NK_COLOR_EDIT_CURSOR, - NK_COLOR_COMBO, - NK_COLOR_CHART, - NK_COLOR_CHART_COLOR, - NK_COLOR_CHART_COLOR_HIGHLIGHT, - NK_COLOR_SCROLLBAR, - NK_COLOR_SCROLLBAR_CURSOR, - NK_COLOR_SCROLLBAR_CURSOR_HOVER, - NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, - NK_COLOR_TAB_HEADER, - NK_COLOR_COUNT -}; -enum nk_style_cursor { - NK_CURSOR_ARROW, - NK_CURSOR_TEXT, - NK_CURSOR_MOVE, - NK_CURSOR_RESIZE_VERTICAL, - NK_CURSOR_RESIZE_HORIZONTAL, - NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT, - NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT, - NK_CURSOR_COUNT -}; -NK_API void nk_style_default(struct nk_context*); -NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*); -NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*); -NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*); -NK_API const char* nk_style_get_color_by_name(enum nk_style_colors); -NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*); -NK_API nk_bool nk_style_set_cursor(struct nk_context*, enum nk_style_cursor); -NK_API void nk_style_show_cursor(struct nk_context*); -NK_API void nk_style_hide_cursor(struct nk_context*); - -NK_API nk_bool nk_style_push_font(struct nk_context*, const struct nk_user_font*); -NK_API nk_bool nk_style_push_float(struct nk_context*, float*, float); -NK_API nk_bool nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2); -NK_API nk_bool nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item); -NK_API nk_bool nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags); -NK_API nk_bool nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color); - -NK_API nk_bool nk_style_pop_font(struct nk_context*); -NK_API nk_bool nk_style_pop_float(struct nk_context*); -NK_API nk_bool nk_style_pop_vec2(struct nk_context*); -NK_API nk_bool nk_style_pop_style_item(struct nk_context*); -NK_API nk_bool nk_style_pop_flags(struct nk_context*); -NK_API nk_bool nk_style_pop_color(struct nk_context*); -/* ============================================================================= - * - * COLOR - * - * ============================================================================= */ -NK_API struct nk_color nk_rgb(int r, int g, int b); -NK_API struct nk_color nk_rgb_iv(const int *rgb); -NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb); -NK_API struct nk_color nk_rgb_f(float r, float g, float b); -NK_API struct nk_color nk_rgb_fv(const float *rgb); -NK_API struct nk_color nk_rgb_cf(struct nk_colorf c); -NK_API struct nk_color nk_rgb_hex(const char *rgb); - -NK_API struct nk_color nk_rgba(int r, int g, int b, int a); -NK_API struct nk_color nk_rgba_u32(nk_uint); -NK_API struct nk_color nk_rgba_iv(const int *rgba); -NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba); -NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a); -NK_API struct nk_color nk_rgba_fv(const float *rgba); -NK_API struct nk_color nk_rgba_cf(struct nk_colorf c); -NK_API struct nk_color nk_rgba_hex(const char *rgb); - -NK_API struct nk_colorf nk_hsva_colorf(float h, float s, float v, float a); -NK_API struct nk_colorf nk_hsva_colorfv(float *c); -NK_API void nk_colorf_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_colorf in); -NK_API void nk_colorf_hsva_fv(float *hsva, struct nk_colorf in); - -NK_API struct nk_color nk_hsv(int h, int s, int v); -NK_API struct nk_color nk_hsv_iv(const int *hsv); -NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv); -NK_API struct nk_color nk_hsv_f(float h, float s, float v); -NK_API struct nk_color nk_hsv_fv(const float *hsv); - -NK_API struct nk_color nk_hsva(int h, int s, int v, int a); -NK_API struct nk_color nk_hsva_iv(const int *hsva); -NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva); -NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a); -NK_API struct nk_color nk_hsva_fv(const float *hsva); - -/* color (conversion nuklear --> user) */ -NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color); -NK_API void nk_color_fv(float *rgba_out, struct nk_color); -NK_API struct nk_colorf nk_color_cf(struct nk_color); -NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color); -NK_API void nk_color_dv(double *rgba_out, struct nk_color); - -NK_API nk_uint nk_color_u32(struct nk_color); -NK_API void nk_color_hex_rgba(char *output, struct nk_color); -NK_API void nk_color_hex_rgb(char *output, struct nk_color); - -NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color); -NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color); -NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color); -NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color); -NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color); -NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color); - -NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color); -NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color); -NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color); -NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color); -NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color); -NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color); -/* ============================================================================= - * - * IMAGE - * - * ============================================================================= */ -NK_API nk_handle nk_handle_ptr(void*); -NK_API nk_handle nk_handle_id(int); -NK_API struct nk_image nk_image_handle(nk_handle); -NK_API struct nk_image nk_image_ptr(void*); -NK_API struct nk_image nk_image_id(int); -NK_API nk_bool nk_image_is_subimage(const struct nk_image* img); -NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region); -/* ============================================================================= - * - * MATH - * - * ============================================================================= */ -NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed); -NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading); - -NK_API struct nk_vec2 nk_vec2(float x, float y); -NK_API struct nk_vec2 nk_vec2i(int x, int y); -NK_API struct nk_vec2 nk_vec2v(const float *xy); -NK_API struct nk_vec2 nk_vec2iv(const int *xy); - -NK_API struct nk_rect nk_get_null_rect(void); -NK_API struct nk_rect nk_rect(float x, float y, float w, float h); -NK_API struct nk_rect nk_recti(int x, int y, int w, int h); -NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size); -NK_API struct nk_rect nk_rectv(const float *xywh); -NK_API struct nk_rect nk_rectiv(const int *xywh); -NK_API struct nk_vec2 nk_rect_pos(struct nk_rect); -NK_API struct nk_vec2 nk_rect_size(struct nk_rect); -/* ============================================================================= - * - * STRING - * - * ============================================================================= */ -NK_API int nk_strlen(const char *str); -NK_API int nk_stricmp(const char *s1, const char *s2); -NK_API int nk_stricmpn(const char *s1, const char *s2, int n); -NK_API int nk_strtoi(const char *str, const char **endptr); -NK_API float nk_strtof(const char *str, const char **endptr); -#ifndef NK_STRTOD -#define NK_STRTOD nk_strtod -NK_API double nk_strtod(const char *str, const char **endptr); -#endif -NK_API int nk_strfilter(const char *text, const char *regexp); -NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score); -NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score); -/* ============================================================================= - * - * UTF-8 - * - * ============================================================================= */ -NK_API int nk_utf_decode(const char*, nk_rune*, int); -NK_API int nk_utf_encode(nk_rune, char*, int); -NK_API int nk_utf_len(const char*, int byte_len); -NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len); -/* =============================================================== - * - * FONT - * - * ===============================================================*/ -/* Font handling in this library was designed to be quite customizable and lets - you decide what you want to use and what you want to provide. There are three - different ways to use the font atlas. The first two will use your font - handling scheme and only requires essential data to run nuklear. The next - slightly more advanced features is font handling with vertex buffer output. - Finally the most complex API wise is using nuklear's font baking API. - - 1.) Using your own implementation without vertex buffer output - -------------------------------------------------------------- - So first up the easiest way to do font handling is by just providing a - `nk_user_font` struct which only requires the height in pixel of the used - font and a callback to calculate the width of a string. This way of handling - fonts is best fitted for using the normal draw shape command API where you - do all the text drawing yourself and the library does not require any kind - of deeper knowledge about which font handling mechanism you use. - IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist - over the complete life time! I know this sucks but it is currently the only - way to switch between fonts. - - float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) - { - your_font_type *type = handle.ptr; - float text_width = ...; - return text_width; - } - - struct nk_user_font font; - font.userdata.ptr = &your_font_class_or_struct; - font.height = your_font_height; - font.width = your_text_width_calculation; - - struct nk_context ctx; - nk_init_default(&ctx, &font); - - 2.) Using your own implementation with vertex buffer output - -------------------------------------------------------------- - While the first approach works fine if you don't want to use the optional - vertex buffer output it is not enough if you do. To get font handling working - for these cases you have to provide two additional parameters inside the - `nk_user_font`. First a texture atlas handle used to draw text as subimages - of a bigger font atlas texture and a callback to query a character's glyph - information (offset, size, ...). So it is still possible to provide your own - font and use the vertex buffer output. - - float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) - { - your_font_type *type = handle.ptr; - float text_width = ...; - return text_width; - } - void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) - { - your_font_type *type = handle.ptr; - glyph.width = ...; - glyph.height = ...; - glyph.xadvance = ...; - glyph.uv[0].x = ...; - glyph.uv[0].y = ...; - glyph.uv[1].x = ...; - glyph.uv[1].y = ...; - glyph.offset.x = ...; - glyph.offset.y = ...; - } - - struct nk_user_font font; - font.userdata.ptr = &your_font_class_or_struct; - font.height = your_font_height; - font.width = your_text_width_calculation; - font.query = query_your_font_glyph; - font.texture.id = your_font_texture; - - struct nk_context ctx; - nk_init_default(&ctx, &font); - - 3.) Nuklear font baker - ------------------------------------ - The final approach if you do not have a font handling functionality or don't - want to use it in this library is by using the optional font baker. - The font baker APIs can be used to create a font plus font atlas texture - and can be used with or without the vertex buffer output. - - It still uses the `nk_user_font` struct and the two different approaches - previously stated still work. The font baker is not located inside - `nk_context` like all other systems since it can be understood as more of - an extension to nuklear and does not really depend on any `nk_context` state. - - Font baker need to be initialized first by one of the nk_font_atlas_init_xxx - functions. If you don't care about memory just call the default version - `nk_font_atlas_init_default` which will allocate all memory from the standard library. - If you want to control memory allocation but you don't care if the allocated - memory is temporary and therefore can be freed directly after the baking process - is over or permanent you can call `nk_font_atlas_init`. - - After successfully initializing the font baker you can add Truetype(.ttf) fonts from - different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`. - functions. Adding font will permanently store each font, font config and ttf memory block(!) - inside the font atlas and allows to reuse the font atlas. If you don't want to reuse - the font baker by for example adding additional fonts you can call - `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end). - - As soon as you added all fonts you wanted you can now start the baking process - for every selected glyph to image by calling `nk_font_atlas_bake`. - The baking process returns image memory, width and height which can be used to - either create your own image object or upload it to any graphics library. - No matter which case you finally have to call `nk_font_atlas_end` which - will free all temporary memory including the font atlas image so make sure - you created our texture beforehand. `nk_font_atlas_end` requires a handle - to your font texture or object and optionally fills a `struct nk_draw_null_texture` - which can be used for the optional vertex output. If you don't want it just - set the argument to `NULL`. - - At this point you are done and if you don't want to reuse the font atlas you - can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration - memory. Finally if you don't use the font atlas and any of it's fonts anymore - you need to call `nk_font_atlas_clear` to free all memory still being used. - - struct nk_font_atlas atlas; - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0); - nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0); - const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32); - nk_font_atlas_end(&atlas, nk_handle_id(texture), 0); - - struct nk_context ctx; - nk_init_default(&ctx, &font->handle); - while (1) { - - } - nk_font_atlas_clear(&atlas); - - The font baker API is probably the most complex API inside this library and - I would suggest reading some of my examples `example/` to get a grip on how - to use the font atlas. There are a number of details I left out. For example - how to merge fonts, configure a font with `nk_font_config` to use other languages, - use another texture coordinate format and a lot more: - - struct nk_font_config cfg = nk_font_config(font_pixel_height); - cfg.merge_mode = nk_false or nk_true; - cfg.range = nk_font_korean_glyph_ranges(); - cfg.coord_type = NK_COORD_PIXEL; - nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg); - -*/ -struct nk_user_font_glyph; -typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len); -typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height, - struct nk_user_font_glyph *glyph, - nk_rune codepoint, nk_rune next_codepoint); - -#if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT) -struct nk_user_font_glyph { - struct nk_vec2 uv[2]; - /* texture coordinates */ - struct nk_vec2 offset; - /* offset between top left and glyph */ - float width, height; - /* size of the glyph */ - float xadvance; - /* offset to the next glyph */ -}; -#endif - -struct nk_user_font { - nk_handle userdata; - /* user provided font handle */ - float height; - /* max height of the font */ - nk_text_width_f width; - /* font string width in pixel callback */ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_query_font_glyph_f query; - /* font glyph callback to query drawing info */ - nk_handle texture; - /* texture handle to the used font atlas or texture */ -#endif -}; - -#ifdef NK_INCLUDE_FONT_BAKING -enum nk_font_coord_type { - NK_COORD_UV, /* texture coordinates inside font glyphs are clamped between 0-1 */ - NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */ -}; - -struct nk_font; -struct nk_baked_font { - float height; - /* height of the font */ - float ascent, descent; - /* font glyphs ascent and descent */ - nk_rune glyph_offset; - /* glyph array offset inside the font glyph baking output array */ - nk_rune glyph_count; - /* number of glyphs of this font inside the glyph baking array output */ - const nk_rune *ranges; - /* font codepoint ranges as pairs of (from/to) and 0 as last element */ -}; - -struct nk_font_config { - struct nk_font_config *next; - /* NOTE: only used internally */ - void *ttf_blob; - /* pointer to loaded TTF file memory block. - * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ - nk_size ttf_size; - /* size of the loaded TTF file memory block - * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ - - unsigned char ttf_data_owned_by_atlas; - /* used inside font atlas: default to: 0*/ - unsigned char merge_mode; - /* merges this font into the last font */ - unsigned char pixel_snap; - /* align every character to pixel boundary (if true set oversample (1,1)) */ - unsigned char oversample_v, oversample_h; - /* rasterize at hight quality for sub-pixel position */ - unsigned char padding[3]; - - float size; - /* baked pixel height of the font */ - enum nk_font_coord_type coord_type; - /* texture coordinate format with either pixel or UV coordinates */ - struct nk_vec2 spacing; - /* extra pixel spacing between glyphs */ - const nk_rune *range; - /* list of unicode ranges (2 values per range, zero terminated) */ - struct nk_baked_font *font; - /* font to setup in the baking process: NOTE: not needed for font atlas */ - nk_rune fallback_glyph; - /* fallback glyph to use if a given rune is not found */ - struct nk_font_config *n; - struct nk_font_config *p; -}; - -struct nk_font_glyph { - nk_rune codepoint; - float xadvance; - float x0, y0, x1, y1, w, h; - float u0, v0, u1, v1; -}; - -struct nk_font { - struct nk_font *next; - struct nk_user_font handle; - struct nk_baked_font info; - float scale; - struct nk_font_glyph *glyphs; - const struct nk_font_glyph *fallback; - nk_rune fallback_codepoint; - nk_handle texture; - struct nk_font_config *config; -}; - -enum nk_font_atlas_format { - NK_FONT_ATLAS_ALPHA8, - NK_FONT_ATLAS_RGBA32 -}; - -struct nk_font_atlas { - void *pixel; - int tex_width; - int tex_height; - - struct nk_allocator permanent; - struct nk_allocator temporary; - - struct nk_recti custom; - struct nk_cursor cursors[NK_CURSOR_COUNT]; - - int glyph_count; - struct nk_font_glyph *glyphs; - struct nk_font *default_font; - struct nk_font *fonts; - struct nk_font_config *config; - int font_num; -}; - -/* some language glyph codepoint ranges */ -NK_API const nk_rune *nk_font_default_glyph_ranges(void); -NK_API const nk_rune *nk_font_chinese_glyph_ranges(void); -NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void); -NK_API const nk_rune *nk_font_korean_glyph_ranges(void); - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_font_atlas_init_default(struct nk_font_atlas*); -#endif -NK_API void nk_font_atlas_init(struct nk_font_atlas*, struct nk_allocator*); -NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, struct nk_allocator *persistent, struct nk_allocator *transient); -NK_API void nk_font_atlas_begin(struct nk_font_atlas*); -NK_API struct nk_font_config nk_font_config(float pixel_height); -NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*); -#ifdef NK_INCLUDE_DEFAULT_FONT -NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*); -#endif -NK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config); -#ifdef NK_INCLUDE_STANDARD_IO -NK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*); -#endif -NK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*); -NK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config); -NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format); -NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*); -NK_API const struct nk_font_glyph* nk_font_find_glyph(struct nk_font*, nk_rune unicode); -NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas); -NK_API void nk_font_atlas_clear(struct nk_font_atlas*); - -#endif - -/* ============================================================== - * - * MEMORY BUFFER - * - * ===============================================================*/ -/* A basic (double)-buffer with linear allocation and resetting as only - freeing policy. The buffer's main purpose is to control all memory management - inside the GUI toolkit and still leave memory control as much as possible in - the hand of the user while also making sure the library is easy to use if - not as much control is needed. - In general all memory inside this library can be provided from the user in - three different ways. - - The first way and the one providing most control is by just passing a fixed - size memory block. In this case all control lies in the hand of the user - since he can exactly control where the memory comes from and how much memory - the library should consume. Of course using the fixed size API removes the - ability to automatically resize a buffer if not enough memory is provided so - you have to take over the resizing. While being a fixed sized buffer sounds - quite limiting, it is very effective in this library since the actual memory - consumption is quite stable and has a fixed upper bound for a lot of cases. - - If you don't want to think about how much memory the library should allocate - at all time or have a very dynamic UI with unpredictable memory consumption - habits but still want control over memory allocation you can use the dynamic - allocator based API. The allocator consists of two callbacks for allocating - and freeing memory and optional userdata so you can plugin your own allocator. - - The final and easiest way can be used by defining - NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory - allocation functions malloc and free and takes over complete control over - memory in this library. -*/ -struct nk_memory_status { - void *memory; - unsigned int type; - nk_size size; - nk_size allocated; - nk_size needed; - nk_size calls; -}; - -enum nk_allocation_type { - NK_BUFFER_FIXED, - NK_BUFFER_DYNAMIC -}; - -enum nk_buffer_allocation_type { - NK_BUFFER_FRONT, - NK_BUFFER_BACK, - NK_BUFFER_MAX -}; - -struct nk_buffer_marker { - nk_bool active; - nk_size offset; -}; - -struct nk_memory {void *ptr;nk_size size;}; -struct nk_buffer { - struct nk_buffer_marker marker[NK_BUFFER_MAX]; - /* buffer marker to free a buffer to a certain offset */ - struct nk_allocator pool; - /* allocator callback for dynamic buffers */ - enum nk_allocation_type type; - /* memory management type */ - struct nk_memory memory; - /* memory and size of the current memory block */ - float grow_factor; - /* growing factor for dynamic memory management */ - nk_size allocated; - /* total amount of memory allocated */ - nk_size needed; - /* totally consumed memory given that enough memory is present */ - nk_size calls; - /* number of allocation calls */ - nk_size size; - /* current size of the buffer */ -}; - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_buffer_init_default(struct nk_buffer*); -#endif -NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size); -NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size); -NK_API void nk_buffer_info(struct nk_memory_status*, struct nk_buffer*); -NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align); -NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type); -NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type); -NK_API void nk_buffer_clear(struct nk_buffer*); -NK_API void nk_buffer_free(struct nk_buffer*); -NK_API void *nk_buffer_memory(struct nk_buffer*); -NK_API const void *nk_buffer_memory_const(const struct nk_buffer*); -NK_API nk_size nk_buffer_total(struct nk_buffer*); - -/* ============================================================== - * - * STRING - * - * ===============================================================*/ -/* Basic string buffer which is only used in context with the text editor - * to manage and manipulate dynamic or fixed size string content. This is _NOT_ - * the default string handling method. The only instance you should have any contact - * with this API is if you interact with an `nk_text_edit` object inside one of the - * copy and paste functions and even there only for more advanced cases. */ -struct nk_str { - struct nk_buffer buffer; - int len; /* in codepoints/runes/glyphs */ -}; - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_str_init_default(struct nk_str*); -#endif -NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size); -NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size); -NK_API void nk_str_clear(struct nk_str*); -NK_API void nk_str_free(struct nk_str*); - -NK_API int nk_str_append_text_char(struct nk_str*, const char*, int); -NK_API int nk_str_append_str_char(struct nk_str*, const char*); -NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int); -NK_API int nk_str_append_str_utf8(struct nk_str*, const char*); -NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int); -NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*); - -NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int); - -NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*); -NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*); -NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int); -NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*); - -NK_API void nk_str_remove_chars(struct nk_str*, int len); -NK_API void nk_str_remove_runes(struct nk_str *str, int len); -NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len); -NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len); - -NK_API char *nk_str_at_char(struct nk_str*, int pos); -NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len); -NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos); -NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos); -NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len); - -NK_API char *nk_str_get(struct nk_str*); -NK_API const char *nk_str_get_const(const struct nk_str*); -NK_API int nk_str_len(struct nk_str*); -NK_API int nk_str_len_char(struct nk_str*); - -/*=============================================================== - * - * TEXT EDITOR - * - * ===============================================================*/ -/* Editing text in this library is handled by either `nk_edit_string` or - * `nk_edit_buffer`. But like almost everything in this library there are multiple - * ways of doing it and a balance between control and ease of use with memory - * as well as functionality controlled by flags. - * - * This library generally allows three different levels of memory control: - * First of is the most basic way of just providing a simple char array with - * string length. This method is probably the easiest way of handling simple - * user text input. Main upside is complete control over memory while the biggest - * downside in comparison with the other two approaches is missing undo/redo. - * - * For UIs that require undo/redo the second way was created. It is based on - * a fixed size nk_text_edit struct, which has an internal undo/redo stack. - * This is mainly useful if you want something more like a text editor but don't want - * to have a dynamically growing buffer. - * - * The final way is using a dynamically growing nk_text_edit struct, which - * has both a default version if you don't care where memory comes from and an - * allocator version if you do. While the text editor is quite powerful for its - * complexity I would not recommend editing gigabytes of data with it. - * It is rather designed for uses cases which make sense for a GUI library not for - * an full blown text editor. - */ -#ifndef NK_TEXTEDIT_UNDOSTATECOUNT -#define NK_TEXTEDIT_UNDOSTATECOUNT 99 -#endif - -#ifndef NK_TEXTEDIT_UNDOCHARCOUNT -#define NK_TEXTEDIT_UNDOCHARCOUNT 999 -#endif - -struct nk_text_edit; -struct nk_clipboard { - nk_handle userdata; - nk_plugin_paste paste; - nk_plugin_copy copy; -}; - -struct nk_text_undo_record { - int where; - short insert_length; - short delete_length; - short char_storage; -}; - -struct nk_text_undo_state { - struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT]; - nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT]; - short undo_point; - short redo_point; - short undo_char_point; - short redo_char_point; -}; - -enum nk_text_edit_type { - NK_TEXT_EDIT_SINGLE_LINE, - NK_TEXT_EDIT_MULTI_LINE -}; - -enum nk_text_edit_mode { - NK_TEXT_EDIT_MODE_VIEW, - NK_TEXT_EDIT_MODE_INSERT, - NK_TEXT_EDIT_MODE_REPLACE -}; - -struct nk_text_edit { - struct nk_clipboard clip; - struct nk_str string; - nk_plugin_filter filter; - struct nk_vec2 scrollbar; - - int cursor; - int select_start; - int select_end; - unsigned char mode; - unsigned char cursor_at_end_of_line; - unsigned char initialized; - unsigned char has_preferred_x; - unsigned char single_line; - unsigned char active; - unsigned char padding1; - float preferred_x; - struct nk_text_undo_state undo; -}; - -/* filter function */ -NK_API nk_bool nk_filter_default(const struct nk_text_edit*, nk_rune unicode); -NK_API nk_bool nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode); -NK_API nk_bool nk_filter_float(const struct nk_text_edit*, nk_rune unicode); -NK_API nk_bool nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode); -NK_API nk_bool nk_filter_hex(const struct nk_text_edit*, nk_rune unicode); -NK_API nk_bool nk_filter_oct(const struct nk_text_edit*, nk_rune unicode); -NK_API nk_bool nk_filter_binary(const struct nk_text_edit*, nk_rune unicode); - -/* text editor */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_textedit_init_default(struct nk_text_edit*); -#endif -NK_API void nk_textedit_init(struct nk_text_edit*, struct nk_allocator*, nk_size size); -NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size); -NK_API void nk_textedit_free(struct nk_text_edit*); -NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len); -NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len); -NK_API void nk_textedit_delete_selection(struct nk_text_edit*); -NK_API void nk_textedit_select_all(struct nk_text_edit*); -NK_API nk_bool nk_textedit_cut(struct nk_text_edit*); -NK_API nk_bool nk_textedit_paste(struct nk_text_edit*, char const*, int len); -NK_API void nk_textedit_undo(struct nk_text_edit*); -NK_API void nk_textedit_redo(struct nk_text_edit*); - -/* =============================================================== - * - * DRAWING - * - * ===============================================================*/ -/* This library was designed to be render backend agnostic so it does - not draw anything to screen. Instead all drawn shapes, widgets - are made of, are buffered into memory and make up a command queue. - Each frame therefore fills the command buffer with draw commands - that then need to be executed by the user and his own render backend. - After that the command buffer needs to be cleared and a new frame can be - started. It is probably important to note that the command buffer is the main - drawing API and the optional vertex buffer API only takes this format and - converts it into a hardware accessible format. - - To use the command queue to draw your own widgets you can access the - command buffer of each window by calling `nk_window_get_canvas` after - previously having called `nk_begin`: - - void draw_red_rectangle_widget(struct nk_context *ctx) - { - struct nk_command_buffer *canvas; - struct nk_input *input = &ctx->input; - canvas = nk_window_get_canvas(ctx); - - struct nk_rect space; - enum nk_widget_layout_states state; - state = nk_widget(&space, ctx); - if (!state) return; - - if (state != NK_WIDGET_ROM) - update_your_widget_by_user_input(...); - nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0)); - } - - if (nk_begin(...)) { - nk_layout_row_dynamic(ctx, 25, 1); - draw_red_rectangle_widget(ctx); - } - nk_end(..) - - Important to know if you want to create your own widgets is the `nk_widget` - call. It allocates space on the panel reserved for this widget to be used, - but also returns the state of the widget space. If your widget is not seen and does - not have to be updated it is '0' and you can just return. If it only has - to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both - update and draw your widget. The reason for separating is to only draw and - update what is actually necessary which is crucial for performance. -*/ -enum nk_command_type { - NK_COMMAND_NOP, - NK_COMMAND_SCISSOR, - NK_COMMAND_LINE, - NK_COMMAND_CURVE, - NK_COMMAND_RECT, - NK_COMMAND_RECT_FILLED, - NK_COMMAND_RECT_MULTI_COLOR, - NK_COMMAND_CIRCLE, - NK_COMMAND_CIRCLE_FILLED, - NK_COMMAND_ARC, - NK_COMMAND_ARC_FILLED, - NK_COMMAND_TRIANGLE, - NK_COMMAND_TRIANGLE_FILLED, - NK_COMMAND_POLYGON, - NK_COMMAND_POLYGON_FILLED, - NK_COMMAND_POLYLINE, - NK_COMMAND_TEXT, - NK_COMMAND_IMAGE, - NK_COMMAND_CUSTOM -}; - -/* command base and header of every command inside the buffer */ -struct nk_command { - enum nk_command_type type; - nk_size next; -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -struct nk_command_scissor { - struct nk_command header; - short x, y; - unsigned short w, h; -}; - -struct nk_command_line { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i begin; - struct nk_vec2i end; - struct nk_color color; -}; - -struct nk_command_curve { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i begin; - struct nk_vec2i end; - struct nk_vec2i ctrl[2]; - struct nk_color color; -}; - -struct nk_command_rect { - struct nk_command header; - unsigned short rounding; - unsigned short line_thickness; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_rect_filled { - struct nk_command header; - unsigned short rounding; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_rect_multi_color { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_color left; - struct nk_color top; - struct nk_color bottom; - struct nk_color right; -}; - -struct nk_command_triangle { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i a; - struct nk_vec2i b; - struct nk_vec2i c; - struct nk_color color; -}; - -struct nk_command_triangle_filled { - struct nk_command header; - struct nk_vec2i a; - struct nk_vec2i b; - struct nk_vec2i c; - struct nk_color color; -}; - -struct nk_command_circle { - struct nk_command header; - short x, y; - unsigned short line_thickness; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_circle_filled { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_arc { - struct nk_command header; - short cx, cy; - unsigned short r; - unsigned short line_thickness; - float a[2]; - struct nk_color color; -}; - -struct nk_command_arc_filled { - struct nk_command header; - short cx, cy; - unsigned short r; - float a[2]; - struct nk_color color; -}; - -struct nk_command_polygon { - struct nk_command header; - struct nk_color color; - unsigned short line_thickness; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_polygon_filled { - struct nk_command header; - struct nk_color color; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_polyline { - struct nk_command header; - struct nk_color color; - unsigned short line_thickness; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_image { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_image img; - struct nk_color col; -}; - -typedef void (*nk_command_custom_callback)(void *canvas, short x,short y, - unsigned short w, unsigned short h, nk_handle callback_data); -struct nk_command_custom { - struct nk_command header; - short x, y; - unsigned short w, h; - nk_handle callback_data; - nk_command_custom_callback callback; -}; - -struct nk_command_text { - struct nk_command header; - const struct nk_user_font *font; - struct nk_color background; - struct nk_color foreground; - short x, y; - unsigned short w, h; - float height; - int length; - char string[1]; -}; - -enum nk_command_clipping { - NK_CLIPPING_OFF = nk_false, - NK_CLIPPING_ON = nk_true -}; - -struct nk_command_buffer { - struct nk_buffer *base; - struct nk_rect clip; - int use_clipping; - nk_handle userdata; - nk_size begin, end, last; -}; - -/* shape outlines */ -NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color); -NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color); -NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color); -NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color); -NK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color); -NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color); -NK_API void nk_stroke_polyline(struct nk_command_buffer*, float *points, int point_count, float line_thickness, struct nk_color col); -NK_API void nk_stroke_polygon(struct nk_command_buffer*, float*, int point_count, float line_thickness, struct nk_color); - -/* filled shades */ -NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color); -NK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); -NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color); -NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color); -NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color); -NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color); - -/* misc */ -NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color); -NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color); -NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect); -NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr); - -/* =============================================================== - * - * INPUT - * - * ===============================================================*/ -struct nk_mouse_button { - nk_bool down; - unsigned int clicked; - struct nk_vec2 clicked_pos; -}; -struct nk_mouse { - struct nk_mouse_button buttons[NK_BUTTON_MAX]; - struct nk_vec2 pos; - struct nk_vec2 prev; - struct nk_vec2 delta; - struct nk_vec2 scroll_delta; - unsigned char grab; - unsigned char grabbed; - unsigned char ungrab; -}; - -struct nk_key { - nk_bool down; - unsigned int clicked; -}; -struct nk_keyboard { - struct nk_key keys[NK_KEY_MAX]; - char text[NK_INPUT_MAX]; - int text_len; -}; - -struct nk_input { - struct nk_keyboard keyboard; - struct nk_mouse mouse; -}; - -NK_API nk_bool nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons); -NK_API nk_bool nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API nk_bool nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, nk_bool down); -NK_API nk_bool nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API nk_bool nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, nk_bool down); -NK_API nk_bool nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect); -NK_API nk_bool nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect); -NK_API nk_bool nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect); -NK_API nk_bool nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API nk_bool nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons); -NK_API nk_bool nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons); -NK_API nk_bool nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons); -NK_API nk_bool nk_input_is_key_pressed(const struct nk_input*, enum nk_keys); -NK_API nk_bool nk_input_is_key_released(const struct nk_input*, enum nk_keys); -NK_API nk_bool nk_input_is_key_down(const struct nk_input*, enum nk_keys); - -/* =============================================================== - * - * DRAW LIST - * - * ===============================================================*/ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/* The optional vertex buffer draw list provides a 2D drawing context - with antialiasing functionality which takes basic filled or outlined shapes - or a path and outputs vertexes, elements and draw commands. - The actual draw list API is not required to be used directly while using this - library since converting the default library draw command output is done by - just calling `nk_convert` but I decided to still make this library accessible - since it can be useful. - - The draw list is based on a path buffering and polygon and polyline - rendering API which allows a lot of ways to draw 2D content to screen. - In fact it is probably more powerful than needed but allows even more crazy - things than this library provides by default. -*/ -#ifdef NK_UINT_DRAW_INDEX -typedef nk_uint nk_draw_index; -#else -typedef nk_ushort nk_draw_index; -#endif -enum nk_draw_list_stroke { - NK_STROKE_OPEN = nk_false, - /* build up path has no connection back to the beginning */ - NK_STROKE_CLOSED = nk_true - /* build up path has a connection back to the beginning */ -}; - -enum nk_draw_vertex_layout_attribute { - NK_VERTEX_POSITION, - NK_VERTEX_COLOR, - NK_VERTEX_TEXCOORD, - NK_VERTEX_ATTRIBUTE_COUNT -}; - -enum nk_draw_vertex_layout_format { - NK_FORMAT_SCHAR, - NK_FORMAT_SSHORT, - NK_FORMAT_SINT, - NK_FORMAT_UCHAR, - NK_FORMAT_USHORT, - NK_FORMAT_UINT, - NK_FORMAT_FLOAT, - NK_FORMAT_DOUBLE, - -NK_FORMAT_COLOR_BEGIN, - NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN, - NK_FORMAT_R16G15B16, - NK_FORMAT_R32G32B32, - - NK_FORMAT_R8G8B8A8, - NK_FORMAT_B8G8R8A8, - NK_FORMAT_R16G15B16A16, - NK_FORMAT_R32G32B32A32, - NK_FORMAT_R32G32B32A32_FLOAT, - NK_FORMAT_R32G32B32A32_DOUBLE, - - NK_FORMAT_RGB32, - NK_FORMAT_RGBA32, -NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32, - NK_FORMAT_COUNT -}; - -#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0 -struct nk_draw_vertex_layout_element { - enum nk_draw_vertex_layout_attribute attribute; - enum nk_draw_vertex_layout_format format; - nk_size offset; -}; - -struct nk_draw_command { - unsigned int elem_count; - /* number of elements in the current draw batch */ - struct nk_rect clip_rect; - /* current screen clipping rectangle */ - nk_handle texture; - /* current texture to set */ -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -struct nk_draw_list { - struct nk_rect clip_rect; - struct nk_vec2 circle_vtx[12]; - struct nk_convert_config config; - - struct nk_buffer *buffer; - struct nk_buffer *vertices; - struct nk_buffer *elements; - - unsigned int element_count; - unsigned int vertex_count; - unsigned int cmd_count; - nk_size cmd_offset; - - unsigned int path_count; - unsigned int path_offset; - - enum nk_anti_aliasing line_AA; - enum nk_anti_aliasing shape_AA; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -/* draw list */ -NK_API void nk_draw_list_init(struct nk_draw_list*); -NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa); - -/* drawing */ -#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can)) -NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*); -NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*); -NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*); - -/* path */ -NK_API void nk_draw_list_path_clear(struct nk_draw_list*); -NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos); -NK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max); -NK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments); -NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding); -NK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments); -NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color); -NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness); - -/* stroke */ -NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness); -NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness); -NK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness); -NK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness); -NK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness); -NK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing); - -/* fill */ -NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding); -NK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); -NK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color); -NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs); -NK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing); - -/* misc */ -NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color); -NK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color); -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata); -#endif - -#endif - -/* =============================================================== - * - * GUI - * - * ===============================================================*/ -enum nk_style_item_type { - NK_STYLE_ITEM_COLOR, - NK_STYLE_ITEM_IMAGE -}; - -union nk_style_item_data { - struct nk_image image; - struct nk_color color; -}; - -struct nk_style_item { - enum nk_style_item_type type; - union nk_style_item_data data; -}; - -struct nk_style_text { - struct nk_color color; - struct nk_vec2 padding; -}; - -struct nk_style_button { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* text */ - struct nk_color text_background; - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - nk_flags text_alignment; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; - struct nk_vec2 image_padding; - struct nk_vec2 touch_padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata); - void(*draw_end)(struct nk_command_buffer*, nk_handle userdata); -}; - -struct nk_style_toggle { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - - /* text */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - struct nk_color text_background; - nk_flags text_alignment; - - /* properties */ - struct nk_vec2 padding; - struct nk_vec2 touch_padding; - float spacing; - float border; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_selectable { - /* background (inactive) */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item pressed; - - /* background (active) */ - struct nk_style_item normal_active; - struct nk_style_item hover_active; - struct nk_style_item pressed_active; - - /* text color (inactive) */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_pressed; - - /* text color (active) */ - struct nk_color text_normal_active; - struct nk_color text_hover_active; - struct nk_color text_pressed_active; - struct nk_color text_background; - nk_flags text_alignment; - - /* properties */ - float rounding; - struct nk_vec2 padding; - struct nk_vec2 touch_padding; - struct nk_vec2 image_padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_slider { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* background bar */ - struct nk_color bar_normal; - struct nk_color bar_hover; - struct nk_color bar_active; - struct nk_color bar_filled; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - - /* properties */ - float border; - float rounding; - float bar_height; - struct nk_vec2 padding; - struct nk_vec2 spacing; - struct nk_vec2 cursor_size; - - /* optional buttons */ - int show_buttons; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - enum nk_symbol_type inc_symbol; - enum nk_symbol_type dec_symbol; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_progress { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - struct nk_color cursor_border_color; - - /* properties */ - float rounding; - float border; - float cursor_border; - float cursor_rounding; - struct nk_vec2 padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_scrollbar { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - struct nk_color cursor_border_color; - - /* properties */ - float border; - float rounding; - float border_cursor; - float rounding_cursor; - struct nk_vec2 padding; - - /* optional buttons */ - int show_buttons; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - enum nk_symbol_type inc_symbol; - enum nk_symbol_type dec_symbol; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_edit { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - struct nk_style_scrollbar scrollbar; - - /* cursor */ - struct nk_color cursor_normal; - struct nk_color cursor_hover; - struct nk_color cursor_text_normal; - struct nk_color cursor_text_hover; - - /* text (unselected) */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - - /* text (selected) */ - struct nk_color selected_normal; - struct nk_color selected_hover; - struct nk_color selected_text_normal; - struct nk_color selected_text_hover; - - /* properties */ - float border; - float rounding; - float cursor_size; - struct nk_vec2 scrollbar_size; - struct nk_vec2 padding; - float row_padding; -}; - -struct nk_style_property { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* text */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* symbols */ - enum nk_symbol_type sym_left; - enum nk_symbol_type sym_right; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; - - struct nk_style_edit edit; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_chart { - /* colors */ - struct nk_style_item background; - struct nk_color border_color; - struct nk_color selected_color; - struct nk_color color; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; -}; - -struct nk_style_combo { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* label */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* symbol */ - struct nk_color symbol_normal; - struct nk_color symbol_hover; - struct nk_color symbol_active; - - /* button */ - struct nk_style_button button; - enum nk_symbol_type sym_normal; - enum nk_symbol_type sym_hover; - enum nk_symbol_type sym_active; - - /* properties */ - float border; - float rounding; - struct nk_vec2 content_padding; - struct nk_vec2 button_padding; - struct nk_vec2 spacing; -}; - -struct nk_style_tab { - /* background */ - struct nk_style_item background; - struct nk_color border_color; - struct nk_color text; - - /* button */ - struct nk_style_button tab_maximize_button; - struct nk_style_button tab_minimize_button; - struct nk_style_button node_maximize_button; - struct nk_style_button node_minimize_button; - enum nk_symbol_type sym_minimize; - enum nk_symbol_type sym_maximize; - - /* properties */ - float border; - float rounding; - float indent; - struct nk_vec2 padding; - struct nk_vec2 spacing; -}; - -enum nk_style_header_align { - NK_HEADER_LEFT, - NK_HEADER_RIGHT -}; -struct nk_style_window_header { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - - /* button */ - struct nk_style_button close_button; - struct nk_style_button minimize_button; - enum nk_symbol_type close_symbol; - enum nk_symbol_type minimize_symbol; - enum nk_symbol_type maximize_symbol; - - /* title */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* properties */ - enum nk_style_header_align align; - struct nk_vec2 padding; - struct nk_vec2 label_padding; - struct nk_vec2 spacing; -}; - -struct nk_style_window { - struct nk_style_window_header header; - struct nk_style_item fixed_background; - struct nk_color background; - - struct nk_color border_color; - struct nk_color popup_border_color; - struct nk_color combo_border_color; - struct nk_color contextual_border_color; - struct nk_color menu_border_color; - struct nk_color group_border_color; - struct nk_color tooltip_border_color; - struct nk_style_item scaler; - - float border; - float combo_border; - float contextual_border; - float menu_border; - float group_border; - float tooltip_border; - float popup_border; - float min_row_height_padding; - - float rounding; - struct nk_vec2 spacing; - struct nk_vec2 scrollbar_size; - struct nk_vec2 min_size; - - struct nk_vec2 padding; - struct nk_vec2 group_padding; - struct nk_vec2 popup_padding; - struct nk_vec2 combo_padding; - struct nk_vec2 contextual_padding; - struct nk_vec2 menu_padding; - struct nk_vec2 tooltip_padding; -}; - -struct nk_style { - const struct nk_user_font *font; - const struct nk_cursor *cursors[NK_CURSOR_COUNT]; - const struct nk_cursor *cursor_active; - struct nk_cursor *cursor_last; - int cursor_visible; - - struct nk_style_text text; - struct nk_style_button button; - struct nk_style_button contextual_button; - struct nk_style_button menu_button; - struct nk_style_toggle option; - struct nk_style_toggle checkbox; - struct nk_style_selectable selectable; - struct nk_style_slider slider; - struct nk_style_progress progress; - struct nk_style_property property; - struct nk_style_edit edit; - struct nk_style_chart chart; - struct nk_style_scrollbar scrollh; - struct nk_style_scrollbar scrollv; - struct nk_style_tab tab; - struct nk_style_combo combo; - struct nk_style_window window; -}; - -NK_API struct nk_style_item nk_style_item_image(struct nk_image img); -NK_API struct nk_style_item nk_style_item_color(struct nk_color); -NK_API struct nk_style_item nk_style_item_hide(void); - -/*============================================================== - * PANEL - * =============================================================*/ -#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS -#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16 -#endif -#ifndef NK_CHART_MAX_SLOT -#define NK_CHART_MAX_SLOT 4 -#endif - -enum nk_panel_type { - NK_PANEL_NONE = 0, - NK_PANEL_WINDOW = NK_FLAG(0), - NK_PANEL_GROUP = NK_FLAG(1), - NK_PANEL_POPUP = NK_FLAG(2), - NK_PANEL_CONTEXTUAL = NK_FLAG(4), - NK_PANEL_COMBO = NK_FLAG(5), - NK_PANEL_MENU = NK_FLAG(6), - NK_PANEL_TOOLTIP = NK_FLAG(7) -}; -enum nk_panel_set { - NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP, - NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP, - NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP -}; - -struct nk_chart_slot { - enum nk_chart_type type; - struct nk_color color; - struct nk_color highlight; - float min, max, range; - int count; - struct nk_vec2 last; - int index; -}; - -struct nk_chart { - int slot; - float x, y, w, h; - struct nk_chart_slot slots[NK_CHART_MAX_SLOT]; -}; - -enum nk_panel_row_layout_type { - NK_LAYOUT_DYNAMIC_FIXED = 0, - NK_LAYOUT_DYNAMIC_ROW, - NK_LAYOUT_DYNAMIC_FREE, - NK_LAYOUT_DYNAMIC, - NK_LAYOUT_STATIC_FIXED, - NK_LAYOUT_STATIC_ROW, - NK_LAYOUT_STATIC_FREE, - NK_LAYOUT_STATIC, - NK_LAYOUT_TEMPLATE, - NK_LAYOUT_COUNT -}; -struct nk_row_layout { - enum nk_panel_row_layout_type type; - int index; - float height; - float min_height; - int columns; - const float *ratio; - float item_width; - float item_height; - float item_offset; - float filled; - struct nk_rect item; - int tree_depth; - float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS]; -}; - -struct nk_popup_buffer { - nk_size begin; - nk_size parent; - nk_size last; - nk_size end; - nk_bool active; -}; - -struct nk_menu_state { - float x, y, w, h; - struct nk_scroll offset; -}; - -struct nk_panel { - enum nk_panel_type type; - nk_flags flags; - struct nk_rect bounds; - nk_uint *offset_x; - nk_uint *offset_y; - float at_x, at_y, max_x; - float footer_height; - float header_height; - float border; - unsigned int has_scrolling; - struct nk_rect clip; - struct nk_menu_state menu; - struct nk_row_layout row; - struct nk_chart chart; - struct nk_command_buffer *buffer; - struct nk_panel *parent; -}; - -/*============================================================== - * WINDOW - * =============================================================*/ -#ifndef NK_WINDOW_MAX_NAME -#define NK_WINDOW_MAX_NAME 64 -#endif - -struct nk_table; -enum nk_window_flags { - NK_WINDOW_PRIVATE = NK_FLAG(11), - NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE, - /* special window type growing up in height while being filled to a certain maximum height */ - NK_WINDOW_ROM = NK_FLAG(12), - /* sets window widgets into a read only mode and does not allow input changes */ - NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, - /* prevents all interaction caused by input to either window or widgets inside */ - NK_WINDOW_HIDDEN = NK_FLAG(13), - /* Hides window and stops any window interaction and drawing */ - NK_WINDOW_CLOSED = NK_FLAG(14), - /* Directly closes and frees the window at the end of the frame */ - NK_WINDOW_MINIMIZED = NK_FLAG(15), - /* marks the window as minimized */ - NK_WINDOW_REMOVE_ROM = NK_FLAG(16) - /* Removes read only mode at the end of the window */ -}; - -struct nk_popup_state { - struct nk_window *win; - enum nk_panel_type type; - struct nk_popup_buffer buf; - nk_hash name; - nk_bool active; - unsigned combo_count; - unsigned con_count, con_old; - unsigned active_con; - struct nk_rect header; -}; - -struct nk_edit_state { - nk_hash name; - unsigned int seq; - unsigned int old; - int active, prev; - int cursor; - int sel_start; - int sel_end; - struct nk_scroll scrollbar; - unsigned char mode; - unsigned char single_line; -}; - -struct nk_property_state { - int active, prev; - char buffer[NK_MAX_NUMBER_BUFFER]; - int length; - int cursor; - int select_start; - int select_end; - nk_hash name; - unsigned int seq; - unsigned int old; - int state; -}; - -struct nk_window { - unsigned int seq; - nk_hash name; - char name_string[NK_WINDOW_MAX_NAME]; - nk_flags flags; - - struct nk_rect bounds; - struct nk_scroll scrollbar; - struct nk_command_buffer buffer; - struct nk_panel *layout; - float scrollbar_hiding_timer; - - /* persistent widget state */ - struct nk_property_state property; - struct nk_popup_state popup; - struct nk_edit_state edit; - unsigned int scrolled; - - struct nk_table *tables; - unsigned int table_count; - - /* window list hooks */ - struct nk_window *next; - struct nk_window *prev; - struct nk_window *parent; -}; - -/*============================================================== - * STACK - * =============================================================*/ -/* The style modifier stack can be used to temporarily change a - * property inside `nk_style`. For example if you want a special - * red button you can temporarily push the old button color onto a stack - * draw the button with a red color and then you just pop the old color - * back from the stack: - * - * nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2)); - * - * nk_button(...); - * - * nk_style_pop_style_item(ctx); - * nk_style_pop_style_item(ctx); - * nk_style_pop_style_item(ctx); - * nk_style_pop_vec2(ctx); - * - * Nuklear has a stack for style_items, float properties, vector properties, - * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack - * which can be changed at compile time. - */ -#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE -#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8 -#endif - -#ifndef NK_FONT_STACK_SIZE -#define NK_FONT_STACK_SIZE 8 -#endif - -#ifndef NK_STYLE_ITEM_STACK_SIZE -#define NK_STYLE_ITEM_STACK_SIZE 16 -#endif - -#ifndef NK_FLOAT_STACK_SIZE -#define NK_FLOAT_STACK_SIZE 32 -#endif - -#ifndef NK_VECTOR_STACK_SIZE -#define NK_VECTOR_STACK_SIZE 16 -#endif - -#ifndef NK_FLAGS_STACK_SIZE -#define NK_FLAGS_STACK_SIZE 32 -#endif - -#ifndef NK_COLOR_STACK_SIZE -#define NK_COLOR_STACK_SIZE 32 -#endif - -#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\ - struct nk_config_stack_##name##_element {\ - prefix##_##type *address;\ - prefix##_##type old_value;\ - } -#define NK_CONFIG_STACK(type,size)\ - struct nk_config_stack_##type {\ - int head;\ - struct nk_config_stack_##type##_element elements[size];\ - } - -#define nk_float float -NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item); -NK_CONFIGURATION_STACK_TYPE(nk ,float, float); -NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2); -NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags); -NK_CONFIGURATION_STACK_TYPE(struct nk, color, color); -NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*); -NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior); - -NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE); -NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE); -NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE); -NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE); -NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE); -NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE); -NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE); - -struct nk_configuration_stacks { - struct nk_config_stack_style_item style_items; - struct nk_config_stack_float floats; - struct nk_config_stack_vec2 vectors; - struct nk_config_stack_flags flags; - struct nk_config_stack_color colors; - struct nk_config_stack_user_font fonts; - struct nk_config_stack_button_behavior button_behaviors; -}; - -/*============================================================== - * CONTEXT - * =============================================================*/ -#define NK_VALUE_PAGE_CAPACITY \ - (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2) - -struct nk_table { - unsigned int seq; - unsigned int size; - nk_hash keys[NK_VALUE_PAGE_CAPACITY]; - nk_uint values[NK_VALUE_PAGE_CAPACITY]; - struct nk_table *next, *prev; -}; - -union nk_page_data { - struct nk_table tbl; - struct nk_panel pan; - struct nk_window win; -}; - -struct nk_page_element { - union nk_page_data data; - struct nk_page_element *next; - struct nk_page_element *prev; -}; - -struct nk_page { - unsigned int size; - struct nk_page *next; - struct nk_page_element win[1]; -}; - -struct nk_pool { - struct nk_allocator alloc; - enum nk_allocation_type type; - unsigned int page_count; - struct nk_page *pages; - struct nk_page_element *freelist; - unsigned capacity; - nk_size size; - nk_size cap; -}; - -struct nk_context { -/* public: can be accessed freely */ - struct nk_input input; - struct nk_style style; - struct nk_buffer memory; - struct nk_clipboard clip; - nk_flags last_widget_state; - enum nk_button_behavior button_behavior; - struct nk_configuration_stacks stacks; - float delta_time_seconds; - -/* private: - should only be accessed if you - know what you are doing */ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - struct nk_draw_list draw_list; -#endif -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif - /* text editor objects are quite big because of an internal - * undo/redo stack. Therefore it does not make sense to have one for - * each window for temporary use cases, so I only provide *one* instance - * for all windows. This works because the content is cleared anyway */ - struct nk_text_edit text_edit; - /* draw buffer used for overlay drawing operation like cursor */ - struct nk_command_buffer overlay; - - /* windows */ - int build; - int use_pool; - struct nk_pool pool; - struct nk_window *begin; - struct nk_window *end; - struct nk_window *active; - struct nk_window *current; - struct nk_page_element *freelist; - unsigned int count; - unsigned int seq; -}; - -/* ============================================================== - * MATH - * =============================================================== */ -#define NK_PI 3.141592654f -#define NK_UTF_INVALID 0xFFFD -#define NK_MAX_FLOAT_PRECISION 2 - -#define NK_UNUSED(x) ((void)(x)) -#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) -#define NK_LEN(a) (sizeof(a)/sizeof(a)[0]) -#define NK_ABS(a) (((a) < 0) ? -(a) : (a)) -#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b)) -#define NK_INBOX(px, py, x, y, w, h)\ - (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h)) -#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \ - ((x1 < (x0 + w0)) && (x0 < (x1 + w1)) && \ - (y1 < (y0 + h0)) && (y0 < (y1 + h1))) -#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\ - (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh)) - -#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y) -#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y) -#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y) -#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t)) - -#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i)))) -#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i)))) -#define nk_zero_struct(s) nk_zero(&s, sizeof(s)) - -/* ============================================================== - * ALIGNMENT - * =============================================================== */ -/* Pointer to Integer type conversion for pointer alignment */ -#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/ -# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x)) -# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x)) -#elif !defined(__GNUC__) /* works for compilers other than LLVM */ -# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x]) -# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0)) -#elif defined(NK_USE_FIXED_TYPES) /* used if we have */ -# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x)) -# define NK_PTR_TO_UINT(x) ((uintptr_t)(x)) -#else /* generates warning but works */ -# define NK_UINT_TO_PTR(x) ((void*)(x)) -# define NK_PTR_TO_UINT(x) ((nk_size)(x)) -#endif - -#define NK_ALIGN_PTR(x, mask)\ - (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1)))) -#define NK_ALIGN_PTR_BACK(x, mask)\ - (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1)))) - -#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m)) -#define NK_CONTAINER_OF(ptr,type,member)\ - (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member))) - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -template struct nk_alignof; -template struct nk_helper{enum {value = size_diff};}; -template struct nk_helper{enum {value = nk_alignof::value};}; -template struct nk_alignof{struct Big {T x; char c;}; enum { - diff = sizeof(Big) - sizeof(T), value = nk_helper::value};}; -#define NK_ALIGNOF(t) (nk_alignof::value) -#elif defined(_MSC_VER) -#define NK_ALIGNOF(t) (__alignof(t)) -#else -#define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0) -#endif - -#endif /* NK_NUKLEAR_H_ */ - -#ifdef NK_IMPLEMENTATION - -#ifndef NK_INTERNAL_H -#define NK_INTERNAL_H - -#ifndef NK_POOL_DEFAULT_CAPACITY -#define NK_POOL_DEFAULT_CAPACITY 16 -#endif - -#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE -#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024) -#endif - -#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE -#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024) -#endif - -/* standard library headers */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -#include /* malloc, free */ -#endif -#ifdef NK_INCLUDE_STANDARD_IO -#include /* fopen, fclose,... */ -#endif -#ifdef NK_INCLUDE_STANDARD_VARARGS -#include /* valist, va_start, va_end, ... */ -#endif -#ifndef NK_ASSERT -#include -#define NK_ASSERT(expr) assert(expr) -#endif - -#define NK_DEFAULT (-1) - -#ifndef NK_VSNPRINTF -/* If your compiler does support `vsnprintf` I would highly recommend - * defining this to vsnprintf instead since `vsprintf` is basically - * unbelievable unsafe and should *NEVER* be used. But I have to support - * it since C89 only provides this unsafe version. */ - #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\ - (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\ - defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) - #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a) - #else - #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a) - #endif -#endif - -#define NK_SCHAR_MIN (-127) -#define NK_SCHAR_MAX 127 -#define NK_UCHAR_MIN 0 -#define NK_UCHAR_MAX 256 -#define NK_SSHORT_MIN (-32767) -#define NK_SSHORT_MAX 32767 -#define NK_USHORT_MIN 0 -#define NK_USHORT_MAX 65535 -#define NK_SINT_MIN (-2147483647) -#define NK_SINT_MAX 2147483647 -#define NK_UINT_MIN 0 -#define NK_UINT_MAX 4294967295u - -/* Make sure correct type size: - * This will fire with a negative subscript error if the type sizes - * are set incorrectly by the compiler, and compile out if not */ -NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); -NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); -NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); -NK_STATIC_ASSERT(sizeof(nk_short) == 2); -NK_STATIC_ASSERT(sizeof(nk_uint) == 4); -NK_STATIC_ASSERT(sizeof(nk_int) == 4); -NK_STATIC_ASSERT(sizeof(nk_byte) == 1); -#ifdef NK_INCLUDE_STANDARD_BOOL -NK_STATIC_ASSERT(sizeof(nk_bool) == sizeof(bool)); -#else -NK_STATIC_ASSERT(sizeof(nk_bool) == 4); -#endif - -NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384}; -#define NK_FLOAT_PRECISION 0.00000000000001 - -NK_GLOBAL const struct nk_color nk_red = {255,0,0,255}; -NK_GLOBAL const struct nk_color nk_green = {0,255,0,255}; -NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255}; -NK_GLOBAL const struct nk_color nk_white = {255,255,255,255}; -NK_GLOBAL const struct nk_color nk_black = {0,0,0,255}; -NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; - -/* widget */ -#define nk_widget_state_reset(s)\ - if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\ - (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\ - else (*(s)) = NK_WIDGET_STATE_INACTIVE; - -/* math */ -NK_LIB float nk_inv_sqrt(float n); -#ifndef NK_SIN -NK_LIB float nk_sin(float x); -#endif -#ifndef NK_COS -NK_LIB float nk_cos(float x); -#endif -NK_LIB nk_uint nk_round_up_pow2(nk_uint v); -NK_LIB struct nk_rect nk_shrink_rect(struct nk_rect r, float amount); -NK_LIB struct nk_rect nk_pad_rect(struct nk_rect r, struct nk_vec2 pad); -NK_LIB void nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, float x1, float y1); -NK_LIB double nk_pow(double x, int n); -NK_LIB int nk_ifloord(double x); -NK_LIB int nk_ifloorf(float x); -NK_LIB int nk_iceilf(float x); -NK_LIB int nk_log10(double n); - -/* util */ -enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE}; -NK_LIB nk_bool nk_is_lower(int c); -NK_LIB nk_bool nk_is_upper(int c); -NK_LIB int nk_to_upper(int c); -NK_LIB int nk_to_lower(int c); - -#ifndef NK_MEMCPY -NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n); -#endif -#ifndef NK_MEMSET -NK_LIB void nk_memset(void *ptr, int c0, nk_size size); -#endif -NK_LIB void nk_zero(void *ptr, nk_size size); -NK_LIB char *nk_itoa(char *s, long n); -NK_LIB int nk_string_float_limit(char *string, int prec); -#ifndef NK_DTOA -NK_LIB char *nk_dtoa(char *s, double n); -#endif -NK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count); -NK_LIB struct nk_vec2 nk_text_calculate_text_bounds(const struct nk_user_font *font, const char *begin, int byte_len, float row_height, const char **remaining, struct nk_vec2 *out_offset, int *glyphs, int op); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_LIB int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args); -#endif -#ifdef NK_INCLUDE_STANDARD_IO -NK_LIB char *nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc); -#endif - -/* buffer */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_LIB void* nk_malloc(nk_handle unused, void *old,nk_size size); -NK_LIB void nk_mfree(nk_handle unused, void *ptr); -#endif -NK_LIB void* nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, enum nk_buffer_allocation_type type); -NK_LIB void* nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, nk_size size, nk_size align); -NK_LIB void* nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size); - -/* draw */ -NK_LIB void nk_command_buffer_init(struct nk_command_buffer *cb, struct nk_buffer *b, enum nk_command_clipping clip); -NK_LIB void nk_command_buffer_reset(struct nk_command_buffer *b); -NK_LIB void* nk_command_buffer_push(struct nk_command_buffer* b, enum nk_command_type t, nk_size size); -NK_LIB void nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, struct nk_rect content, struct nk_color background, struct nk_color foreground, float border_width, const struct nk_user_font *font); - -/* buffering */ -NK_LIB void nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *b); -NK_LIB void nk_start(struct nk_context *ctx, struct nk_window *win); -NK_LIB void nk_start_popup(struct nk_context *ctx, struct nk_window *win); -NK_LIB void nk_finish_popup(struct nk_context *ctx, struct nk_window*); -NK_LIB void nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *b); -NK_LIB void nk_finish(struct nk_context *ctx, struct nk_window *w); -NK_LIB void nk_build(struct nk_context *ctx); - -/* text editor */ -NK_LIB void nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, nk_plugin_filter filter); -NK_LIB void nk_textedit_click(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height); -NK_LIB void nk_textedit_drag(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height); -NK_LIB void nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, const struct nk_user_font *font, float row_height); - -/* window */ -enum nk_window_insert_location { - NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */ - NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */ -}; -NK_LIB void *nk_create_window(struct nk_context *ctx); -NK_LIB void nk_remove_window(struct nk_context*, struct nk_window*); -NK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win); -NK_LIB struct nk_window *nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name); -NK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc); - -/* pool */ -NK_LIB void nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, unsigned int capacity); -NK_LIB void nk_pool_free(struct nk_pool *pool); -NK_LIB void nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size); -NK_LIB struct nk_page_element *nk_pool_alloc(struct nk_pool *pool); - -/* page-element */ -NK_LIB struct nk_page_element* nk_create_page_element(struct nk_context *ctx); -NK_LIB void nk_link_page_element_into_freelist(struct nk_context *ctx, struct nk_page_element *elem); -NK_LIB void nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem); - -/* table */ -NK_LIB struct nk_table* nk_create_table(struct nk_context *ctx); -NK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl); -NK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl); -NK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl); -NK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value); -NK_LIB nk_uint *nk_find_value(struct nk_window *win, nk_hash name); - -/* panel */ -NK_LIB void *nk_create_panel(struct nk_context *ctx); -NK_LIB void nk_free_panel(struct nk_context*, struct nk_panel *pan); -NK_LIB nk_bool nk_panel_has_header(nk_flags flags, const char *title); -NK_LIB struct nk_vec2 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type); -NK_LIB float nk_panel_get_border(const struct nk_style *style, nk_flags flags, enum nk_panel_type type); -NK_LIB struct nk_color nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type); -NK_LIB nk_bool nk_panel_is_sub(enum nk_panel_type type); -NK_LIB nk_bool nk_panel_is_nonblock(enum nk_panel_type type); -NK_LIB nk_bool nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type); -NK_LIB void nk_panel_end(struct nk_context *ctx); - -/* layout */ -NK_LIB float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns); -NK_LIB void nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, float height, int cols); -NK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, float height, int cols, int width); -NK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win); -NK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify); -NK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx); -NK_LIB void nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx); - -/* popup */ -NK_LIB nk_bool nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type); - -/* text */ -struct nk_text { - struct nk_vec2 padding; - struct nk_color background; - struct nk_color text; -}; -NK_LIB void nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, nk_flags a, const struct nk_user_font *f); -NK_LIB void nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, const struct nk_user_font *f); - -/* button */ -NK_LIB nk_bool nk_button_behavior(nk_flags *state, struct nk_rect r, const struct nk_input *i, enum nk_button_behavior behavior); -NK_LIB const struct nk_style_item* nk_draw_button(struct nk_command_buffer *out, const struct nk_rect *bounds, nk_flags state, const struct nk_style_button *style); -NK_LIB nk_bool nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, const struct nk_style_button *style, const struct nk_input *in, enum nk_button_behavior behavior, struct nk_rect *content); -NK_LIB void nk_draw_button_text(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const char *txt, int len, nk_flags text_alignment, const struct nk_user_font *font); -NK_LIB nk_bool nk_do_button_text(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *string, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font); -NK_LIB void nk_draw_button_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, enum nk_symbol_type type, const struct nk_user_font *font); -NK_LIB nk_bool nk_do_button_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font); -NK_LIB void nk_draw_button_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const struct nk_image *img); -NK_LIB nk_bool nk_do_button_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, enum nk_button_behavior b, const struct nk_style_button *style, const struct nk_input *in); -NK_LIB void nk_draw_button_text_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, const char *str, int len, enum nk_symbol_type type, const struct nk_user_font *font); -NK_LIB nk_bool nk_do_button_text_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, const char *str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in); -NK_LIB void nk_draw_button_text_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, const char *str, int len, const struct nk_user_font *font, const struct nk_image *img); -NK_LIB nk_bool nk_do_button_text_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, const char* str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in); - -/* toggle */ -enum nk_toggle_type { - NK_TOGGLE_CHECK, - NK_TOGGLE_OPTION -}; -NK_LIB nk_bool nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, nk_flags *state, nk_bool active); -NK_LIB void nk_draw_checkbox(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font); -NK_LIB void nk_draw_option(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font); -NK_LIB nk_bool nk_do_toggle(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, nk_bool *active, const char *str, int len, enum nk_toggle_type type, const struct nk_style_toggle *style, const struct nk_input *in, const struct nk_user_font *font); - -/* progress */ -NK_LIB nk_size nk_progress_behavior(nk_flags *state, struct nk_input *in, struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable); -NK_LIB void nk_draw_progress(struct nk_command_buffer *out, nk_flags state, const struct nk_style_progress *style, const struct nk_rect *bounds, const struct nk_rect *scursor, nk_size value, nk_size max); -NK_LIB nk_size nk_do_progress(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_size value, nk_size max, nk_bool modifiable, const struct nk_style_progress *style, struct nk_input *in); - -/* slider */ -NK_LIB float nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, struct nk_rect *visual_cursor, struct nk_input *in, struct nk_rect bounds, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps); -NK_LIB void nk_draw_slider(struct nk_command_buffer *out, nk_flags state, const struct nk_style_slider *style, const struct nk_rect *bounds, const struct nk_rect *visual_cursor, float min, float value, float max); -NK_LIB float nk_do_slider(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, float min, float val, float max, float step, const struct nk_style_slider *style, struct nk_input *in, const struct nk_user_font *font); - -/* scrollbar */ -NK_LIB float nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, int has_scrolling, const struct nk_rect *scroll, const struct nk_rect *cursor, const struct nk_rect *empty0, const struct nk_rect *empty1, float scroll_offset, float target, float scroll_step, enum nk_orientation o); -NK_LIB void nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, const struct nk_style_scrollbar *style, const struct nk_rect *bounds, const struct nk_rect *scroll); -NK_LIB float nk_do_scrollbarv(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font); -NK_LIB float nk_do_scrollbarh(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font); - -/* selectable */ -NK_LIB void nk_draw_selectable(struct nk_command_buffer *out, nk_flags state, const struct nk_style_selectable *style, nk_bool active, const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym, const char *string, int len, nk_flags align, const struct nk_user_font *font); -NK_LIB nk_bool nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font); -NK_LIB nk_bool nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_image *img, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font); - -/* edit */ -NK_LIB void nk_edit_draw_text(struct nk_command_buffer *out, const struct nk_style_edit *style, float pos_x, float pos_y, float x_offset, const char *text, int byte_len, float row_height, const struct nk_user_font *font, struct nk_color background, struct nk_color foreground, nk_bool is_selected); -NK_LIB nk_flags nk_do_edit(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, struct nk_text_edit *edit, const struct nk_style_edit *style, struct nk_input *in, const struct nk_user_font *font); - -/* color-picker */ -NK_LIB nk_bool nk_color_picker_behavior(nk_flags *state, const struct nk_rect *bounds, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf *color, const struct nk_input *in); -NK_LIB void nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf col); -NK_LIB nk_bool nk_do_color_picker(nk_flags *state, struct nk_command_buffer *out, struct nk_colorf *col, enum nk_color_format fmt, struct nk_rect bounds, struct nk_vec2 padding, const struct nk_input *in, const struct nk_user_font *font); - -/* property */ -enum nk_property_status { - NK_PROPERTY_DEFAULT, - NK_PROPERTY_EDIT, - NK_PROPERTY_DRAG -}; -enum nk_property_filter { - NK_FILTER_INT, - NK_FILTER_FLOAT -}; -enum nk_property_kind { - NK_PROPERTY_INT, - NK_PROPERTY_FLOAT, - NK_PROPERTY_DOUBLE -}; -union nk_property { - int i; - float f; - double d; -}; -struct nk_property_variant { - enum nk_property_kind kind; - union nk_property value; - union nk_property min_value; - union nk_property max_value; - union nk_property step; -}; -NK_LIB struct nk_property_variant nk_property_variant_int(int value, int min_value, int max_value, int step); -NK_LIB struct nk_property_variant nk_property_variant_float(float value, float min_value, float max_value, float step); -NK_LIB struct nk_property_variant nk_property_variant_double(double value, double min_value, double max_value, double step); - -NK_LIB void nk_drag_behavior(nk_flags *state, const struct nk_input *in, struct nk_rect drag, struct nk_property_variant *variant, float inc_per_pixel); -NK_LIB void nk_property_behavior(nk_flags *ws, const struct nk_input *in, struct nk_rect property, struct nk_rect label, struct nk_rect edit, struct nk_rect empty, int *state, struct nk_property_variant *variant, float inc_per_pixel); -NK_LIB void nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, const char *name, int len, const struct nk_user_font *font); -NK_LIB void nk_do_property(nk_flags *ws, struct nk_command_buffer *out, struct nk_rect property, const char *name, struct nk_property_variant *variant, float inc_per_pixel, char *buffer, int *len, int *state, int *cursor, int *select_begin, int *select_end, const struct nk_style_property *style, enum nk_property_filter filter, struct nk_input *in, const struct nk_user_font *font, struct nk_text_edit *text_edit, enum nk_button_behavior behavior); -NK_LIB void nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, float inc_per_pixel, const enum nk_property_filter filter); - -#ifdef NK_INCLUDE_FONT_BAKING - -#define STB_RECT_PACK_IMPLEMENTATION -#define STB_TRUETYPE_IMPLEMENTATION - -/* Allow consumer to define own STBTT_malloc/STBTT_free, and use the font atlas' allocator otherwise */ -#ifndef STBTT_malloc -static void* -nk_stbtt_malloc(nk_size size, void *user_data) { - struct nk_allocator *alloc = (struct nk_allocator *) user_data; - return alloc->alloc(alloc->userdata, 0, size); -} - -static void -nk_stbtt_free(void *ptr, void *user_data) { - struct nk_allocator *alloc = (struct nk_allocator *) user_data; - alloc->free(alloc->userdata, ptr); -} - -#define STBTT_malloc(x,u) nk_stbtt_malloc(x,u) -#define STBTT_free(x,u) nk_stbtt_free(x,u) - -#endif /* STBTT_malloc */ - -#endif /* NK_INCLUDE_FONT_BAKING */ - -#endif - - - - - -/* =============================================================== - * - * MATH - * - * ===============================================================*/ -/* Since nuklear is supposed to work on all systems providing floating point - math without any dependencies I also had to implement my own math functions - for sqrt, sin and cos. Since the actual highly accurate implementations for - the standard library functions are quite complex and I do not need high - precision for my use cases I use approximations. - - Sqrt - ---- - For square root nuklear uses the famous fast inverse square root: - https://en.wikipedia.org/wiki/Fast_inverse_square_root with - slightly tweaked magic constant. While on today's hardware it is - probably not faster it is still fast and accurate enough for - nuklear's use cases. IMPORTANT: this requires float format IEEE 754 - - Sine/Cosine - ----------- - All constants inside both function are generated Remez's minimax - approximations for value range 0...2*PI. The reason why I decided to - approximate exactly that range is that nuklear only needs sine and - cosine to generate circles which only requires that exact range. - In addition I used Remez instead of Taylor for additional precision: - www.lolengine.net/blog/2011/12/21/better-function-approximations. - - The tool I used to generate constants for both sine and cosine - (it can actually approximate a lot more functions) can be - found here: www.lolengine.net/wiki/oss/lolremez -*/ -NK_LIB float -nk_inv_sqrt(float n) -{ - float x2; - const float threehalfs = 1.5f; - union {nk_uint i; float f;} conv = {0}; - conv.f = n; - x2 = n * 0.5f; - conv.i = 0x5f375A84 - (conv.i >> 1); - conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f)); - return conv.f; -} -#ifndef NK_SIN -#define NK_SIN nk_sin -NK_LIB float -nk_sin(float x) -{ - NK_STORAGE const float a0 = +1.91059300966915117e-31f; - NK_STORAGE const float a1 = +1.00086760103908896f; - NK_STORAGE const float a2 = -1.21276126894734565e-2f; - NK_STORAGE const float a3 = -1.38078780785773762e-1f; - NK_STORAGE const float a4 = -2.67353392911981221e-2f; - NK_STORAGE const float a5 = +2.08026600266304389e-2f; - NK_STORAGE const float a6 = -3.03996055049204407e-3f; - NK_STORAGE const float a7 = +1.38235642404333740e-4f; - return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); -} -#endif -#ifndef NK_COS -#define NK_COS nk_cos -NK_LIB float -nk_cos(float x) -{ - /* New implementation. Also generated using lolremez. */ - /* Old version significantly deviated from expected results. */ - NK_STORAGE const float a0 = 9.9995999154986614e-1f; - NK_STORAGE const float a1 = 1.2548995793001028e-3f; - NK_STORAGE const float a2 = -5.0648546280678015e-1f; - NK_STORAGE const float a3 = 1.2942246466519995e-2f; - NK_STORAGE const float a4 = 2.8668384702547972e-2f; - NK_STORAGE const float a5 = 7.3726485210586547e-3f; - NK_STORAGE const float a6 = -3.8510875386947414e-3f; - NK_STORAGE const float a7 = 4.7196604604366623e-4f; - NK_STORAGE const float a8 = -1.8776444013090451e-5f; - return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8))))))); -} -#endif -NK_LIB nk_uint -nk_round_up_pow2(nk_uint v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} -NK_LIB double -nk_pow(double x, int n) -{ - /* check the sign of n */ - double r = 1; - int plus = n >= 0; - n = (plus) ? n : -n; - while (n > 0) { - if ((n & 1) == 1) - r *= x; - n /= 2; - x *= x; - } - return plus ? r : 1.0 / r; -} -NK_LIB int -nk_ifloord(double x) -{ - x = (double)((int)x - ((x < 0.0) ? 1 : 0)); - return (int)x; -} -NK_LIB int -nk_ifloorf(float x) -{ - x = (float)((int)x - ((x < 0.0f) ? 1 : 0)); - return (int)x; -} -NK_LIB int -nk_iceilf(float x) -{ - if (x >= 0) { - int i = (int)x; - return (x > i) ? i+1: i; - } else { - int t = (int)x; - float r = x - (float)t; - return (r > 0.0f) ? t+1: t; - } -} -NK_LIB int -nk_log10(double n) -{ - int neg; - int ret; - int exp = 0; - - neg = (n < 0) ? 1 : 0; - ret = (neg) ? (int)-n : (int)n; - while ((ret / 10) > 0) { - ret /= 10; - exp++; - } - if (neg) exp = -exp; - return exp; -} -NK_API struct nk_rect -nk_get_null_rect(void) -{ - return nk_null_rect; -} -NK_API struct nk_rect -nk_rect(float x, float y, float w, float h) -{ - struct nk_rect r; - r.x = x; r.y = y; - r.w = w; r.h = h; - return r; -} -NK_API struct nk_rect -nk_recti(int x, int y, int w, int h) -{ - struct nk_rect r; - r.x = (float)x; - r.y = (float)y; - r.w = (float)w; - r.h = (float)h; - return r; -} -NK_API struct nk_rect -nk_recta(struct nk_vec2 pos, struct nk_vec2 size) -{ - return nk_rect(pos.x, pos.y, size.x, size.y); -} -NK_API struct nk_rect -nk_rectv(const float *r) -{ - return nk_rect(r[0], r[1], r[2], r[3]); -} -NK_API struct nk_rect -nk_rectiv(const int *r) -{ - return nk_recti(r[0], r[1], r[2], r[3]); -} -NK_API struct nk_vec2 -nk_rect_pos(struct nk_rect r) -{ - struct nk_vec2 ret; - ret.x = r.x; ret.y = r.y; - return ret; -} -NK_API struct nk_vec2 -nk_rect_size(struct nk_rect r) -{ - struct nk_vec2 ret; - ret.x = r.w; ret.y = r.h; - return ret; -} -NK_LIB struct nk_rect -nk_shrink_rect(struct nk_rect r, float amount) -{ - struct nk_rect res; - r.w = NK_MAX(r.w, 2 * amount); - r.h = NK_MAX(r.h, 2 * amount); - res.x = r.x + amount; - res.y = r.y + amount; - res.w = r.w - 2 * amount; - res.h = r.h - 2 * amount; - return res; -} -NK_LIB struct nk_rect -nk_pad_rect(struct nk_rect r, struct nk_vec2 pad) -{ - r.w = NK_MAX(r.w, 2 * pad.x); - r.h = NK_MAX(r.h, 2 * pad.y); - r.x += pad.x; r.y += pad.y; - r.w -= 2 * pad.x; - r.h -= 2 * pad.y; - return r; -} -NK_API struct nk_vec2 -nk_vec2(float x, float y) -{ - struct nk_vec2 ret; - ret.x = x; ret.y = y; - return ret; -} -NK_API struct nk_vec2 -nk_vec2i(int x, int y) -{ - struct nk_vec2 ret; - ret.x = (float)x; - ret.y = (float)y; - return ret; -} -NK_API struct nk_vec2 -nk_vec2v(const float *v) -{ - return nk_vec2(v[0], v[1]); -} -NK_API struct nk_vec2 -nk_vec2iv(const int *v) -{ - return nk_vec2i(v[0], v[1]); -} -NK_LIB void -nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, - float x1, float y1) -{ - NK_ASSERT(a); - NK_ASSERT(clip); - clip->x = NK_MAX(a->x, x0); - clip->y = NK_MAX(a->y, y0); - clip->w = NK_MIN(a->x + a->w, x1) - clip->x; - clip->h = NK_MIN(a->y + a->h, y1) - clip->y; - clip->w = NK_MAX(0, clip->w); - clip->h = NK_MAX(0, clip->h); -} - -NK_API void -nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, - float pad_x, float pad_y, enum nk_heading direction) -{ - float w_half, h_half; - NK_ASSERT(result); - - r.w = NK_MAX(2 * pad_x, r.w); - r.h = NK_MAX(2 * pad_y, r.h); - r.w = r.w - 2 * pad_x; - r.h = r.h - 2 * pad_y; - - r.x = r.x + pad_x; - r.y = r.y + pad_y; - - w_half = r.w / 2.0f; - h_half = r.h / 2.0f; - - if (direction == NK_UP) { - result[0] = nk_vec2(r.x + w_half, r.y); - result[1] = nk_vec2(r.x + r.w, r.y + r.h); - result[2] = nk_vec2(r.x, r.y + r.h); - } else if (direction == NK_RIGHT) { - result[0] = nk_vec2(r.x, r.y); - result[1] = nk_vec2(r.x + r.w, r.y + h_half); - result[2] = nk_vec2(r.x, r.y + r.h); - } else if (direction == NK_DOWN) { - result[0] = nk_vec2(r.x, r.y); - result[1] = nk_vec2(r.x + r.w, r.y); - result[2] = nk_vec2(r.x + w_half, r.y + r.h); - } else { - result[0] = nk_vec2(r.x, r.y + h_half); - result[1] = nk_vec2(r.x + r.w, r.y); - result[2] = nk_vec2(r.x + r.w, r.y + r.h); - } -} - - - - - -/* =============================================================== - * - * UTIL - * - * ===============================================================*/ -NK_INTERN int nk_str_match_here(const char *regexp, const char *text); -NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text); -NK_LIB nk_bool nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);} -NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);} -NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;} -NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;} - -#ifndef NK_MEMCPY -#define NK_MEMCPY nk_memcopy -NK_LIB void* -nk_memcopy(void *dst0, const void *src0, nk_size length) -{ - nk_ptr t; - char *dst = (char*)dst0; - const char *src = (const char*)src0; - if (length == 0 || dst == src) - goto done; - - #define nk_word int - #define nk_wsize sizeof(nk_word) - #define nk_wmask (nk_wsize-1) - #define NK_TLOOP(s) if (t) NK_TLOOP1(s) - #define NK_TLOOP1(s) do { s; } while (--t) - - if (dst < src) { - t = (nk_ptr)src; /* only need low bits */ - if ((t | (nk_ptr)dst) & nk_wmask) { - if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize) - t = length; - else - t = nk_wsize - (t & nk_wmask); - length -= t; - NK_TLOOP1(*dst++ = *src++); - } - t = length / nk_wsize; - NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src; - src += nk_wsize; dst += nk_wsize); - t = length & nk_wmask; - NK_TLOOP(*dst++ = *src++); - } else { - src += length; - dst += length; - t = (nk_ptr)src; - if ((t | (nk_ptr)dst) & nk_wmask) { - if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize) - t = length; - else - t &= nk_wmask; - length -= t; - NK_TLOOP1(*--dst = *--src); - } - t = length / nk_wsize; - NK_TLOOP(src -= nk_wsize; dst -= nk_wsize; - *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src); - t = length & nk_wmask; - NK_TLOOP(*--dst = *--src); - } - #undef nk_word - #undef nk_wsize - #undef nk_wmask - #undef NK_TLOOP - #undef NK_TLOOP1 -done: - return (dst0); -} -#endif -#ifndef NK_MEMSET -#define NK_MEMSET nk_memset -NK_LIB void -nk_memset(void *ptr, int c0, nk_size size) -{ - #define nk_word unsigned - #define nk_wsize sizeof(nk_word) - #define nk_wmask (nk_wsize - 1) - nk_byte *dst = (nk_byte*)ptr; - unsigned c = 0; - nk_size t = 0; - - if ((c = (nk_byte)c0) != 0) { - c = (c << 8) | c; /* at least 16-bits */ - if (sizeof(unsigned int) > 2) - c = (c << 16) | c; /* at least 32-bits*/ - } - - /* too small of a word count */ - dst = (nk_byte*)ptr; - if (size < 3 * nk_wsize) { - while (size--) *dst++ = (nk_byte)c0; - return; - } - - /* align destination */ - if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) { - t = nk_wsize -t; - size -= t; - do { - *dst++ = (nk_byte)c0; - } while (--t != 0); - } - - /* fill word */ - t = size / nk_wsize; - do { - *(nk_word*)((void*)dst) = c; - dst += nk_wsize; - } while (--t != 0); - - /* fill trailing bytes */ - t = (size & nk_wmask); - if (t != 0) { - do { - *dst++ = (nk_byte)c0; - } while (--t != 0); - } - - #undef nk_word - #undef nk_wsize - #undef nk_wmask -} -#endif -NK_LIB void -nk_zero(void *ptr, nk_size size) -{ - NK_ASSERT(ptr); - NK_MEMSET(ptr, 0, size); -} -NK_API int -nk_strlen(const char *str) -{ - int siz = 0; - NK_ASSERT(str); - while (str && *str++ != '\0') siz++; - return siz; -} -NK_API int -nk_strtoi(const char *str, const char **endptr) -{ - int neg = 1; - const char *p = str; - int value = 0; - - NK_ASSERT(str); - if (!str) return 0; - - /* skip whitespace */ - while (*p == ' ') p++; - if (*p == '-') { - neg = -1; - p++; - } - while (*p && *p >= '0' && *p <= '9') { - value = value * 10 + (int) (*p - '0'); - p++; - } - if (endptr) - *endptr = p; - return neg*value; -} -NK_API double -nk_strtod(const char *str, const char **endptr) -{ - double m; - double neg = 1.0; - const char *p = str; - double value = 0; - double number = 0; - - NK_ASSERT(str); - if (!str) return 0; - - /* skip whitespace */ - while (*p == ' ') p++; - if (*p == '-') { - neg = -1.0; - p++; - } - - while (*p && *p != '.' && *p != 'e') { - value = value * 10.0 + (double) (*p - '0'); - p++; - } - - if (*p == '.') { - p++; - for(m = 0.1; *p && *p != 'e'; p++ ) { - value = value + (double) (*p - '0') * m; - m *= 0.1; - } - } - if (*p == 'e') { - int i, pow, div; - p++; - if (*p == '-') { - div = nk_true; - p++; - } else if (*p == '+') { - div = nk_false; - p++; - } else div = nk_false; - - for (pow = 0; *p; p++) - pow = pow * 10 + (int) (*p - '0'); - - for (m = 1.0, i = 0; i < pow; i++) - m *= 10.0; - - if (div) - value /= m; - else value *= m; - } - number = value * neg; - if (endptr) - *endptr = p; - return number; -} -NK_API float -nk_strtof(const char *str, const char **endptr) -{ - float float_value; - double double_value; - double_value = NK_STRTOD(str, endptr); - float_value = (float)double_value; - return float_value; -} -NK_API int -nk_stricmp(const char *s1, const char *s2) -{ - nk_int c1,c2,d; - do { - c1 = *s1++; - c2 = *s2++; - d = c1 - c2; - while (d) { - if (c1 <= 'Z' && c1 >= 'A') { - d += ('a' - 'A'); - if (!d) break; - } - if (c2 <= 'Z' && c2 >= 'A') { - d -= ('a' - 'A'); - if (!d) break; - } - return ((d >= 0) << 1) - 1; - } - } while (c1); - return 0; -} -NK_API int -nk_stricmpn(const char *s1, const char *s2, int n) -{ - int c1,c2,d; - NK_ASSERT(n >= 0); - do { - c1 = *s1++; - c2 = *s2++; - if (!n--) return 0; - - d = c1 - c2; - while (d) { - if (c1 <= 'Z' && c1 >= 'A') { - d += ('a' - 'A'); - if (!d) break; - } - if (c2 <= 'Z' && c2 >= 'A') { - d -= ('a' - 'A'); - if (!d) break; - } - return ((d >= 0) << 1) - 1; - } - } while (c1); - return 0; -} -NK_INTERN int -nk_str_match_here(const char *regexp, const char *text) -{ - if (regexp[0] == '\0') - return 1; - if (regexp[1] == '*') - return nk_str_match_star(regexp[0], regexp+2, text); - if (regexp[0] == '$' && regexp[1] == '\0') - return *text == '\0'; - if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) - return nk_str_match_here(regexp+1, text+1); - return 0; -} -NK_INTERN int -nk_str_match_star(int c, const char *regexp, const char *text) -{ - do {/* a '* matches zero or more instances */ - if (nk_str_match_here(regexp, text)) - return 1; - } while (*text != '\0' && (*text++ == c || c == '.')); - return 0; -} -NK_API int -nk_strfilter(const char *text, const char *regexp) -{ - /* - c matches any literal character c - . matches any single character - ^ matches the beginning of the input string - $ matches the end of the input string - * matches zero or more occurrences of the previous character*/ - if (regexp[0] == '^') - return nk_str_match_here(regexp+1, text); - do { /* must look even if string is empty */ - if (nk_str_match_here(regexp, text)) - return 1; - } while (*text++ != '\0'); - return 0; -} -NK_API int -nk_strmatch_fuzzy_text(const char *str, int str_len, - const char *pattern, int *out_score) -{ - /* Returns true if each character in pattern is found sequentially within str - * if found then out_score is also set. Score value has no intrinsic meaning. - * Range varies with pattern. Can only compare scores with same search pattern. */ - - /* bonus for adjacent matches */ - #define NK_ADJACENCY_BONUS 5 - /* bonus if match occurs after a separator */ - #define NK_SEPARATOR_BONUS 10 - /* bonus if match is uppercase and prev is lower */ - #define NK_CAMEL_BONUS 10 - /* penalty applied for every letter in str before the first match */ - #define NK_LEADING_LETTER_PENALTY (-3) - /* maximum penalty for leading letters */ - #define NK_MAX_LEADING_LETTER_PENALTY (-9) - /* penalty for every letter that doesn't matter */ - #define NK_UNMATCHED_LETTER_PENALTY (-1) - - /* loop variables */ - int score = 0; - char const * pattern_iter = pattern; - int str_iter = 0; - int prev_matched = nk_false; - int prev_lower = nk_false; - /* true so if first letter match gets separator bonus*/ - int prev_separator = nk_true; - - /* use "best" matched letter if multiple string letters match the pattern */ - char const * best_letter = 0; - int best_letter_score = 0; - - /* loop over strings */ - NK_ASSERT(str); - NK_ASSERT(pattern); - if (!str || !str_len || !pattern) return 0; - while (str_iter < str_len) - { - const char pattern_letter = *pattern_iter; - const char str_letter = str[str_iter]; - - int next_match = *pattern_iter != '\0' && - nk_to_lower(pattern_letter) == nk_to_lower(str_letter); - int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter); - - int advanced = next_match && best_letter; - int pattern_repeat = best_letter && *pattern_iter != '\0'; - pattern_repeat = pattern_repeat && - nk_to_lower(*best_letter) == nk_to_lower(pattern_letter); - - if (advanced || pattern_repeat) { - score += best_letter_score; - best_letter = 0; - best_letter_score = 0; - } - - if (next_match || rematch) - { - int new_score = 0; - /* Apply penalty for each letter before the first pattern match */ - if (pattern_iter == pattern) { - int count = (int)(&str[str_iter] - str); - int penalty = NK_LEADING_LETTER_PENALTY * count; - if (penalty < NK_MAX_LEADING_LETTER_PENALTY) - penalty = NK_MAX_LEADING_LETTER_PENALTY; - - score += penalty; - } - - /* apply bonus for consecutive bonuses */ - if (prev_matched) - new_score += NK_ADJACENCY_BONUS; - - /* apply bonus for matches after a separator */ - if (prev_separator) - new_score += NK_SEPARATOR_BONUS; - - /* apply bonus across camel case boundaries */ - if (prev_lower && nk_is_upper(str_letter)) - new_score += NK_CAMEL_BONUS; - - /* update pattern iter IFF the next pattern letter was matched */ - if (next_match) - ++pattern_iter; - - /* update best letter in str which may be for a "next" letter or a rematch */ - if (new_score >= best_letter_score) { - /* apply penalty for now skipped letter */ - if (best_letter != 0) - score += NK_UNMATCHED_LETTER_PENALTY; - - best_letter = &str[str_iter]; - best_letter_score = new_score; - } - prev_matched = nk_true; - } else { - score += NK_UNMATCHED_LETTER_PENALTY; - prev_matched = nk_false; - } - - /* separators should be more easily defined */ - prev_lower = nk_is_lower(str_letter) != 0; - prev_separator = str_letter == '_' || str_letter == ' '; - - ++str_iter; - } - - /* apply score for last match */ - if (best_letter) - score += best_letter_score; - - /* did not match full pattern */ - if (*pattern_iter != '\0') - return nk_false; - - if (out_score) - *out_score = score; - return nk_true; -} -NK_API int -nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score) -{ - return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score); -} -NK_LIB int -nk_string_float_limit(char *string, int prec) -{ - int dot = 0; - char *c = string; - while (*c) { - if (*c == '.') { - dot = 1; - c++; - continue; - } - if (dot == (prec+1)) { - *c = 0; - break; - } - if (dot > 0) dot++; - c++; - } - return (int)(c - string); -} -NK_INTERN void -nk_strrev_ascii(char *s) -{ - int len = nk_strlen(s); - int end = len / 2; - int i = 0; - char t; - for (; i < end; ++i) { - t = s[i]; - s[i] = s[len - 1 - i]; - s[len -1 - i] = t; - } -} -NK_LIB char* -nk_itoa(char *s, long n) -{ - long i = 0; - if (n == 0) { - s[i++] = '0'; - s[i] = 0; - return s; - } - if (n < 0) { - s[i++] = '-'; - n = -n; - } - while (n > 0) { - s[i++] = (char)('0' + (n % 10)); - n /= 10; - } - s[i] = 0; - if (s[0] == '-') - ++s; - - nk_strrev_ascii(s); - return s; -} -#ifndef NK_DTOA -#define NK_DTOA nk_dtoa -NK_LIB char* -nk_dtoa(char *s, double n) -{ - int useExp = 0; - int digit = 0, m = 0, m1 = 0; - char *c = s; - int neg = 0; - - NK_ASSERT(s); - if (!s) return 0; - - if (n == 0.0) { - s[0] = '0'; s[1] = '\0'; - return s; - } - - neg = (n < 0); - if (neg) n = -n; - - /* calculate magnitude */ - m = nk_log10(n); - useExp = (m >= 14 || (neg && m >= 9) || m <= -9); - if (neg) *(c++) = '-'; - - /* set up for scientific notation */ - if (useExp) { - if (m < 0) - m -= 1; - n = n / (double)nk_pow(10.0, m); - m1 = m; - m = 0; - } - if (m < 1.0) { - m = 0; - } - - /* convert the number */ - while (n > NK_FLOAT_PRECISION || m >= 0) { - double weight = nk_pow(10.0, m); - if (weight > 0) { - double t = (double)n / weight; - digit = nk_ifloord(t); - n -= ((double)digit * weight); - *(c++) = (char)('0' + (char)digit); - } - if (m == 0 && n > 0) - *(c++) = '.'; - m--; - } - - if (useExp) { - /* convert the exponent */ - int i, j; - *(c++) = 'e'; - if (m1 > 0) { - *(c++) = '+'; - } else { - *(c++) = '-'; - m1 = -m1; - } - m = 0; - while (m1 > 0) { - *(c++) = (char)('0' + (char)(m1 % 10)); - m1 /= 10; - m++; - } - c -= m; - for (i = 0, j = m-1; i= buf_size) break; - iter++; - - /* flag arguments */ - while (*iter) { - if (*iter == '-') flag |= NK_ARG_FLAG_LEFT; - else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS; - else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE; - else if (*iter == '#') flag |= NK_ARG_FLAG_NUM; - else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO; - else break; - iter++; - } - - /* width argument */ - width = NK_DEFAULT; - if (*iter >= '1' && *iter <= '9') { - const char *end; - width = nk_strtoi(iter, &end); - if (end == iter) - width = -1; - else iter = end; - } else if (*iter == '*') { - width = va_arg(args, int); - iter++; - } - - /* precision argument */ - precision = NK_DEFAULT; - if (*iter == '.') { - iter++; - if (*iter == '*') { - precision = va_arg(args, int); - iter++; - } else { - const char *end; - precision = nk_strtoi(iter, &end); - if (end == iter) - precision = -1; - else iter = end; - } - } - - /* length modifier */ - if (*iter == 'h') { - if (*(iter+1) == 'h') { - arg_type = NK_ARG_TYPE_CHAR; - iter++; - } else arg_type = NK_ARG_TYPE_SHORT; - iter++; - } else if (*iter == 'l') { - arg_type = NK_ARG_TYPE_LONG; - iter++; - } else arg_type = NK_ARG_TYPE_DEFAULT; - - /* specifier */ - if (*iter == '%') { - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (len < buf_size) - buf[len++] = '%'; - } else if (*iter == 's') { - /* string */ - const char *str = va_arg(args, const char*); - NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!"); - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (str == buf) return -1; - while (str && *str && len < buf_size) - buf[len++] = *str++; - } else if (*iter == 'n') { - /* current length callback */ - signed int *n = va_arg(args, int*); - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (n) *n = len; - } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') { - /* signed integer */ - long value = 0; - const char *num_iter; - int num_len, num_print, padding; - int cur_precision = NK_MAX(precision, 1); - int cur_width = NK_MAX(width, 0); - - /* retrieve correct value type */ - if (arg_type == NK_ARG_TYPE_CHAR) - value = (signed char)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_SHORT) - value = (signed short)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_LONG) - value = va_arg(args, signed long); - else if (*iter == 'c') - value = (unsigned char)va_arg(args, int); - else value = va_arg(args, signed int); - - /* convert number to string */ - nk_itoa(number_buffer, value); - num_len = nk_strlen(number_buffer); - padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); - if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while (padding-- > 0 && (len < buf_size)) { - if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* copy string value representation into buffer */ - if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size) - buf[len++] = '+'; - else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size) - buf[len++] = ' '; - - /* fill up to precision number of digits with '0' */ - num_print = NK_MAX(cur_precision, num_len); - while (precision && (num_print > num_len) && (len < buf_size)) { - buf[len++] = '0'; - num_print--; - } - - /* copy string value representation into buffer */ - num_iter = number_buffer; - while (precision && *num_iter && len < buf_size) - buf[len++] = *num_iter++; - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') { - /* unsigned integer */ - unsigned long value = 0; - int num_len = 0, num_print, padding = 0; - int cur_precision = NK_MAX(precision, 1); - int cur_width = NK_MAX(width, 0); - unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16; - - /* print oct/hex/dec value */ - const char *upper_output_format = "0123456789ABCDEF"; - const char *lower_output_format = "0123456789abcdef"; - const char *output_format = (*iter == 'x') ? - lower_output_format: upper_output_format; - - /* retrieve correct value type */ - if (arg_type == NK_ARG_TYPE_CHAR) - value = (unsigned char)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_SHORT) - value = (unsigned short)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_LONG) - value = va_arg(args, unsigned long); - else value = va_arg(args, unsigned int); - - do { - /* convert decimal number into hex/oct number */ - int digit = output_format[value % base]; - if (num_len < NK_MAX_NUMBER_BUFFER) - number_buffer[num_len++] = (char)digit; - value /= base; - } while (value > 0); - - num_print = NK_MAX(cur_precision, num_len); - padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); - if (flag & NK_ARG_FLAG_NUM) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while ((padding-- > 0) && (len < buf_size)) { - if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* fill up to precision number of digits */ - if (num_print && (flag & NK_ARG_FLAG_NUM)) { - if ((*iter == 'o') && (len < buf_size)) { - buf[len++] = '0'; - } else if ((*iter == 'x') && ((len+1) < buf_size)) { - buf[len++] = '0'; - buf[len++] = 'x'; - } else if ((*iter == 'X') && ((len+1) < buf_size)) { - buf[len++] = '0'; - buf[len++] = 'X'; - } - } - while (precision && (num_print > num_len) && (len < buf_size)) { - buf[len++] = '0'; - num_print--; - } - - /* reverse number direction */ - while (num_len > 0) { - if (precision && (len < buf_size)) - buf[len++] = number_buffer[num_len-1]; - num_len--; - } - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else if (*iter == 'f') { - /* floating point */ - const char *num_iter; - int cur_precision = (precision < 0) ? 6: precision; - int prefix, cur_width = NK_MAX(width, 0); - double value = va_arg(args, double); - int num_len = 0, frac_len = 0, dot = 0; - int padding = 0; - - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_DTOA(number_buffer, value); - num_len = nk_strlen(number_buffer); - - /* calculate padding */ - num_iter = number_buffer; - while (*num_iter && *num_iter != '.') - num_iter++; - - prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0; - padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0); - if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while (padding-- > 0 && (len < buf_size)) { - if (flag & NK_ARG_FLAG_ZERO) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* copy string value representation into buffer */ - num_iter = number_buffer; - if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size)) - buf[len++] = '+'; - else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size)) - buf[len++] = ' '; - while (*num_iter) { - if (dot) frac_len++; - if (len < buf_size) - buf[len++] = *num_iter; - if (*num_iter == '.') dot = 1; - if (frac_len >= cur_precision) break; - num_iter++; - } - - /* fill number up to precision */ - while (frac_len < cur_precision) { - if (!dot && len < buf_size) { - buf[len++] = '.'; - dot = 1; - } - if (len < buf_size) - buf[len++] = '0'; - frac_len++; - } - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else { - /* Specifier not supported: g,G,e,E,p,z */ - NK_ASSERT(0 && "specifier is not supported!"); - return result; - } - } - buf[(len >= buf_size)?(buf_size-1):len] = 0; - result = (len >= buf_size)?-1:len; - return result; -} -#endif -NK_LIB int -nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args) -{ - int result = -1; - NK_ASSERT(buf); - NK_ASSERT(buf_size); - if (!buf || !buf_size || !fmt) return 0; -#ifdef NK_INCLUDE_STANDARD_IO - result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args); - result = (result >= buf_size) ? -1: result; - buf[buf_size-1] = 0; -#else - result = nk_vsnprintf(buf, buf_size, fmt, args); -#endif - return result; -} -#endif -NK_API nk_hash -nk_murmur_hash(const void * key, int len, nk_hash seed) -{ - /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/ - #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r))) - - nk_uint h1 = seed; - nk_uint k1; - const nk_byte *data = (const nk_byte*)key; - const nk_byte *keyptr = data; - nk_byte *k1ptr; - const int bsize = sizeof(k1); - const int nblocks = len/4; - - const nk_uint c1 = 0xcc9e2d51; - const nk_uint c2 = 0x1b873593; - const nk_byte *tail; - int i; - - /* body */ - if (!key) return 0; - for (i = 0; i < nblocks; ++i, keyptr += bsize) { - k1ptr = (nk_byte*)&k1; - k1ptr[0] = keyptr[0]; - k1ptr[1] = keyptr[1]; - k1ptr[2] = keyptr[2]; - k1ptr[3] = keyptr[3]; - - k1 *= c1; - k1 = NK_ROTL(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = NK_ROTL(h1,13); - h1 = h1*5+0xe6546b64; - } - - /* tail */ - tail = (const nk_byte*)(data + nblocks*4); - k1 = 0; - switch (len & 3) { - case 3: k1 ^= (nk_uint)(tail[2] << 16); /* fallthrough */ - case 2: k1 ^= (nk_uint)(tail[1] << 8u); /* fallthrough */ - case 1: k1 ^= tail[0]; - k1 *= c1; - k1 = NK_ROTL(k1,15); - k1 *= c2; - h1 ^= k1; - break; - default: break; - } - - /* finalization */ - h1 ^= (nk_uint)len; - /* fmix32 */ - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - #undef NK_ROTL - return h1; -} -#ifdef NK_INCLUDE_STANDARD_IO -NK_LIB char* -nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc) -{ - char *buf; - FILE *fd; - long ret; - - NK_ASSERT(path); - NK_ASSERT(siz); - NK_ASSERT(alloc); - if (!path || !siz || !alloc) - return 0; - - fd = fopen(path, "rb"); - if (!fd) return 0; - fseek(fd, 0, SEEK_END); - ret = ftell(fd); - if (ret < 0) { - fclose(fd); - return 0; - } - *siz = (nk_size)ret; - fseek(fd, 0, SEEK_SET); - buf = (char*)alloc->alloc(alloc->userdata,0, *siz); - NK_ASSERT(buf); - if (!buf) { - fclose(fd); - return 0; - } - *siz = (nk_size)fread(buf, 1,*siz, fd); - fclose(fd); - return buf; -} -#endif -NK_LIB int -nk_text_clamp(const struct nk_user_font *font, const char *text, - int text_len, float space, int *glyphs, float *text_width, - nk_rune *sep_list, int sep_count) -{ - int i = 0; - int glyph_len = 0; - float last_width = 0; - nk_rune unicode = 0; - float width = 0; - int len = 0; - int g = 0; - float s; - - int sep_len = 0; - int sep_g = 0; - float sep_width = 0; - sep_count = NK_MAX(sep_count,0); - - glyph_len = nk_utf_decode(text, &unicode, text_len); - while (glyph_len && (width < space) && (len < text_len)) { - len += glyph_len; - s = font->width(font->userdata, font->height, text, len); - for (i = 0; i < sep_count; ++i) { - if (unicode != sep_list[i]) continue; - sep_width = last_width = width; - sep_g = g+1; - sep_len = len; - break; - } - if (i == sep_count){ - last_width = sep_width = width; - sep_g = g+1; - } - width = s; - glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len); - g++; - } - if (len >= text_len) { - *glyphs = g; - *text_width = last_width; - return len; - } else { - *glyphs = sep_g; - *text_width = sep_width; - return (!sep_len) ? len: sep_len; - } -} -NK_LIB struct nk_vec2 -nk_text_calculate_text_bounds(const struct nk_user_font *font, - const char *begin, int byte_len, float row_height, const char **remaining, - struct nk_vec2 *out_offset, int *glyphs, int op) -{ - float line_height = row_height; - struct nk_vec2 text_size = nk_vec2(0,0); - float line_width = 0.0f; - - float glyph_width; - int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - if (!begin || byte_len <= 0 || !font) - return nk_vec2(0,row_height); - - glyph_len = nk_utf_decode(begin, &unicode, byte_len); - if (!glyph_len) return text_size; - glyph_width = font->width(font->userdata, font->height, begin, glyph_len); - - *glyphs = 0; - while ((text_len < byte_len) && glyph_len) { - if (unicode == '\n') { - text_size.x = NK_MAX(text_size.x, line_width); - text_size.y += line_height; - line_width = 0; - *glyphs+=1; - if (op == NK_STOP_ON_NEW_LINE) - break; - - text_len++; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - continue; - } - - if (unicode == '\r') { - text_len++; - *glyphs+=1; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - continue; - } - - *glyphs = *glyphs + 1; - text_len += glyph_len; - line_width += (float)glyph_width; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len); - continue; - } - - if (text_size.x < line_width) - text_size.x = line_width; - if (out_offset) - *out_offset = nk_vec2(line_width, text_size.y + line_height); - if (line_width > 0 || text_size.y == 0.0f) - text_size.y += line_height; - if (remaining) - *remaining = begin+text_len; - return text_size; -} - - - - - -/* ============================================================== - * - * COLOR - * - * ===============================================================*/ -NK_INTERN int -nk_parse_hex(const char *p, int length) -{ - int i = 0; - int len = 0; - while (len < length) { - i <<= 4; - if (p[len] >= 'a' && p[len] <= 'f') - i += ((p[len] - 'a') + 10); - else if (p[len] >= 'A' && p[len] <= 'F') - i += ((p[len] - 'A') + 10); - else i += (p[len] - '0'); - len++; - } - return i; -} -NK_API struct nk_color -nk_rgba(int r, int g, int b, int a) -{ - struct nk_color ret; - ret.r = (nk_byte)NK_CLAMP(0, r, 255); - ret.g = (nk_byte)NK_CLAMP(0, g, 255); - ret.b = (nk_byte)NK_CLAMP(0, b, 255); - ret.a = (nk_byte)NK_CLAMP(0, a, 255); - return ret; -} -NK_API struct nk_color -nk_rgb_hex(const char *rgb) -{ - struct nk_color col; - const char *c = rgb; - if (*c == '#') c++; - col.r = (nk_byte)nk_parse_hex(c, 2); - col.g = (nk_byte)nk_parse_hex(c+2, 2); - col.b = (nk_byte)nk_parse_hex(c+4, 2); - col.a = 255; - return col; -} -NK_API struct nk_color -nk_rgba_hex(const char *rgb) -{ - struct nk_color col; - const char *c = rgb; - if (*c == '#') c++; - col.r = (nk_byte)nk_parse_hex(c, 2); - col.g = (nk_byte)nk_parse_hex(c+2, 2); - col.b = (nk_byte)nk_parse_hex(c+4, 2); - col.a = (nk_byte)nk_parse_hex(c+6, 2); - return col; -} -NK_API void -nk_color_hex_rgba(char *output, struct nk_color col) -{ - #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) - output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); - output[1] = (char)NK_TO_HEX((col.r & 0x0F)); - output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); - output[3] = (char)NK_TO_HEX((col.g & 0x0F)); - output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); - output[5] = (char)NK_TO_HEX((col.b & 0x0F)); - output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4); - output[7] = (char)NK_TO_HEX((col.a & 0x0F)); - output[8] = '\0'; - #undef NK_TO_HEX -} -NK_API void -nk_color_hex_rgb(char *output, struct nk_color col) -{ - #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) - output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); - output[1] = (char)NK_TO_HEX((col.r & 0x0F)); - output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); - output[3] = (char)NK_TO_HEX((col.g & 0x0F)); - output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); - output[5] = (char)NK_TO_HEX((col.b & 0x0F)); - output[6] = '\0'; - #undef NK_TO_HEX -} -NK_API struct nk_color -nk_rgba_iv(const int *c) -{ - return nk_rgba(c[0], c[1], c[2], c[3]); -} -NK_API struct nk_color -nk_rgba_bv(const nk_byte *c) -{ - return nk_rgba(c[0], c[1], c[2], c[3]); -} -NK_API struct nk_color -nk_rgb(int r, int g, int b) -{ - struct nk_color ret; - ret.r = (nk_byte)NK_CLAMP(0, r, 255); - ret.g = (nk_byte)NK_CLAMP(0, g, 255); - ret.b = (nk_byte)NK_CLAMP(0, b, 255); - ret.a = (nk_byte)255; - return ret; -} -NK_API struct nk_color -nk_rgb_iv(const int *c) -{ - return nk_rgb(c[0], c[1], c[2]); -} -NK_API struct nk_color -nk_rgb_bv(const nk_byte* c) -{ - return nk_rgb(c[0], c[1], c[2]); -} -NK_API struct nk_color -nk_rgba_u32(nk_uint in) -{ - struct nk_color ret; - ret.r = (in & 0xFF); - ret.g = ((in >> 8) & 0xFF); - ret.b = ((in >> 16) & 0xFF); - ret.a = (nk_byte)((in >> 24) & 0xFF); - return ret; -} -NK_API struct nk_color -nk_rgba_f(float r, float g, float b, float a) -{ - struct nk_color ret; - ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); - ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); - ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); - ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f); - return ret; -} -NK_API struct nk_color -nk_rgba_fv(const float *c) -{ - return nk_rgba_f(c[0], c[1], c[2], c[3]); -} -NK_API struct nk_color -nk_rgba_cf(struct nk_colorf c) -{ - return nk_rgba_f(c.r, c.g, c.b, c.a); -} -NK_API struct nk_color -nk_rgb_f(float r, float g, float b) -{ - struct nk_color ret; - ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); - ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); - ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); - ret.a = 255; - return ret; -} -NK_API struct nk_color -nk_rgb_fv(const float *c) -{ - return nk_rgb_f(c[0], c[1], c[2]); -} -NK_API struct nk_color -nk_rgb_cf(struct nk_colorf c) -{ - return nk_rgb_f(c.r, c.g, c.b); -} -NK_API struct nk_color -nk_hsv(int h, int s, int v) -{ - return nk_hsva(h, s, v, 255); -} -NK_API struct nk_color -nk_hsv_iv(const int *c) -{ - return nk_hsv(c[0], c[1], c[2]); -} -NK_API struct nk_color -nk_hsv_bv(const nk_byte *c) -{ - return nk_hsv(c[0], c[1], c[2]); -} -NK_API struct nk_color -nk_hsv_f(float h, float s, float v) -{ - return nk_hsva_f(h, s, v, 1.0f); -} -NK_API struct nk_color -nk_hsv_fv(const float *c) -{ - return nk_hsv_f(c[0], c[1], c[2]); -} -NK_API struct nk_color -nk_hsva(int h, int s, int v, int a) -{ - float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f; - float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f; - float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f; - float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f; - return nk_hsva_f(hf, sf, vf, af); -} -NK_API struct nk_color -nk_hsva_iv(const int *c) -{ - return nk_hsva(c[0], c[1], c[2], c[3]); -} -NK_API struct nk_color -nk_hsva_bv(const nk_byte *c) -{ - return nk_hsva(c[0], c[1], c[2], c[3]); -} -NK_API struct nk_colorf -nk_hsva_colorf(float h, float s, float v, float a) -{ - int i; - float p, q, t, f; - struct nk_colorf out = {0,0,0,0}; - if (s <= 0.0f) { - out.r = v; out.g = v; out.b = v; out.a = a; - return out; - } - h = h / (60.0f/360.0f); - i = (int)h; - f = h - (float)i; - p = v * (1.0f - s); - q = v * (1.0f - (s * f)); - t = v * (1.0f - s * (1.0f - f)); - - switch (i) { - case 0: default: out.r = v; out.g = t; out.b = p; break; - case 1: out.r = q; out.g = v; out.b = p; break; - case 2: out.r = p; out.g = v; out.b = t; break; - case 3: out.r = p; out.g = q; out.b = v; break; - case 4: out.r = t; out.g = p; out.b = v; break; - case 5: out.r = v; out.g = p; out.b = q; break;} - out.a = a; - return out; -} -NK_API struct nk_colorf -nk_hsva_colorfv(float *c) -{ - return nk_hsva_colorf(c[0], c[1], c[2], c[3]); -} -NK_API struct nk_color -nk_hsva_f(float h, float s, float v, float a) -{ - struct nk_colorf c = nk_hsva_colorf(h, s, v, a); - return nk_rgba_f(c.r, c.g, c.b, c.a); -} -NK_API struct nk_color -nk_hsva_fv(const float *c) -{ - return nk_hsva_f(c[0], c[1], c[2], c[3]); -} -NK_API nk_uint -nk_color_u32(struct nk_color in) -{ - nk_uint out = (nk_uint)in.r; - out |= ((nk_uint)in.g << 8); - out |= ((nk_uint)in.b << 16); - out |= ((nk_uint)in.a << 24); - return out; -} -NK_API void -nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in) -{ - NK_STORAGE const float s = 1.0f/255.0f; - *r = (float)in.r * s; - *g = (float)in.g * s; - *b = (float)in.b * s; - *a = (float)in.a * s; -} -NK_API void -nk_color_fv(float *c, struct nk_color in) -{ - nk_color_f(&c[0], &c[1], &c[2], &c[3], in); -} -NK_API struct nk_colorf -nk_color_cf(struct nk_color in) -{ - struct nk_colorf o; - nk_color_f(&o.r, &o.g, &o.b, &o.a, in); - return o; -} -NK_API void -nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in) -{ - NK_STORAGE const double s = 1.0/255.0; - *r = (double)in.r * s; - *g = (double)in.g * s; - *b = (double)in.b * s; - *a = (double)in.a * s; -} -NK_API void -nk_color_dv(double *c, struct nk_color in) -{ - nk_color_d(&c[0], &c[1], &c[2], &c[3], in); -} -NK_API void -nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in) -{ - float a; - nk_color_hsva_f(out_h, out_s, out_v, &a, in); -} -NK_API void -nk_color_hsv_fv(float *out, struct nk_color in) -{ - float a; - nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in); -} -NK_API void -nk_colorf_hsva_f(float *out_h, float *out_s, - float *out_v, float *out_a, struct nk_colorf in) -{ - float chroma; - float K = 0.0f; - if (in.g < in.b) { - const float t = in.g; in.g = in.b; in.b = t; - K = -1.f; - } - if (in.r < in.g) { - const float t = in.r; in.r = in.g; in.g = t; - K = -2.f/6.0f - K; - } - chroma = in.r - ((in.g < in.b) ? in.g: in.b); - *out_h = NK_ABS(K + (in.g - in.b)/(6.0f * chroma + 1e-20f)); - *out_s = chroma / (in.r + 1e-20f); - *out_v = in.r; - *out_a = in.a; - -} -NK_API void -nk_colorf_hsva_fv(float *hsva, struct nk_colorf in) -{ - nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in); -} -NK_API void -nk_color_hsva_f(float *out_h, float *out_s, - float *out_v, float *out_a, struct nk_color in) -{ - struct nk_colorf col; - nk_color_f(&col.r,&col.g,&col.b,&col.a, in); - nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col); -} -NK_API void -nk_color_hsva_fv(float *out, struct nk_color in) -{ - nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in); -} -NK_API void -nk_color_hsva_i(int *out_h, int *out_s, int *out_v, - int *out_a, struct nk_color in) -{ - float h,s,v,a; - nk_color_hsva_f(&h, &s, &v, &a, in); - *out_h = (nk_byte)(h * 255.0f); - *out_s = (nk_byte)(s * 255.0f); - *out_v = (nk_byte)(v * 255.0f); - *out_a = (nk_byte)(a * 255.0f); -} -NK_API void -nk_color_hsva_iv(int *out, struct nk_color in) -{ - nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in); -} -NK_API void -nk_color_hsva_bv(nk_byte *out, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - out[0] = (nk_byte)tmp[0]; - out[1] = (nk_byte)tmp[1]; - out[2] = (nk_byte)tmp[2]; - out[3] = (nk_byte)tmp[3]; -} -NK_API void -nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - *h = (nk_byte)tmp[0]; - *s = (nk_byte)tmp[1]; - *v = (nk_byte)tmp[2]; - *a = (nk_byte)tmp[3]; -} -NK_API void -nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in) -{ - int a; - nk_color_hsva_i(out_h, out_s, out_v, &a, in); -} -NK_API void -nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - *out_h = (nk_byte)tmp[0]; - *out_s = (nk_byte)tmp[1]; - *out_v = (nk_byte)tmp[2]; -} -NK_API void -nk_color_hsv_iv(int *out, struct nk_color in) -{ - nk_color_hsv_i(&out[0], &out[1], &out[2], in); -} -NK_API void -nk_color_hsv_bv(nk_byte *out, struct nk_color in) -{ - int tmp[4]; - nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in); - out[0] = (nk_byte)tmp[0]; - out[1] = (nk_byte)tmp[1]; - out[2] = (nk_byte)tmp[2]; -} - - - - - -/* =============================================================== - * - * UTF-8 - * - * ===============================================================*/ -NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; -NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000}; -NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; - -NK_INTERN int -nk_utf_validate(nk_rune *u, int i) -{ - NK_ASSERT(u); - if (!u) return 0; - if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) || - NK_BETWEEN(*u, 0xD800, 0xDFFF)) - *u = NK_UTF_INVALID; - for (i = 1; *u > nk_utfmax[i]; ++i); - return i; -} -NK_INTERN nk_rune -nk_utf_decode_byte(char c, int *i) -{ - NK_ASSERT(i); - if (!i) return 0; - for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) { - if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i]) - return (nk_byte)(c & ~nk_utfmask[*i]); - } - return 0; -} -NK_API int -nk_utf_decode(const char *c, nk_rune *u, int clen) -{ - int i, j, len, type=0; - nk_rune udecoded; - - NK_ASSERT(c); - NK_ASSERT(u); - - if (!c || !u) return 0; - if (!clen) return 0; - *u = NK_UTF_INVALID; - - udecoded = nk_utf_decode_byte(c[0], &len); - if (!NK_BETWEEN(len, 1, NK_UTF_SIZE)) - return 1; - - for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { - udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type); - if (type != 0) - return j; - } - if (j < len) - return 0; - *u = udecoded; - nk_utf_validate(u, len); - return len; -} -NK_INTERN char -nk_utf_encode_byte(nk_rune u, int i) -{ - return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i])); -} -NK_API int -nk_utf_encode(nk_rune u, char *c, int clen) -{ - int len, i; - len = nk_utf_validate(&u, 0); - if (clen < len || !len || len > NK_UTF_SIZE) - return 0; - - for (i = len - 1; i != 0; --i) { - c[i] = nk_utf_encode_byte(u, 0); - u >>= 6; - } - c[0] = nk_utf_encode_byte(u, len); - return len; -} -NK_API int -nk_utf_len(const char *str, int len) -{ - const char *text; - int glyphs = 0; - int text_len; - int glyph_len; - int src_len = 0; - nk_rune unicode; - - NK_ASSERT(str); - if (!str || !len) return 0; - - text = str; - text_len = len; - glyph_len = nk_utf_decode(text, &unicode, text_len); - while (glyph_len && src_len < len) { - glyphs++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len); - } - return glyphs; -} -NK_API const char* -nk_utf_at(const char *buffer, int length, int index, - nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - const char *text; - int text_len; - - NK_ASSERT(buffer); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!buffer || !unicode || !len) return 0; - if (index < 0) { - *unicode = NK_UTF_INVALID; - *len = 0; - return 0; - } - - text = buffer; - text_len = length; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == index) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != index) return 0; - return buffer + src_len; -} - - - - - -/* ============================================================== - * - * BUFFER - * - * ===============================================================*/ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_LIB void* -nk_malloc(nk_handle unused, void *old,nk_size size) -{ - NK_UNUSED(unused); - NK_UNUSED(old); - return malloc(size); -} -NK_LIB void -nk_mfree(nk_handle unused, void *ptr) -{ - NK_UNUSED(unused); - free(ptr); -} -NK_API void -nk_buffer_init_default(struct nk_buffer *buffer) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE); -} -#endif - -NK_API void -nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a, - nk_size initial_size) -{ - NK_ASSERT(b); - NK_ASSERT(a); - NK_ASSERT(initial_size); - if (!b || !a || !initial_size) return; - - nk_zero(b, sizeof(*b)); - b->type = NK_BUFFER_DYNAMIC; - b->memory.ptr = a->alloc(a->userdata,0, initial_size); - b->memory.size = initial_size; - b->size = initial_size; - b->grow_factor = 2.0f; - b->pool = *a; -} -NK_API void -nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size) -{ - NK_ASSERT(b); - NK_ASSERT(m); - NK_ASSERT(size); - if (!b || !m || !size) return; - - nk_zero(b, sizeof(*b)); - b->type = NK_BUFFER_FIXED; - b->memory.ptr = m; - b->memory.size = size; - b->size = size; -} -NK_LIB void* -nk_buffer_align(void *unaligned, - nk_size align, nk_size *alignment, - enum nk_buffer_allocation_type type) -{ - void *memory = 0; - switch (type) { - default: - case NK_BUFFER_MAX: - case NK_BUFFER_FRONT: - if (align) { - memory = NK_ALIGN_PTR(unaligned, align); - *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); - } else { - memory = unaligned; - *alignment = 0; - } - break; - case NK_BUFFER_BACK: - if (align) { - memory = NK_ALIGN_PTR_BACK(unaligned, align); - *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory); - } else { - memory = unaligned; - *alignment = 0; - } - break; - } - return memory; -} -NK_LIB void* -nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size) -{ - void *temp; - nk_size buffer_size; - - NK_ASSERT(b); - NK_ASSERT(size); - if (!b || !size || !b->pool.alloc || !b->pool.free) - return 0; - - buffer_size = b->memory.size; - temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity); - NK_ASSERT(temp); - if (!temp) return 0; - - *size = capacity; - if (temp != b->memory.ptr) { - NK_MEMCPY(temp, b->memory.ptr, buffer_size); - b->pool.free(b->pool.userdata, b->memory.ptr); - } - - if (b->size == buffer_size) { - /* no back buffer so just set correct size */ - b->size = capacity; - return temp; - } else { - /* copy back buffer to the end of the new buffer */ - void *dst, *src; - nk_size back_size; - back_size = buffer_size - b->size; - dst = nk_ptr_add(void, temp, capacity - back_size); - src = nk_ptr_add(void, temp, b->size); - NK_MEMCPY(dst, src, back_size); - b->size = capacity - back_size; - } - return temp; -} -NK_LIB void* -nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, - nk_size size, nk_size align) -{ - int full; - nk_size alignment; - void *unaligned; - void *memory; - - NK_ASSERT(b); - NK_ASSERT(size); - if (!b || !size) return 0; - b->needed += size; - - /* calculate total size with needed alignment + size */ - if (type == NK_BUFFER_FRONT) - unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); - else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); - memory = nk_buffer_align(unaligned, align, &alignment, type); - - /* check if buffer has enough memory*/ - if (type == NK_BUFFER_FRONT) - full = ((b->allocated + size + alignment) > b->size); - else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated); - - if (full) { - nk_size capacity; - if (b->type != NK_BUFFER_DYNAMIC) - return 0; - NK_ASSERT(b->pool.alloc && b->pool.free); - if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free) - return 0; - - /* buffer is full so allocate bigger buffer if dynamic */ - capacity = (nk_size)((float)b->memory.size * b->grow_factor); - capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size))); - b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size); - if (!b->memory.ptr) return 0; - - /* align newly allocated pointer */ - if (type == NK_BUFFER_FRONT) - unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); - else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); - memory = nk_buffer_align(unaligned, align, &alignment, type); - } - if (type == NK_BUFFER_FRONT) - b->allocated += size + alignment; - else b->size -= (size + alignment); - b->needed += alignment; - b->calls++; - return memory; -} -NK_API void -nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type, - const void *memory, nk_size size, nk_size align) -{ - void *mem = nk_buffer_alloc(b, type, size, align); - if (!mem) return; - NK_MEMCPY(mem, memory, size); -} -NK_API void -nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) -{ - NK_ASSERT(buffer); - if (!buffer) return; - buffer->marker[type].active = nk_true; - if (type == NK_BUFFER_BACK) - buffer->marker[type].offset = buffer->size; - else buffer->marker[type].offset = buffer->allocated; -} -NK_API void -nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) -{ - NK_ASSERT(buffer); - if (!buffer) return; - if (type == NK_BUFFER_BACK) { - /* reset back buffer either back to marker or empty */ - buffer->needed -= (buffer->memory.size - buffer->marker[type].offset); - if (buffer->marker[type].active) - buffer->size = buffer->marker[type].offset; - else buffer->size = buffer->memory.size; - buffer->marker[type].active = nk_false; - } else { - /* reset front buffer either back to back marker or empty */ - buffer->needed -= (buffer->allocated - buffer->marker[type].offset); - if (buffer->marker[type].active) - buffer->allocated = buffer->marker[type].offset; - else buffer->allocated = 0; - buffer->marker[type].active = nk_false; - } -} -NK_API void -nk_buffer_clear(struct nk_buffer *b) -{ - NK_ASSERT(b); - if (!b) return; - b->allocated = 0; - b->size = b->memory.size; - b->calls = 0; - b->needed = 0; -} -NK_API void -nk_buffer_free(struct nk_buffer *b) -{ - NK_ASSERT(b); - if (!b || !b->memory.ptr) return; - if (b->type == NK_BUFFER_FIXED) return; - if (!b->pool.free) return; - NK_ASSERT(b->pool.free); - b->pool.free(b->pool.userdata, b->memory.ptr); -} -NK_API void -nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b) -{ - NK_ASSERT(b); - NK_ASSERT(s); - if (!s || !b) return; - s->allocated = b->allocated; - s->size = b->memory.size; - s->needed = b->needed; - s->memory = b->memory.ptr; - s->calls = b->calls; -} -NK_API void* -nk_buffer_memory(struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.ptr; -} -NK_API const void* -nk_buffer_memory_const(const struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.ptr; -} -NK_API nk_size -nk_buffer_total(struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.size; -} - - - - - -/* =============================================================== - * - * STRING - * - * ===============================================================*/ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_str_init_default(struct nk_str *str) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - nk_buffer_init(&str->buffer, &alloc, 32); - str->len = 0; -} -#endif - -NK_API void -nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size) -{ - nk_buffer_init(&str->buffer, alloc, size); - str->len = 0; -} -NK_API void -nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size) -{ - nk_buffer_init_fixed(&str->buffer, memory, size); - str->len = 0; -} -NK_API int -nk_str_append_text_char(struct nk_str *s, const char *str, int len) -{ - char *mem; - NK_ASSERT(s); - NK_ASSERT(str); - if (!s || !str || !len) return 0; - mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); - if (!mem) return 0; - NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); - s->len += nk_utf_len(str, len); - return len; -} -NK_API int -nk_str_append_str_char(struct nk_str *s, const char *str) -{ - return nk_str_append_text_char(s, str, nk_strlen(str)); -} -NK_API int -nk_str_append_text_utf8(struct nk_str *str, const char *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_rune unicode; - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) - byte_len += nk_utf_decode(text+byte_len, &unicode, 4); - nk_str_append_text_char(str, text, byte_len); - return len; -} -NK_API int -nk_str_append_str_utf8(struct nk_str *str, const char *text) -{ - int runes = 0; - int byte_len = 0; - int num_runes = 0; - int glyph_len = 0; - nk_rune unicode; - if (!str || !text) return 0; - - glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); - while (unicode != '\0' && glyph_len) { - glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); - byte_len += glyph_len; - num_runes++; - } - nk_str_append_text_char(str, text, byte_len); - return runes; -} -NK_API int -nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_glyph glyph; - - NK_ASSERT(str); - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) { - byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE); - if (!byte_len) break; - nk_str_append_text_char(str, glyph, byte_len); - } - return len; -} -NK_API int -nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes) -{ - int i = 0; - nk_glyph glyph; - int byte_len; - NK_ASSERT(str); - if (!str || !runes) return 0; - while (runes[i] != '\0') { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - nk_str_append_text_char(str, glyph, byte_len); - i++; - } - return i; -} -NK_API int -nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len) -{ - int i; - void *mem; - char *src; - char *dst; - - int copylen; - NK_ASSERT(s); - NK_ASSERT(str); - NK_ASSERT(len >= 0); - if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0; - if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) && - (s->buffer.type == NK_BUFFER_FIXED)) return 0; - - copylen = (int)s->buffer.allocated - pos; - if (!copylen) { - nk_str_append_text_char(s, str, len); - return 1; - } - mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); - if (!mem) return 0; - - /* memmove */ - NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0); - NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0); - dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1)); - src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1)); - for (i = 0; i < copylen; ++i) *dst-- = *src--; - mem = nk_ptr_add(void, s->buffer.memory.ptr, pos); - NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); - return 1; -} -NK_API int -nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len) -{ - int glyph_len; - nk_rune unicode; - const char *begin; - const char *buffer; - - NK_ASSERT(str); - NK_ASSERT(cstr); - NK_ASSERT(len); - if (!str || !cstr || !len) return 0; - begin = nk_str_at_rune(str, pos, &unicode, &glyph_len); - if (!str->len) - return nk_str_append_text_char(str, cstr, len); - buffer = nk_str_get_const(str); - if (!begin) return 0; - return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len); -} -NK_API int -nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len) -{ - return nk_str_insert_text_utf8(str, pos, text, len); -} -NK_API int -nk_str_insert_str_char(struct nk_str *str, int pos, const char *text) -{ - return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text)); -} -NK_API int -nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_rune unicode; - - NK_ASSERT(str); - NK_ASSERT(text); - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) - byte_len += nk_utf_decode(text+byte_len, &unicode, 4); - nk_str_insert_at_rune(str, pos, text, byte_len); - return len; -} -NK_API int -nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text) -{ - int runes = 0; - int byte_len = 0; - int num_runes = 0; - int glyph_len = 0; - nk_rune unicode; - if (!str || !text) return 0; - - glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); - while (unicode != '\0' && glyph_len) { - glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); - byte_len += glyph_len; - num_runes++; - } - nk_str_insert_at_rune(str, pos, text, byte_len); - return runes; -} -NK_API int -nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len) -{ - int i = 0; - int byte_len = 0; - nk_glyph glyph; - - NK_ASSERT(str); - if (!str || !runes || !len) return 0; - for (i = 0; i < len; ++i) { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - if (!byte_len) break; - nk_str_insert_at_rune(str, pos+i, glyph, byte_len); - } - return len; -} -NK_API int -nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes) -{ - int i = 0; - nk_glyph glyph; - int byte_len; - NK_ASSERT(str); - if (!str || !runes) return 0; - while (runes[i] != '\0') { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - nk_str_insert_at_rune(str, pos+i, glyph, byte_len); - i++; - } - return i; -} -NK_API void -nk_str_remove_chars(struct nk_str *s, int len) -{ - NK_ASSERT(s); - NK_ASSERT(len >= 0); - if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return; - NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); - s->buffer.allocated -= (nk_size)len; - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); -} -NK_API void -nk_str_remove_runes(struct nk_str *str, int len) -{ - int index; - const char *begin; - const char *end; - nk_rune unicode; - - NK_ASSERT(str); - NK_ASSERT(len >= 0); - if (!str || len < 0) return; - if (len >= str->len) { - str->len = 0; - return; - } - - index = str->len - len; - begin = nk_str_at_rune(str, index, &unicode, &len); - end = (const char*)str->buffer.memory.ptr + str->buffer.allocated; - nk_str_remove_chars(str, (int)(end-begin)+1); -} -NK_API void -nk_str_delete_chars(struct nk_str *s, int pos, int len) -{ - NK_ASSERT(s); - if (!s || !len || (nk_size)pos > s->buffer.allocated || - (nk_size)(pos + len) > s->buffer.allocated) return; - - if ((nk_size)(pos + len) < s->buffer.allocated) { - /* memmove */ - char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos); - char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len); - NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len)); - NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); - s->buffer.allocated -= (nk_size)len; - } else nk_str_remove_chars(s, len); - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); -} -NK_API void -nk_str_delete_runes(struct nk_str *s, int pos, int len) -{ - char *temp; - nk_rune unicode; - char *begin; - char *end; - int unused; - - NK_ASSERT(s); - NK_ASSERT(s->len >= pos + len); - if (s->len < pos + len) - len = NK_CLAMP(0, (s->len - pos), s->len); - if (!len) return; - - temp = (char *)s->buffer.memory.ptr; - begin = nk_str_at_rune(s, pos, &unicode, &unused); - if (!begin) return; - s->buffer.memory.ptr = begin; - end = nk_str_at_rune(s, len, &unicode, &unused); - s->buffer.memory.ptr = temp; - if (!end) return; - nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin)); -} -NK_API char* -nk_str_at_char(struct nk_str *s, int pos) -{ - NK_ASSERT(s); - if (!s || pos > (int)s->buffer.allocated) return 0; - return nk_ptr_add(char, s->buffer.memory.ptr, pos); -} -NK_API char* -nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - char *text; - int text_len; - - NK_ASSERT(str); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!str || !unicode || !len) return 0; - if (pos < 0) { - *unicode = 0; - *len = 0; - return 0; - } - - text = (char*)str->buffer.memory.ptr; - text_len = (int)str->buffer.allocated; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == pos) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != pos) return 0; - return text + src_len; -} -NK_API const char* -nk_str_at_char_const(const struct nk_str *s, int pos) -{ - NK_ASSERT(s); - if (!s || pos > (int)s->buffer.allocated) return 0; - return nk_ptr_add(char, s->buffer.memory.ptr, pos); -} -NK_API const char* -nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - char *text; - int text_len; - - NK_ASSERT(str); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!str || !unicode || !len) return 0; - if (pos < 0) { - *unicode = 0; - *len = 0; - return 0; - } - - text = (char*)str->buffer.memory.ptr; - text_len = (int)str->buffer.allocated; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == pos) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != pos) return 0; - return text + src_len; -} -NK_API nk_rune -nk_str_rune_at(const struct nk_str *str, int pos) -{ - int len; - nk_rune unicode = 0; - nk_str_at_const(str, pos, &unicode, &len); - return unicode; -} -NK_API char* -nk_str_get(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (char*)s->buffer.memory.ptr; -} -NK_API const char* -nk_str_get_const(const struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (const char*)s->buffer.memory.ptr; -} -NK_API int -nk_str_len(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return s->len; -} -NK_API int -nk_str_len_char(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (int)s->buffer.allocated; -} -NK_API void -nk_str_clear(struct nk_str *str) -{ - NK_ASSERT(str); - nk_buffer_clear(&str->buffer); - str->len = 0; -} -NK_API void -nk_str_free(struct nk_str *str) -{ - NK_ASSERT(str); - nk_buffer_free(&str->buffer); - str->len = 0; -} - - - - - -/* ============================================================== - * - * DRAW - * - * ===============================================================*/ -NK_LIB void -nk_command_buffer_init(struct nk_command_buffer *cb, - struct nk_buffer *b, enum nk_command_clipping clip) -{ - NK_ASSERT(cb); - NK_ASSERT(b); - if (!cb || !b) return; - cb->base = b; - cb->use_clipping = (int)clip; - cb->begin = b->allocated; - cb->end = b->allocated; - cb->last = b->allocated; -} -NK_LIB void -nk_command_buffer_reset(struct nk_command_buffer *b) -{ - NK_ASSERT(b); - if (!b) return; - b->begin = 0; - b->end = 0; - b->last = 0; - b->clip = nk_null_rect; -#ifdef NK_INCLUDE_COMMAND_USERDATA - b->userdata.ptr = 0; -#endif -} -NK_LIB void* -nk_command_buffer_push(struct nk_command_buffer* b, - enum nk_command_type t, nk_size size) -{ - NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command); - struct nk_command *cmd; - nk_size alignment; - void *unaligned; - void *memory; - - NK_ASSERT(b); - NK_ASSERT(b->base); - if (!b) return 0; - cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align); - if (!cmd) return 0; - - /* make sure the offset to the next command is aligned */ - b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr); - unaligned = (nk_byte*)cmd + size; - memory = NK_ALIGN_PTR(unaligned, align); - alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); -#ifdef NK_ZERO_COMMAND_MEMORY - NK_MEMSET(cmd, 0, size + alignment); -#endif - - cmd->type = t; - cmd->next = b->base->allocated + alignment; -#ifdef NK_INCLUDE_COMMAND_USERDATA - cmd->userdata = b->userdata; -#endif - b->end = cmd->next; - return cmd; -} -NK_API void -nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r) -{ - struct nk_command_scissor *cmd; - NK_ASSERT(b); - if (!b) return; - - b->clip.x = r.x; - b->clip.y = r.y; - b->clip.w = r.w; - b->clip.h = r.h; - cmd = (struct nk_command_scissor*) - nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd)); - - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); -} -NK_API void -nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, - float x1, float y1, float line_thickness, struct nk_color c) -{ - struct nk_command_line *cmd; - NK_ASSERT(b); - if (!b || line_thickness <= 0) return; - cmd = (struct nk_command_line*) - nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->begin.x = (short)x0; - cmd->begin.y = (short)y0; - cmd->end.x = (short)x1; - cmd->end.y = (short)y1; - cmd->color = c; -} -NK_API void -nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay, - float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y, - float bx, float by, float line_thickness, struct nk_color col) -{ - struct nk_command_curve *cmd; - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - - cmd = (struct nk_command_curve*) - nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->begin.x = (short)ax; - cmd->begin.y = (short)ay; - cmd->ctrl[0].x = (short)ctrl0x; - cmd->ctrl[0].y = (short)ctrl0y; - cmd->ctrl[1].x = (short)ctrl1x; - cmd->ctrl[1].y = (short)ctrl1y; - cmd->end.x = (short)bx; - cmd->end.y = (short)by; - cmd->color = col; -} -NK_API void -nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect, - float rounding, float line_thickness, struct nk_color c) -{ - struct nk_command_rect *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - cmd = (struct nk_command_rect*) - nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd)); - if (!cmd) return; - cmd->rounding = (unsigned short)rounding; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->color = c; -} -NK_API void -nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect, - float rounding, struct nk_color c) -{ - struct nk_command_rect_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - - cmd = (struct nk_command_rect_filled*) - nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->rounding = (unsigned short)rounding; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->color = c; -} -NK_API void -nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect, - struct nk_color left, struct nk_color top, struct nk_color right, - struct nk_color bottom) -{ - struct nk_command_rect_multi_color *cmd; - NK_ASSERT(b); - if (!b || rect.w == 0 || rect.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - - cmd = (struct nk_command_rect_multi_color*) - nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->left = left; - cmd->top = top; - cmd->right = right; - cmd->bottom = bottom; -} -NK_API void -nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r, - float line_thickness, struct nk_color c) -{ - struct nk_command_circle *cmd; - if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_circle*) - nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(r.w, 0); - cmd->h = (unsigned short)NK_MAX(r.h, 0); - cmd->color = c; -} -NK_API void -nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c) -{ - struct nk_command_circle_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || r.w == 0 || r.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_circle_filled*) - nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(r.w, 0); - cmd->h = (unsigned short)NK_MAX(r.h, 0); - cmd->color = c; -} -NK_API void -nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius, - float a_min, float a_max, float line_thickness, struct nk_color c) -{ - struct nk_command_arc *cmd; - if (!b || c.a == 0 || line_thickness <= 0) return; - cmd = (struct nk_command_arc*) - nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->cx = (short)cx; - cmd->cy = (short)cy; - cmd->r = (unsigned short)radius; - cmd->a[0] = a_min; - cmd->a[1] = a_max; - cmd->color = c; -} -NK_API void -nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius, - float a_min, float a_max, struct nk_color c) -{ - struct nk_command_arc_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0) return; - cmd = (struct nk_command_arc_filled*) - nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->cx = (short)cx; - cmd->cy = (short)cy; - cmd->r = (unsigned short)radius; - cmd->a[0] = a_min; - cmd->a[1] = a_max; - cmd->color = c; -} -NK_API void -nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, - float y1, float x2, float y2, float line_thickness, struct nk_color c) -{ - struct nk_command_triangle *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_triangle*) - nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->a.x = (short)x0; - cmd->a.y = (short)y0; - cmd->b.x = (short)x1; - cmd->b.y = (short)y1; - cmd->c.x = (short)x2; - cmd->c.y = (short)y2; - cmd->color = c; -} -NK_API void -nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, - float y1, float x2, float y2, struct nk_color c) -{ - struct nk_command_triangle_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0) return; - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_triangle_filled*) - nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->a.x = (short)x0; - cmd->a.y = (short)y0; - cmd->b.x = (short)x1; - cmd->b.y = (short)y1; - cmd->c.x = (short)x2; - cmd->c.y = (short)y2; - cmd->color = c; -} -NK_API void -nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count, - float line_thickness, struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polygon *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size); - if (!cmd) return; - cmd->color = col; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->point_count = (unsigned short)point_count; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2]; - cmd->points[i].y = (short)points[i*2+1]; - } -} -NK_API void -nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count, - struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polygon_filled *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polygon_filled*) - nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size); - if (!cmd) return; - cmd->color = col; - cmd->point_count = (unsigned short)point_count; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2+0]; - cmd->points[i].y = (short)points[i*2+1]; - } -} -NK_API void -nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count, - float line_thickness, struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polyline *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size); - if (!cmd) return; - cmd->color = col; - cmd->point_count = (unsigned short)point_count; - cmd->line_thickness = (unsigned short)line_thickness; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2]; - cmd->points[i].y = (short)points[i*2+1]; - } -} -NK_API void -nk_draw_image(struct nk_command_buffer *b, struct nk_rect r, - const struct nk_image *img, struct nk_color col) -{ - struct nk_command_image *cmd; - NK_ASSERT(b); - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - cmd = (struct nk_command_image*) - nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); - cmd->img = *img; - cmd->col = col; -} -NK_API void -nk_push_custom(struct nk_command_buffer *b, struct nk_rect r, - nk_command_custom_callback cb, nk_handle usr) -{ - struct nk_command_custom *cmd; - NK_ASSERT(b); - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - cmd = (struct nk_command_custom*) - nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); - cmd->callback_data = usr; - cmd->callback = cb; -} -NK_API void -nk_draw_text(struct nk_command_buffer *b, struct nk_rect r, - const char *string, int length, const struct nk_user_font *font, - struct nk_color bg, struct nk_color fg) -{ - float text_width = 0; - struct nk_command_text *cmd; - - NK_ASSERT(b); - NK_ASSERT(font); - if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - /* make sure text fits inside bounds */ - text_width = font->width(font->userdata, font->height, string, length); - if (text_width > r.w){ - int glyphs = 0; - float txt_width = (float)text_width; - length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0); - } - - if (!length) return; - cmd = (struct nk_command_text*) - nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)r.w; - cmd->h = (unsigned short)r.h; - cmd->background = bg; - cmd->foreground = fg; - cmd->font = font; - cmd->length = length; - cmd->height = font->height; - NK_MEMCPY(cmd->string, string, (nk_size)length); - cmd->string[length] = '\0'; -} - - - - - -/* =============================================================== - * - * VERTEX - * - * ===============================================================*/ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_API void -nk_draw_list_init(struct nk_draw_list *list) -{ - nk_size i = 0; - NK_ASSERT(list); - if (!list) return; - nk_zero(list, sizeof(*list)); - for (i = 0; i < NK_LEN(list->circle_vtx); ++i) { - const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI; - list->circle_vtx[i].x = (float)NK_COS(a); - list->circle_vtx[i].y = (float)NK_SIN(a); - } -} -NK_API void -nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config, - struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, - enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa) -{ - NK_ASSERT(canvas); - NK_ASSERT(config); - NK_ASSERT(cmds); - NK_ASSERT(vertices); - NK_ASSERT(elements); - if (!canvas || !config || !cmds || !vertices || !elements) - return; - - canvas->buffer = cmds; - canvas->config = *config; - canvas->elements = elements; - canvas->vertices = vertices; - canvas->line_AA = line_aa; - canvas->shape_AA = shape_aa; - canvas->clip_rect = nk_null_rect; - - canvas->cmd_offset = 0; - canvas->element_count = 0; - canvas->vertex_count = 0; - canvas->cmd_offset = 0; - canvas->cmd_count = 0; - canvas->path_count = 0; -} -NK_API const struct nk_draw_command* -nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) -{ - nk_byte *memory; - nk_size offset; - const struct nk_draw_command *cmd; - - NK_ASSERT(buffer); - if (!buffer || !buffer->size || !canvas->cmd_count) - return 0; - - memory = (nk_byte*)buffer->memory.ptr; - offset = buffer->memory.size - canvas->cmd_offset; - cmd = nk_ptr_add(const struct nk_draw_command, memory, offset); - return cmd; -} -NK_API const struct nk_draw_command* -nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) -{ - nk_size size; - nk_size offset; - nk_byte *memory; - const struct nk_draw_command *end; - - NK_ASSERT(buffer); - NK_ASSERT(canvas); - if (!buffer || !canvas) - return 0; - - memory = (nk_byte*)buffer->memory.ptr; - size = buffer->memory.size; - offset = size - canvas->cmd_offset; - end = nk_ptr_add(const struct nk_draw_command, memory, offset); - end -= (canvas->cmd_count-1); - return end; -} -NK_API const struct nk_draw_command* -nk__draw_list_next(const struct nk_draw_command *cmd, - const struct nk_buffer *buffer, const struct nk_draw_list *canvas) -{ - const struct nk_draw_command *end; - NK_ASSERT(buffer); - NK_ASSERT(canvas); - if (!cmd || !buffer || !canvas) - return 0; - - end = nk__draw_list_end(canvas, buffer); - if (cmd <= end) return 0; - return (cmd-1); -} -NK_INTERN struct nk_vec2* -nk_draw_list_alloc_path(struct nk_draw_list *list, int count) -{ - struct nk_vec2 *points; - NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2); - points = (struct nk_vec2*) - nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT, - point_size * (nk_size)count, point_align); - - if (!points) return 0; - if (!list->path_offset) { - void *memory = nk_buffer_memory(list->buffer); - list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory); - } - list->path_count += (unsigned int)count; - return points; -} -NK_INTERN struct nk_vec2 -nk_draw_list_path_last(struct nk_draw_list *list) -{ - void *memory; - struct nk_vec2 *point; - NK_ASSERT(list->path_count); - memory = nk_buffer_memory(list->buffer); - point = nk_ptr_add(struct nk_vec2, memory, list->path_offset); - point += (list->path_count-1); - return *point; -} -NK_INTERN struct nk_draw_command* -nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip, - nk_handle texture) -{ - NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command); - NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command); - struct nk_draw_command *cmd; - - NK_ASSERT(list); - cmd = (struct nk_draw_command*) - nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align); - - if (!cmd) return 0; - if (!list->cmd_count) { - nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer); - nk_size total = nk_buffer_total(list->buffer); - memory = nk_ptr_add(nk_byte, memory, total); - list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd); - } - - cmd->elem_count = 0; - cmd->clip_rect = clip; - cmd->texture = texture; -#ifdef NK_INCLUDE_COMMAND_USERDATA - cmd->userdata = list->userdata; -#endif - - list->cmd_count++; - list->clip_rect = clip; - return cmd; -} -NK_INTERN struct nk_draw_command* -nk_draw_list_command_last(struct nk_draw_list *list) -{ - void *memory; - nk_size size; - struct nk_draw_command *cmd; - NK_ASSERT(list->cmd_count); - - memory = nk_buffer_memory(list->buffer); - size = nk_buffer_total(list->buffer); - cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset); - return (cmd - (list->cmd_count-1)); -} -NK_INTERN void -nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect) -{ - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) { - nk_draw_list_push_command(list, rect, list->config.null.texture); - } else { - struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) - prev->clip_rect = rect; - nk_draw_list_push_command(list, rect, prev->texture); - } -} -NK_INTERN void -nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture) -{ - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) { - nk_draw_list_push_command(list, nk_null_rect, texture); - } else { - struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) { - prev->texture = texture; - #ifdef NK_INCLUDE_COMMAND_USERDATA - prev->userdata = list->userdata; - #endif - } else if (prev->texture.id != texture.id - #ifdef NK_INCLUDE_COMMAND_USERDATA - || prev->userdata.id != list->userdata.id - #endif - ) nk_draw_list_push_command(list, prev->clip_rect, texture); - } -} -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void -nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata) -{ - list->userdata = userdata; -} -#endif -NK_INTERN void* -nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count) -{ - void *vtx; - NK_ASSERT(list); - if (!list) return 0; - vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, - list->config.vertex_size*count, list->config.vertex_alignment); - if (!vtx) return 0; - list->vertex_count += (unsigned int)count; - - /* This assert triggers because your are drawing a lot of stuff and nuklear - * defined `nk_draw_index` as `nk_ushort` to safe space be default. - * - * So you reached the maximum number of indicies or rather vertexes. - * To solve this issue please change typdef `nk_draw_index` to `nk_uint` - * and don't forget to specify the new element size in your drawing - * backend (OpenGL, DirectX, ...). For example in OpenGL for `glDrawElements` - * instead of specifing `GL_UNSIGNED_SHORT` you have to define `GL_UNSIGNED_INT`. - * Sorry for the inconvenience. */ - if(sizeof(nk_draw_index)==2) NK_ASSERT((list->vertex_count < NK_USHORT_MAX && - "To many verticies for 16-bit vertex indicies. Please read comment above on how to solve this problem")); - return vtx; -} -NK_INTERN nk_draw_index* -nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count) -{ - nk_draw_index *ids; - struct nk_draw_command *cmd; - NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index); - NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index); - NK_ASSERT(list); - if (!list) return 0; - - ids = (nk_draw_index*) - nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align); - if (!ids) return 0; - cmd = nk_draw_list_command_last(list); - list->element_count += (unsigned int)count; - cmd->elem_count += (unsigned int)count; - return ids; -} -NK_INTERN int -nk_draw_vertex_layout_element_is_end_of_layout( - const struct nk_draw_vertex_layout_element *element) -{ - return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT || - element->format == NK_FORMAT_COUNT); -} -NK_INTERN void -nk_draw_vertex_color(void *attr, const float *vals, - enum nk_draw_vertex_layout_format format) -{ - /* if this triggers you tried to provide a value format for a color */ - float val[4]; - NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN); - NK_ASSERT(format <= NK_FORMAT_COLOR_END); - if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return; - - val[0] = NK_SATURATE(vals[0]); - val[1] = NK_SATURATE(vals[1]); - val[2] = NK_SATURATE(vals[2]); - val[3] = NK_SATURATE(vals[3]); - - switch (format) { - default: NK_ASSERT(0 && "Invalid vertex layout color format"); break; - case NK_FORMAT_R8G8B8A8: - case NK_FORMAT_R8G8B8: { - struct nk_color col = nk_rgba_fv(val); - NK_MEMCPY(attr, &col.r, sizeof(col)); - } break; - case NK_FORMAT_B8G8R8A8: { - struct nk_color col = nk_rgba_fv(val); - struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a); - NK_MEMCPY(attr, &bgra, sizeof(bgra)); - } break; - case NK_FORMAT_R16G15B16: { - nk_ushort col[3]; - col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX); - col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX); - col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R16G15B16A16: { - nk_ushort col[4]; - col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX); - col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX); - col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX); - col[3] = (nk_ushort)(val[3]*(float)NK_USHORT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32: { - nk_uint col[3]; - col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX); - col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX); - col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32A32: { - nk_uint col[4]; - col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX); - col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX); - col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX); - col[3] = (nk_uint)(val[3]*(float)NK_UINT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32A32_FLOAT: - NK_MEMCPY(attr, val, sizeof(float)*4); - break; - case NK_FORMAT_R32G32B32A32_DOUBLE: { - double col[4]; - col[0] = (double)val[0]; - col[1] = (double)val[1]; - col[2] = (double)val[2]; - col[3] = (double)val[3]; - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_RGB32: - case NK_FORMAT_RGBA32: { - struct nk_color col = nk_rgba_fv(val); - nk_uint color = nk_color_u32(col); - NK_MEMCPY(attr, &color, sizeof(color)); - } break; } -} -NK_INTERN void -nk_draw_vertex_element(void *dst, const float *values, int value_count, - enum nk_draw_vertex_layout_format format) -{ - int value_index; - void *attribute = dst; - /* if this triggers you tried to provide a color format for a value */ - NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN); - if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return; - for (value_index = 0; value_index < value_count; ++value_index) { - switch (format) { - default: NK_ASSERT(0 && "invalid vertex layout format"); break; - case NK_FORMAT_SCHAR: { - char value = (char)NK_CLAMP((float)NK_SCHAR_MIN, values[value_index], (float)NK_SCHAR_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(char)); - } break; - case NK_FORMAT_SSHORT: { - nk_short value = (nk_short)NK_CLAMP((float)NK_SSHORT_MIN, values[value_index], (float)NK_SSHORT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(value)); - } break; - case NK_FORMAT_SINT: { - nk_int value = (nk_int)NK_CLAMP((float)NK_SINT_MIN, values[value_index], (float)NK_SINT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(nk_int)); - } break; - case NK_FORMAT_UCHAR: { - unsigned char value = (unsigned char)NK_CLAMP((float)NK_UCHAR_MIN, values[value_index], (float)NK_UCHAR_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(unsigned char)); - } break; - case NK_FORMAT_USHORT: { - nk_ushort value = (nk_ushort)NK_CLAMP((float)NK_USHORT_MIN, values[value_index], (float)NK_USHORT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(value)); - } break; - case NK_FORMAT_UINT: { - nk_uint value = (nk_uint)NK_CLAMP((float)NK_UINT_MIN, values[value_index], (float)NK_UINT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(nk_uint)); - } break; - case NK_FORMAT_FLOAT: - NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index])); - attribute = (void*)((char*)attribute + sizeof(float)); - break; - case NK_FORMAT_DOUBLE: { - double value = (double)values[value_index]; - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(double)); - } break; - } - } -} -NK_INTERN void* -nk_draw_vertex(void *dst, const struct nk_convert_config *config, - struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color) -{ - void *result = (void*)((char*)dst + config->vertex_size); - const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout; - while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) { - void *address = (void*)((char*)dst + elem_iter->offset); - switch (elem_iter->attribute) { - case NK_VERTEX_ATTRIBUTE_COUNT: - default: NK_ASSERT(0 && "wrong element attribute"); break; - case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break; - case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break; - case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break; - } - elem_iter++; - } - return result; -} -NK_API void -nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points, - const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed, - float thickness, enum nk_anti_aliasing aliasing) -{ - nk_size count; - int thick_line; - struct nk_colorf col; - struct nk_colorf col_trans; - NK_ASSERT(list); - if (!list || points_count < 2) return; - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - count = points_count; - if (!closed) count = points_count-1; - thick_line = thickness > 1.0f; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_draw_list_push_userdata(list, list->userdata); -#endif - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - nk_color_fv(&col.r, color); - col_trans = col; - col_trans.a = 0; - - if (aliasing == NK_ANTI_ALIASING_ON) { - /* ANTI-ALIASED STROKE */ - const float AA_SIZE = 1.0f; - NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); - - /* allocate vertices and elements */ - nk_size i1 = 0; - nk_size vertex_offset; - nk_size index = list->vertex_count; - - const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12); - const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3); - - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - nk_size size; - struct nk_vec2 *normals, *temp; - if (!vtx || !ids) return; - - /* temporary allocate normals + points */ - vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); - nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); - size = pnt_size * ((thick_line) ? 5 : 3) * points_count; - normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); - if (!normals) return; - temp = normals + points_count; - - /* make sure vertex pointer is still correct */ - vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); - - /* calculate normals */ - for (i1 = 0; i1 < count; ++i1) { - const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); - struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]); - float len; - - /* vec2 inverted length */ - len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - - diff = nk_vec2_muls(diff, len); - normals[i1].x = diff.y; - normals[i1].y = -diff.x; - } - - if (!closed) - normals[points_count-1] = normals[points_count-2]; - - if (!thick_line) { - nk_size idx1, i; - if (!closed) { - struct nk_vec2 d; - temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE)); - temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE)); - d = nk_vec2_muls(normals[points_count-1], AA_SIZE); - temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d); - temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d); - } - - /* fill elements */ - idx1 = index; - for (i1 = 0; i1 < count; i1++) { - struct nk_vec2 dm; - float dmr2; - nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); - nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3); - - /* average normals */ - dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); - dmr2 = dm.x * dm.x + dm.y* dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f/dmr2; - scale = NK_MIN(100.0f, scale); - dm = nk_vec2_muls(dm, scale); - } - - dm = nk_vec2_muls(dm, AA_SIZE); - temp[i2*2+0] = nk_vec2_add(points[i2], dm); - temp[i2*2+1] = nk_vec2_sub(points[i2], dm); - - ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0); - ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); - ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0); - ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); - ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); - ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1); - ids += 12; - idx1 = idx2; - } - - /* fill vertices */ - for (i = 0; i < points_count; ++i) { - const struct nk_vec2 uv = list->config.null.uv; - vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans); - } - } else { - nk_size idx1, i; - const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; - if (!closed) { - struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE); - struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness); - - temp[0] = nk_vec2_add(points[0], d1); - temp[1] = nk_vec2_add(points[0], d2); - temp[2] = nk_vec2_sub(points[0], d2); - temp[3] = nk_vec2_sub(points[0], d1); - - d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE); - d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness); - - temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1); - temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2); - temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2); - temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1); - } - - /* add all elements */ - idx1 = index; - for (i1 = 0; i1 < count; ++i1) { - struct nk_vec2 dm_out, dm_in; - const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1); - nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4); - - /* average normals */ - struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); - float dmr2 = dm.x * dm.x + dm.y* dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f/dmr2; - scale = NK_MIN(100.0f, scale); - dm = nk_vec2_muls(dm, scale); - } - - dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE)); - dm_in = nk_vec2_muls(dm, half_inner_thickness); - temp[i2*4+0] = nk_vec2_add(points[i2], dm_out); - temp[i2*4+1] = nk_vec2_add(points[i2], dm_in); - temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in); - temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out); - - /* add indexes */ - ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1); - ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); - ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1); - ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); - ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); - ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1); - ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2); - ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3); - ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2); - ids += 18; - idx1 = idx2; - } - - /* add vertices */ - for (i = 0; i < points_count; ++i) { - const struct nk_vec2 uv = list->config.null.uv; - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans); - } - } - /* free temporary normals + points */ - nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); - } else { - /* NON ANTI-ALIASED STROKE */ - nk_size i1 = 0; - nk_size idx = list->vertex_count; - const nk_size idx_count = count * 6; - const nk_size vtx_count = count * 4; - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - if (!vtx || !ids) return; - - for (i1 = 0; i1 < count; ++i1) { - float dx, dy; - const struct nk_vec2 uv = list->config.null.uv; - const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1; - const struct nk_vec2 p1 = points[i1]; - const struct nk_vec2 p2 = points[i2]; - struct nk_vec2 diff = nk_vec2_sub(p2, p1); - float len; - - /* vec2 inverted length */ - len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - diff = nk_vec2_muls(diff, len); - - /* add vertices */ - dx = diff.x * (thickness * 0.5f); - dy = diff.y * (thickness * 0.5f); - - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col); - - ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1); - ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0); - ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3); - - ids += 6; - idx += 4; - } - } -} -NK_API void -nk_draw_list_fill_poly_convex(struct nk_draw_list *list, - const struct nk_vec2 *points, const unsigned int points_count, - struct nk_color color, enum nk_anti_aliasing aliasing) -{ - struct nk_colorf col; - struct nk_colorf col_trans; - - NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); - NK_ASSERT(list); - if (!list || points_count < 3) return; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_draw_list_push_userdata(list, list->userdata); -#endif - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - nk_color_fv(&col.r, color); - col_trans = col; - col_trans.a = 0; - - if (aliasing == NK_ANTI_ALIASING_ON) { - nk_size i = 0; - nk_size i0 = 0; - nk_size i1 = 0; - - const float AA_SIZE = 1.0f; - nk_size vertex_offset = 0; - nk_size index = list->vertex_count; - - const nk_size idx_count = (points_count-2)*3 + points_count*6; - const nk_size vtx_count = (points_count*2); - - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - nk_size size = 0; - struct nk_vec2 *normals = 0; - unsigned int vtx_inner_idx = (unsigned int)(index + 0); - unsigned int vtx_outer_idx = (unsigned int)(index + 1); - if (!vtx || !ids) return; - - /* temporary allocate normals */ - vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); - nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); - size = pnt_size * points_count; - normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); - if (!normals) return; - vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); - - /* add elements */ - for (i = 2; i < points_count; i++) { - ids[0] = (nk_draw_index)(vtx_inner_idx); - ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1)); - ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1)); - ids += 3; - } - - /* compute normals */ - for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { - struct nk_vec2 p0 = points[i0]; - struct nk_vec2 p1 = points[i1]; - struct nk_vec2 diff = nk_vec2_sub(p1, p0); - - /* vec2 inverted length */ - float len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - diff = nk_vec2_muls(diff, len); - - normals[i0].x = diff.y; - normals[i0].y = -diff.x; - } - - /* add vertices + indexes */ - for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { - const struct nk_vec2 uv = list->config.null.uv; - struct nk_vec2 n0 = normals[i0]; - struct nk_vec2 n1 = normals[i1]; - struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f); - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f / dmr2; - scale = NK_MIN(scale, 100.0f); - dm = nk_vec2_muls(dm, scale); - } - dm = nk_vec2_muls(dm, AA_SIZE * 0.5f); - - /* add vertices */ - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans); - - /* add indexes */ - ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); - ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1)); - ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); - ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); - ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1)); - ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); - ids += 6; - } - /* free temporary normals + points */ - nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); - } else { - nk_size i = 0; - nk_size index = list->vertex_count; - const nk_size idx_count = (points_count-2)*3; - const nk_size vtx_count = points_count; - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - if (!vtx || !ids) return; - for (i = 0; i < vtx_count; ++i) - vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col); - for (i = 2; i < points_count; ++i) { - ids[0] = (nk_draw_index)index; - ids[1] = (nk_draw_index)(index+ i - 1); - ids[2] = (nk_draw_index)(index+i); - ids += 3; - } - } -} -NK_API void -nk_draw_list_path_clear(struct nk_draw_list *list) -{ - NK_ASSERT(list); - if (!list) return; - nk_buffer_reset(list->buffer, NK_BUFFER_FRONT); - list->path_count = 0; - list->path_offset = 0; -} -NK_API void -nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos) -{ - struct nk_vec2 *points = 0; - struct nk_draw_command *cmd = 0; - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) - nk_draw_list_add_clip(list, nk_null_rect); - - cmd = nk_draw_list_command_last(list); - if (cmd && cmd->texture.ptr != list->config.null.texture.ptr) - nk_draw_list_push_image(list, list->config.null.texture); - - points = nk_draw_list_alloc_path(list, 1); - if (!points) return; - points[0] = pos; -} -NK_API void -nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center, - float radius, int a_min, int a_max) -{ - int a = 0; - NK_ASSERT(list); - if (!list) return; - if (a_min <= a_max) { - for (a = a_min; a <= a_max; a++) { - const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)]; - const float x = center.x + c.x * radius; - const float y = center.y + c.y * radius; - nk_draw_list_path_line_to(list, nk_vec2(x, y)); - } - } -} -NK_API void -nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center, - float radius, float a_min, float a_max, unsigned int segments) -{ - unsigned int i = 0; - NK_ASSERT(list); - if (!list) return; - if (radius == 0.0f) return; - - /* This algorithm for arc drawing relies on these two trigonometric identities[1]: - sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b) - cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b) - - Two coordinates (x, y) of a point on a circle centered on - the origin can be written in polar form as: - x = r * cos(a) - y = r * sin(a) - where r is the radius of the circle, - a is the angle between (x, y) and the origin. - - This allows us to rotate the coordinates around the - origin by an angle b using the following transformation: - x' = r * cos(a + b) = x * cos(b) - y * sin(b) - y' = r * sin(a + b) = y * cos(b) + x * sin(b) - - [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities - */ - {const float d_angle = (a_max - a_min) / (float)segments; - const float sin_d = (float)NK_SIN(d_angle); - const float cos_d = (float)NK_COS(d_angle); - - float cx = (float)NK_COS(a_min) * radius; - float cy = (float)NK_SIN(a_min) * radius; - for(i = 0; i <= segments; ++i) { - float new_cx, new_cy; - const float x = center.x + cx; - const float y = center.y + cy; - nk_draw_list_path_line_to(list, nk_vec2(x, y)); - - new_cx = cx * cos_d - cy * sin_d; - new_cy = cy * cos_d + cx * sin_d; - cx = new_cx; - cy = new_cy; - }} -} -NK_API void -nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, float rounding) -{ - float r; - NK_ASSERT(list); - if (!list) return; - r = rounding; - r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); - r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); - - if (r == 0.0f) { - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y)); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y)); - } else { - nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9); - nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12); - nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3); - nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6); - } -} -NK_API void -nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2, - struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments) -{ - float t_step; - unsigned int i_step; - struct nk_vec2 p1; - - NK_ASSERT(list); - NK_ASSERT(list->path_count); - if (!list || !list->path_count) return; - num_segments = NK_MAX(num_segments, 1); - - p1 = nk_draw_list_path_last(list); - t_step = 1.0f/(float)num_segments; - for (i_step = 1; i_step <= num_segments; ++i_step) { - float t = t_step * (float)i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t * t *t; - float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; - float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; - nk_draw_list_path_line_to(list, nk_vec2(x,y)); - } -} -NK_API void -nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color) -{ - struct nk_vec2 *points; - NK_ASSERT(list); - if (!list) return; - points = (struct nk_vec2*)nk_buffer_memory(list->buffer); - nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA); - nk_draw_list_path_clear(list); -} -NK_API void -nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color, - enum nk_draw_list_stroke closed, float thickness) -{ - struct nk_vec2 *points; - NK_ASSERT(list); - if (!list) return; - points = (struct nk_vec2*)nk_buffer_memory(list->buffer); - nk_draw_list_stroke_poly_line(list, points, list->path_count, color, - closed, thickness, list->config.line_AA); - nk_draw_list_path_clear(list); -} -NK_API void -nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_color col, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - } else { - nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f))); - nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f))); - } - nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); -} -NK_API void -nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color col, float rounding) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } else { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } nk_draw_list_path_fill(list, col); -} -NK_API void -nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color col, float rounding, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } else { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} -NK_API void -nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color left, struct nk_color top, struct nk_color right, - struct nk_color bottom) -{ - void *vtx; - struct nk_colorf col_left, col_top; - struct nk_colorf col_right, col_bottom; - nk_draw_index *idx; - nk_draw_index index; - - nk_color_fv(&col_left.r, left); - nk_color_fv(&col_right.r, right); - nk_color_fv(&col_top.r, top); - nk_color_fv(&col_bottom.r, bottom); - - NK_ASSERT(list); - if (!list) return; - - nk_draw_list_push_image(list, list->config.null.texture); - index = (nk_draw_index)list->vertex_count; - vtx = nk_draw_list_alloc_vertices(list, 4); - idx = nk_draw_list_alloc_elements(list, 6); - if (!vtx || !idx) return; - - idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); - idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); - idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); - - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom); -} -NK_API void -nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_vec2 c, struct nk_color col) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, c); - nk_draw_list_path_fill(list, col); -} -NK_API void -nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, c); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} -NK_API void -nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center, - float radius, struct nk_color col, unsigned int segs) -{ - float a_max; - NK_ASSERT(list); - if (!list || !col.a) return; - a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - nk_draw_list_path_fill(list, col); -} -NK_API void -nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center, - float radius, struct nk_color col, unsigned int segs, float thickness) -{ - float a_max; - NK_ASSERT(list); - if (!list || !col.a) return; - a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} -NK_API void -nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0, - struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, - struct nk_color col, unsigned int segments, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, p0); - nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments); - nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); -} -NK_INTERN void -nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc, - struct nk_color color) -{ - void *vtx; - struct nk_vec2 uvb; - struct nk_vec2 uvd; - struct nk_vec2 b; - struct nk_vec2 d; - - struct nk_colorf col; - nk_draw_index *idx; - nk_draw_index index; - NK_ASSERT(list); - if (!list) return; - - nk_color_fv(&col.r, color); - uvb = nk_vec2(uvc.x, uva.y); - uvd = nk_vec2(uva.x, uvc.y); - b = nk_vec2(c.x, a.y); - d = nk_vec2(a.x, c.y); - - index = (nk_draw_index)list->vertex_count; - vtx = nk_draw_list_alloc_vertices(list, 4); - idx = nk_draw_list_alloc_elements(list, 6); - if (!vtx || !idx) return; - - idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); - idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); - idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); - - vtx = nk_draw_vertex(vtx, &list->config, a, uva, col); - vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col); - vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col); - vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col); -} -NK_API void -nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture, - struct nk_rect rect, struct nk_color color) -{ - NK_ASSERT(list); - if (!list) return; - /* push new command with given texture */ - nk_draw_list_push_image(list, texture.handle); - if (nk_image_is_subimage(&texture)) { - /* add region inside of the texture */ - struct nk_vec2 uv[2]; - uv[0].x = (float)texture.region[0]/(float)texture.w; - uv[0].y = (float)texture.region[1]/(float)texture.h; - uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w; - uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h; - nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color); - } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), - nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color); -} -NK_API void -nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font, - struct nk_rect rect, const char *text, int len, float font_height, - struct nk_color fg) -{ - float x = 0; - int text_len = 0; - nk_rune unicode = 0; - nk_rune next = 0; - int glyph_len = 0; - int next_glyph_len = 0; - struct nk_user_font_glyph g; - - NK_ASSERT(list); - if (!list || !len || !text) return; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return; - - nk_draw_list_push_image(list, font->texture); - x = rect.x; - glyph_len = nk_utf_decode(text, &unicode, len); - if (!glyph_len) return; - - /* draw every glyph image */ - fg.a = (nk_byte)((float)fg.a * list->config.global_alpha); - while (text_len < len && glyph_len) { - float gx, gy, gh, gw; - float char_width = 0; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len); - font->query(font->userdata, font_height, &g, unicode, - (next == NK_UTF_INVALID) ? '\0' : next); - - /* calculate and draw glyph drawing rectangle and image */ - gx = x + g.offset.x; - gy = rect.y + g.offset.y; - gw = g.width; gh = g.height; - char_width = g.xadvance; - nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh), - g.uv[0], g.uv[1], fg); - - /* offset next glyph */ - text_len += glyph_len; - x += char_width; - glyph_len = next_glyph_len; - unicode = next; - } -} -NK_API nk_flags -nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, - struct nk_buffer *vertices, struct nk_buffer *elements, - const struct nk_convert_config *config) -{ - nk_flags res = NK_CONVERT_SUCCESS; - const struct nk_command *cmd; - NK_ASSERT(ctx); - NK_ASSERT(cmds); - NK_ASSERT(vertices); - NK_ASSERT(elements); - NK_ASSERT(config); - NK_ASSERT(config->vertex_layout); - NK_ASSERT(config->vertex_size); - if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout) - return NK_CONVERT_INVALID_PARAM; - - nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements, - config->line_AA, config->shape_AA); - nk_foreach(cmd, ctx) - { -#ifdef NK_INCLUDE_COMMAND_USERDATA - ctx->draw_list.userdata = cmd->userdata; -#endif - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd; - nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h)); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line*)cmd; - nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y), - nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve*)cmd; - nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y), - nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x, - q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color, - config->curve_segment_count, q->line_thickness); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect*)cmd; - nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding, r->line_thickness); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd; - nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: { - const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd; - nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->left, r->top, r->right, r->bottom); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle*)cmd; - nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count, c->line_thickness); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count); - } break; - case NK_COMMAND_ARC: { - const struct nk_command_arc *c = (const struct nk_command_arc*)cmd; - nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); - nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], config->arc_segment_count); - nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness); - } break; - case NK_COMMAND_ARC_FILLED: { - const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd; - nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); - nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], config->arc_segment_count); - nk_draw_list_path_fill(&ctx->draw_list, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd; - nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), - nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color, - t->line_thickness); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd; - nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), - nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color); - } break; - case NK_COMMAND_POLYGON: { - int i; - const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness); - } break; - case NK_COMMAND_POLYGON_FILLED: { - int i; - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_fill(&ctx->draw_list, p->color); - } break; - case NK_COMMAND_POLYLINE: { - int i; - const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h), - t->string, t->length, t->height, t->foreground); - } break; - case NK_COMMAND_IMAGE: { - const struct nk_command_image *i = (const struct nk_command_image*)cmd; - nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col); - } break; - case NK_COMMAND_CUSTOM: { - const struct nk_command_custom *c = (const struct nk_command_custom*)cmd; - c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data); - } break; - default: break; - } - } - res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0; - res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0; - res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0; - return res; -} -NK_API const struct nk_draw_command* -nk__draw_begin(const struct nk_context *ctx, - const struct nk_buffer *buffer) -{ - return nk__draw_list_begin(&ctx->draw_list, buffer); -} -NK_API const struct nk_draw_command* -nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer) -{ - return nk__draw_list_end(&ctx->draw_list, buffer); -} -NK_API const struct nk_draw_command* -nk__draw_next(const struct nk_draw_command *cmd, - const struct nk_buffer *buffer, const struct nk_context *ctx) -{ - return nk__draw_list_next(cmd, buffer, &ctx->draw_list); -} -#endif - - -/* stb_rect_pack.h - v1.00 - public domain - rectangle packing */ -/* Sean Barrett 2014 */ -/* */ -/* Useful for e.g. packing rectangular textures into an atlas. */ -/* Does not do rotation. */ -/* */ -/* Not necessarily the awesomest packing method, but better than */ -/* the totally naive one in stb_truetype (which is primarily what */ -/* this is meant to replace). */ -/* */ -/* Has only had a few tests run, may have issues. */ -/* */ -/* More docs to come. */ -/* */ -/* No memory allocations; uses qsort() and assert() from stdlib. */ -/* Can override those by defining STBRP_SORT and STBRP_ASSERT. */ -/* */ -/* This library currently uses the Skyline Bottom-Left algorithm. */ -/* */ -/* Please note: better rectangle packers are welcome! Please */ -/* implement them to the same API, but with a different init */ -/* function. */ -/* */ -/* Credits */ -/* */ -/* Library */ -/* Sean Barrett */ -/* Minor features */ -/* Martins Mozeiko */ -/* github:IntellectualKitty */ -/* */ -/* Bugfixes / warning fixes */ -/* Jeremy Jaussaud */ -/* Fabian Giesen */ -/* */ -/* Version history: */ -/* */ -/* 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles */ -/* 0.99 (2019-02-07) warning fixes */ -/* 0.11 (2017-03-03) return packing success/fail result */ -/* 0.10 (2016-10-25) remove cast-away-const to avoid warnings */ -/* 0.09 (2016-08-27) fix compiler warnings */ -/* 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) */ -/* 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) */ -/* 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort */ -/* 0.05: added STBRP_ASSERT to allow replacing assert */ -/* 0.04: fixed minor bug in STBRP_LARGE_RECTS support */ -/* 0.01: initial release */ -/* */ -/* LICENSE */ -/* */ -/* See end of file for license information. */ - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* INCLUDE SECTION */ -/* */ - -#ifndef STB_INCLUDE_STB_RECT_PACK_H -#define STB_INCLUDE_STB_RECT_PACK_H - -#define STB_RECT_PACK_VERSION 1 - -#ifdef STBRP_STATIC -#define STBRP_DEF static -#else -#define STBRP_DEF extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct stbrp_context stbrp_context; -typedef struct stbrp_node stbrp_node; -typedef struct stbrp_rect stbrp_rect; - -#ifdef STBRP_LARGE_RECTS -typedef int stbrp_coord; -#else -typedef unsigned short stbrp_coord; -#endif - -STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); -/* Assign packed locations to rectangles. The rectangles are of type */ -/* 'stbrp_rect' defined below, stored in the array 'rects', and there */ -/* are 'num_rects' many of them. */ -/* */ -/* Rectangles which are successfully packed have the 'was_packed' flag */ -/* set to a non-zero value and 'x' and 'y' store the minimum location */ -/* on each axis (i.e. bottom-left in cartesian coordinates, top-left */ -/* if you imagine y increasing downwards). Rectangles which do not fit */ -/* have the 'was_packed' flag set to 0. */ -/* */ -/* You should not try to access the 'rects' array from another thread */ -/* while this function is running, as the function temporarily reorders */ -/* the array while it executes. */ -/* */ -/* To pack into another rectangle, you need to call stbrp_init_target */ -/* again. To continue packing into the same rectangle, you can call */ -/* this function again. Calling this multiple times with multiple rect */ -/* arrays will probably produce worse packing results than calling it */ -/* a single time with the full rectangle array, but the option is */ -/* available. */ -/* */ -/* The function returns 1 if all of the rectangles were successfully */ -/* packed and 0 otherwise. */ - -struct stbrp_rect -{ - /* reserved for your use: */ - int id; - - /* input: */ - stbrp_coord w, h; - - /* output: */ - stbrp_coord x, y; - int was_packed; /* non-zero if valid packing */ - -}; /* 16 bytes, nominally */ - - -STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); -/* Initialize a rectangle packer to: */ -/* pack a rectangle that is 'width' by 'height' in dimensions */ -/* using temporary storage provided by the array 'nodes', which is 'num_nodes' long */ -/* */ -/* You must call this function every time you start packing into a new target. */ -/* */ -/* There is no "shutdown" function. The 'nodes' memory must stay valid for */ -/* the following stbrp_pack_rects() call (or calls), but can be freed after */ -/* the call (or calls) finish. */ -/* */ -/* Note: to guarantee best results, either: */ -/* 1. make sure 'num_nodes' >= 'width' */ -/* or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' */ -/* */ -/* If you don't do either of the above things, widths will be quantized to multiples */ -/* of small integers to guarantee the algorithm doesn't run out of temporary storage. */ -/* */ -/* If you do #2, then the non-quantized algorithm will be used, but the algorithm */ -/* may run out of temporary storage and be unable to pack some rectangles. */ - -STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); -/* Optionally call this function after init but before doing any packing to */ -/* change the handling of the out-of-temp-memory scenario, described above. */ -/* If you call init again, this will be reset to the default (false). */ - - -STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); -/* Optionally select which packing heuristic the library should use. Different */ -/* heuristics will produce better/worse results for different data sets. */ -/* If you call init again, this will be reset to the default. */ - -enum -{ - STBRP_HEURISTIC_Skyline_default=0, - STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, - STBRP_HEURISTIC_Skyline_BF_sortHeight -}; - - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* the details of the following structures don't matter to you, but they must */ -/* be visible so you can handle the memory allocations for them */ - -struct stbrp_node -{ - stbrp_coord x,y; - stbrp_node *next; -}; - -struct stbrp_context -{ - int width; - int height; - int align; - int init_mode; - int heuristic; - int num_nodes; - stbrp_node *active_head; - stbrp_node *free_head; - stbrp_node extra[2]; /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */ -}; - -#ifdef __cplusplus -} -#endif - -#endif - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* IMPLEMENTATION SECTION */ -/* */ - -#ifdef STB_RECT_PACK_IMPLEMENTATION -#ifndef STBRP_SORT -#include -#define STBRP_SORT qsort -#endif - -#ifndef STBRP_ASSERT -#include -#define STBRP_ASSERT assert -#endif - -#ifdef _MSC_VER -#define STBRP__NOTUSED(v) (void)(v) -#else -#define STBRP__NOTUSED(v) (void)sizeof(v) -#endif - -enum -{ - STBRP__INIT_skyline = 1 -}; - -STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) -{ - switch (context->init_mode) { - case STBRP__INIT_skyline: - STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); - context->heuristic = heuristic; - break; - default: - STBRP_ASSERT(0); - } -} - -STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) -{ - if (allow_out_of_mem) - /* if it's ok to run out of memory, then don't bother aligning them; */ - /* this gives better packing, but may fail due to OOM (even though */ - /* the rectangles easily fit). @TODO a smarter approach would be to only */ - /* quantize once we've hit OOM, then we could get rid of this parameter. */ - context->align = 1; - else { - /* if it's not ok to run out of memory, then quantize the widths */ - /* so that num_nodes is always enough nodes. */ - /* */ - /* I.e. num_nodes * align >= width */ - /* align >= width / num_nodes */ - /* align = ceil(width/num_nodes) */ - - context->align = (context->width + context->num_nodes-1) / context->num_nodes; - } -} - -STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) -{ - int i; -#ifndef STBRP_LARGE_RECTS - STBRP_ASSERT(width <= 0xffff && height <= 0xffff); -#endif - - for (i=0; i < num_nodes-1; ++i) - nodes[i].next = &nodes[i+1]; - nodes[i].next = NULL; - context->init_mode = STBRP__INIT_skyline; - context->heuristic = STBRP_HEURISTIC_Skyline_default; - context->free_head = &nodes[0]; - context->active_head = &context->extra[0]; - context->width = width; - context->height = height; - context->num_nodes = num_nodes; - stbrp_setup_allow_out_of_mem(context, 0); - - /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */ - context->extra[0].x = 0; - context->extra[0].y = 0; - context->extra[0].next = &context->extra[1]; - context->extra[1].x = (stbrp_coord) width; -#ifdef STBRP_LARGE_RECTS - context->extra[1].y = (1<<30); -#else - context->extra[1].y = 65535; -#endif - context->extra[1].next = NULL; -} - -/* find minimum y position if it starts at x1 */ -static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) -{ - stbrp_node *node = first; - int x1 = x0 + width; - int min_y, visited_width, waste_area; - - STBRP__NOTUSED(c); - - STBRP_ASSERT(first->x <= x0); - - #if 0 - /* skip in case we're past the node */ - while (node->next->x <= x0) - ++node; - #else - STBRP_ASSERT(node->next->x > x0); /* we ended up handling this in the caller for efficiency */ - #endif - - STBRP_ASSERT(node->x <= x0); - - min_y = 0; - waste_area = 0; - visited_width = 0; - while (node->x < x1) { - if (node->y > min_y) { - /* raise min_y higher. */ - /* we've accounted for all waste up to min_y, */ - /* but we'll now add more waste for everything we've visted */ - waste_area += visited_width * (node->y - min_y); - min_y = node->y; - /* the first time through, visited_width might be reduced */ - if (node->x < x0) - visited_width += node->next->x - x0; - else - visited_width += node->next->x - node->x; - } else { - /* add waste area */ - int under_width = node->next->x - node->x; - if (under_width + visited_width > width) - under_width = width - visited_width; - waste_area += under_width * (min_y - node->y); - visited_width += under_width; - } - node = node->next; - } - - *pwaste = waste_area; - return min_y; -} - -typedef struct -{ - int x,y; - stbrp_node **prev_link; -} stbrp__findresult; - -static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) -{ - int best_waste = (1<<30), best_x, best_y = (1 << 30); - stbrp__findresult fr; - stbrp_node **prev, *node, *tail, **best = NULL; - - /* align to multiple of c->align */ - width = (width + c->align - 1); - width -= width % c->align; - STBRP_ASSERT(width % c->align == 0); - - /* if it can't possibly fit, bail immediately */ - if (width > c->width || height > c->height) { - fr.prev_link = NULL; - fr.x = fr.y = 0; - return fr; - } - - node = c->active_head; - prev = &c->active_head; - while (node->x + width <= c->width) { - int y,waste; - y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); - if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { /* actually just want to test BL */ - /* bottom left */ - if (y < best_y) { - best_y = y; - best = prev; - } - } else { - /* best-fit */ - if (y + height <= c->height) { - /* can only use it if it first vertically */ - if (y < best_y || (y == best_y && waste < best_waste)) { - best_y = y; - best_waste = waste; - best = prev; - } - } - } - prev = &node->next; - node = node->next; - } - - best_x = (best == NULL) ? 0 : (*best)->x; - - /* if doing best-fit (BF), we also have to try aligning right edge to each node position */ - /* */ - /* e.g, if fitting */ - /* */ - /* ____________________ */ - /* |____________________| */ - /* */ - /* into */ - /* */ - /* | | */ - /* | ____________| */ - /* |____________| */ - /* */ - /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */ - /* */ - /* This makes BF take about 2x the time */ - - if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { - tail = c->active_head; - node = c->active_head; - prev = &c->active_head; - /* find first node that's admissible */ - while (tail->x < width) - tail = tail->next; - while (tail) { - int xpos = tail->x - width; - int y,waste; - STBRP_ASSERT(xpos >= 0); - /* find the left position that matches this */ - while (node->next->x <= xpos) { - prev = &node->next; - node = node->next; - } - STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); - y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); - if (y + height <= c->height) { - if (y <= best_y) { - if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { - best_x = xpos; - STBRP_ASSERT(y <= best_y); - best_y = y; - best_waste = waste; - best = prev; - } - } - } - tail = tail->next; - } - } - - fr.prev_link = best; - fr.x = best_x; - fr.y = best_y; - return fr; -} - -static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) -{ - /* find best position according to heuristic */ - stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); - stbrp_node *node, *cur; - - /* bail if: */ - /* 1. it failed */ - /* 2. the best node doesn't fit (we don't always check this) */ - /* 3. we're out of memory */ - if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { - res.prev_link = NULL; - return res; - } - - /* on success, create new node */ - node = context->free_head; - node->x = (stbrp_coord) res.x; - node->y = (stbrp_coord) (res.y + height); - - context->free_head = node->next; - - /* insert the new node into the right starting point, and */ - /* let 'cur' point to the remaining nodes needing to be */ - /* stiched back in */ - - cur = *res.prev_link; - if (cur->x < res.x) { - /* preserve the existing one, so start testing with the next one */ - stbrp_node *next = cur->next; - cur->next = node; - cur = next; - } else { - *res.prev_link = node; - } - - /* from here, traverse cur and free the nodes, until we get to one */ - /* that shouldn't be freed */ - while (cur->next && cur->next->x <= res.x + width) { - stbrp_node *next = cur->next; - /* move the current node to the free list */ - cur->next = context->free_head; - context->free_head = cur; - cur = next; - } - - /* stitch the list back in */ - node->next = cur; - - if (cur->x < res.x + width) - cur->x = (stbrp_coord) (res.x + width); - -#ifdef _DEBUG - cur = context->active_head; - while (cur->x < context->width) { - STBRP_ASSERT(cur->x < cur->next->x); - cur = cur->next; - } - STBRP_ASSERT(cur->next == NULL); - - { - int count=0; - cur = context->active_head; - while (cur) { - cur = cur->next; - ++count; - } - cur = context->free_head; - while (cur) { - cur = cur->next; - ++count; - } - STBRP_ASSERT(count == context->num_nodes+2); - } -#endif - - return res; -} - -static int rect_height_compare(const void *a, const void *b) -{ - const stbrp_rect *p = (const stbrp_rect *) a; - const stbrp_rect *q = (const stbrp_rect *) b; - if (p->h > q->h) - return -1; - if (p->h < q->h) - return 1; - return (p->w > q->w) ? -1 : (p->w < q->w); -} - -static int rect_original_order(const void *a, const void *b) -{ - const stbrp_rect *p = (const stbrp_rect *) a; - const stbrp_rect *q = (const stbrp_rect *) b; - return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); -} - -#ifdef STBRP_LARGE_RECTS -#define STBRP__MAXVAL 0xffffffff -#else -#define STBRP__MAXVAL 0xffff -#endif - -STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) -{ - int i, all_rects_packed = 1; - - /* we use the 'was_packed' field internally to allow sorting/unsorting */ - for (i=0; i < num_rects; ++i) { - rects[i].was_packed = i; - } - - /* sort according to heuristic */ - STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); - - for (i=0; i < num_rects; ++i) { - if (rects[i].w == 0 || rects[i].h == 0) { - rects[i].x = rects[i].y = 0; /* empty rect needs no space */ - } else { - stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); - if (fr.prev_link) { - rects[i].x = (stbrp_coord) fr.x; - rects[i].y = (stbrp_coord) fr.y; - } else { - rects[i].x = rects[i].y = STBRP__MAXVAL; - } - } - } - - /* unsort */ - STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); - - /* set was_packed flags and all_rects_packed status */ - for (i=0; i < num_rects; ++i) { - rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); - if (!rects[i].was_packed) - all_rects_packed = 0; - } - - /* return the all_rects_packed status */ - return all_rects_packed; -} -#endif - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ - -/* stb_truetype.h - v1.24 - public domain */ -/* authored from 2009-2020 by Sean Barrett / RAD Game Tools */ -/* */ -/* ======================================================================= */ -/* */ -/* NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES */ -/* */ -/* This library does no range checking of the offsets found in the file, */ -/* meaning an attacker can use it to read arbitrary memory. */ -/* */ -/* ======================================================================= */ -/* */ -/* This library processes TrueType files: */ -/* parse files */ -/* extract glyph metrics */ -/* extract glyph shapes */ -/* render glyphs to one-channel bitmaps with antialiasing (box filter) */ -/* render glyphs to one-channel SDF bitmaps (signed-distance field/function) */ -/* */ -/* Todo: */ -/* non-MS cmaps */ -/* crashproof on bad data */ -/* hinting? (no longer patented) */ -/* cleartype-style AA? */ -/* optimize: use simple memory allocator for intermediates */ -/* optimize: build edge-list directly from curves */ -/* optimize: rasterize directly from curves? */ -/* */ -/* ADDITIONAL CONTRIBUTORS */ -/* */ -/* Mikko Mononen: compound shape support, more cmap formats */ -/* Tor Andersson: kerning, subpixel rendering */ -/* Dougall Johnson: OpenType / Type 2 font handling */ -/* Daniel Ribeiro Maciel: basic GPOS-based kerning */ -/* */ -/* Misc other: */ -/* Ryan Gordon */ -/* Simon Glass */ -/* github:IntellectualKitty */ -/* Imanol Celaya */ -/* Daniel Ribeiro Maciel */ -/* */ -/* Bug/warning reports/fixes: */ -/* "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe */ -/* Cass Everitt Martins Mozeiko github:aloucks */ -/* stoiko (Haemimont Games) Cap Petschulat github:oyvindjam */ -/* Brian Hook Omar Cornut github:vassvik */ -/* Walter van Niftrik Ryan Griege */ -/* David Gow Peter LaValle */ -/* David Given Sergey Popov */ -/* Ivan-Assen Ivanov Giumo X. Clanjor */ -/* Anthony Pesch Higor Euripedes */ -/* Johan Duparc Thomas Fields */ -/* Hou Qiming Derek Vinyard */ -/* Rob Loach Cort Stratton */ -/* Kenney Phillis Jr. Brian Costabile */ -/* Ken Voskuil (kaesve) */ -/* */ -/* VERSION HISTORY */ -/* */ -/* 1.24 (2020-02-05) fix warning */ -/* 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) */ -/* 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined */ -/* 1.21 (2019-02-25) fix warning */ -/* 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() */ -/* 1.19 (2018-02-11) GPOS kerning, STBTT_fmod */ -/* 1.18 (2018-01-29) add missing function */ -/* 1.17 (2017-07-23) make more arguments const; doc fix */ -/* 1.16 (2017-07-12) SDF support */ -/* 1.15 (2017-03-03) make more arguments const */ -/* 1.14 (2017-01-16) num-fonts-in-TTC function */ -/* 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts */ -/* 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual */ -/* 1.11 (2016-04-02) fix unused-variable warning */ -/* 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef */ -/* 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly */ -/* 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges */ -/* 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; */ -/* variant PackFontRanges to pack and render in separate phases; */ -/* fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); */ -/* fixed an assert() bug in the new rasterizer */ -/* replace assert() with STBTT_assert() in new rasterizer */ -/* */ -/* Full history can be found at the end of this file. */ -/* */ -/* LICENSE */ -/* */ -/* See end of file for license information. */ -/* */ -/* USAGE */ -/* */ -/* Include this file in whatever places need to refer to it. In ONE C/C++ */ -/* file, write: */ -/* #define STB_TRUETYPE_IMPLEMENTATION */ -/* before the #include of this file. This expands out the actual */ -/* implementation into that C/C++ file. */ -/* */ -/* To make the implementation private to the file that generates the implementation, */ -/* #define STBTT_STATIC */ -/* */ -/* Simple 3D API (don't ship this, but it's fine for tools and quick start) */ -/* stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture */ -/* stbtt_GetBakedQuad() -- compute quad to draw for a given char */ -/* */ -/* Improved 3D API (more shippable): */ -/* #include "stb_rect_pack.h" -- optional, but you really want it */ -/* stbtt_PackBegin() */ -/* stbtt_PackSetOversampling() -- for improved quality on small fonts */ -/* stbtt_PackFontRanges() -- pack and renders */ -/* stbtt_PackEnd() */ -/* stbtt_GetPackedQuad() */ -/* */ -/* "Load" a font file from a memory buffer (you have to keep the buffer loaded) */ -/* stbtt_InitFont() */ -/* stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections */ -/* stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections */ -/* */ -/* Render a unicode codepoint to a bitmap */ -/* stbtt_GetCodepointBitmap() -- allocates and returns a bitmap */ -/* stbtt_MakeCodepointBitmap() -- renders into bitmap you provide */ -/* stbtt_GetCodepointBitmapBox() -- how big the bitmap must be */ -/* */ -/* Character advance/positioning */ -/* stbtt_GetCodepointHMetrics() */ -/* stbtt_GetFontVMetrics() */ -/* stbtt_GetFontVMetricsOS2() */ -/* stbtt_GetCodepointKernAdvance() */ -/* */ -/* Starting with version 1.06, the rasterizer was replaced with a new, */ -/* faster and generally-more-precise rasterizer. The new rasterizer more */ -/* accurately measures pixel coverage for anti-aliasing, except in the case */ -/* where multiple shapes overlap, in which case it overestimates the AA pixel */ -/* coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If */ -/* this turns out to be a problem, you can re-enable the old rasterizer with */ -/* #define STBTT_RASTERIZER_VERSION 1 */ -/* which will incur about a 15% speed hit. */ -/* */ -/* ADDITIONAL DOCUMENTATION */ -/* */ -/* Immediately after this block comment are a series of sample programs. */ -/* */ -/* After the sample programs is the "header file" section. This section */ -/* includes documentation for each API function. */ -/* */ -/* Some important concepts to understand to use this library: */ -/* */ -/* Codepoint */ -/* Characters are defined by unicode codepoints, e.g. 65 is */ -/* uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is */ -/* the hiragana for "ma". */ -/* */ -/* Glyph */ -/* A visual character shape (every codepoint is rendered as */ -/* some glyph) */ -/* */ -/* Glyph index */ -/* A font-specific integer ID representing a glyph */ -/* */ -/* Baseline */ -/* Glyph shapes are defined relative to a baseline, which is the */ -/* bottom of uppercase characters. Characters extend both above */ -/* and below the baseline. */ -/* */ -/* Current Point */ -/* As you draw text to the screen, you keep track of a "current point" */ -/* which is the origin of each character. The current point's vertical */ -/* position is the baseline. Even "baked fonts" use this model. */ -/* */ -/* Vertical Font Metrics */ -/* The vertical qualities of the font, used to vertically position */ -/* and space the characters. See docs for stbtt_GetFontVMetrics. */ -/* */ -/* Font Size in Pixels or Points */ -/* The preferred interface for specifying font sizes in stb_truetype */ -/* is to specify how tall the font's vertical extent should be in pixels. */ -/* If that sounds good enough, skip the next paragraph. */ -/* */ -/* Most font APIs instead use "points", which are a common typographic */ -/* measurement for describing font size, defined as 72 points per inch. */ -/* stb_truetype provides a point API for compatibility. However, true */ -/* "per inch" conventions don't make much sense on computer displays */ -/* since different monitors have different number of pixels per */ -/* inch. For example, Windows traditionally uses a convention that */ -/* there are 96 pixels per inch, thus making 'inch' measurements have */ -/* nothing to do with inches, and thus effectively defining a point to */ -/* be 1.333 pixels. Additionally, the TrueType font data provides */ -/* an explicit scale factor to scale a given font's glyphs to points, */ -/* but the author has observed that this scale factor is often wrong */ -/* for non-commercial fonts, thus making fonts scaled in points */ -/* according to the TrueType spec incoherently sized in practice. */ -/* */ -/* DETAILED USAGE: */ -/* */ -/* Scale: */ -/* Select how high you want the font to be, in points or pixels. */ -/* Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute */ -/* a scale factor SF that will be used by all other functions. */ -/* */ -/* Baseline: */ -/* You need to select a y-coordinate that is the baseline of where */ -/* your text will appear. Call GetFontBoundingBox to get the baseline-relative */ -/* bounding box for all characters. SF*-y0 will be the distance in pixels */ -/* that the worst-case character could extend above the baseline, so if */ -/* you want the top edge of characters to appear at the top of the */ -/* screen where y=0, then you would set the baseline to SF*-y0. */ -/* */ -/* Current point: */ -/* Set the current point where the first character will appear. The */ -/* first character could extend left of the current point; this is font */ -/* dependent. You can either choose a current point that is the leftmost */ -/* point and hope, or add some padding, or check the bounding box or */ -/* left-side-bearing of the first character to be displayed and set */ -/* the current point based on that. */ -/* */ -/* Displaying a character: */ -/* Compute the bounding box of the character. It will contain signed values */ -/* relative to . I.e. if it returns x0,y0,x1,y1, */ -/* then the character should be displayed in the rectangle from */ -/* to = 32 && *text < 128) { - stbtt_aligned_quad q; - stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);/* 1=opengl & d3d10+,0=d3d9 */ - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); - } - ++text; - } - glEnd(); -} -#endif -/* */ -/* */ -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* Complete program (this compiles): get a single bitmap, print as ASCII art */ -/* */ -#if 0 -#include -#define STB_TRUETYPE_IMPLEMENTATION /* force following include to generate implementation */ -#include "stb_truetype.h" - -char ttf_buffer[1<<25]; - -int main(int argc, char **argv) -{ - stbtt_fontinfo font; - unsigned char *bitmap; - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); - - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); - - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); - putchar('\n'); - } - return 0; -} -#endif -/* */ -/* Output: */ -/* */ -/* .ii. */ -/* @@@@@@. */ -/* V@Mio@@o */ -/* :i. V@V */ -/* :oM@@M */ -/* :@@@MM@M */ -/* @@o o@M */ -/* :@@. M@M */ -/* @@@o@@@@ */ -/* :M@@V:@@. */ -/* */ -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* Complete program: print "Hello World!" banner, with bugs */ -/* */ -#if 0 -char buffer[24<<20]; -unsigned char screen[20][79]; - -int main(int arg, char **argv) -{ - stbtt_fontinfo font; - int i,j,ascent,baseline,ch=0; - float scale, xpos=2; /* leave a little padding in case the character extends left */ - char *text = "Heljo World!"; /* intentionally misspelled to show 'lj' brokenness */ - - fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); - stbtt_InitFont(&font, buffer, 0); - - scale = stbtt_ScaleForPixelHeight(&font, 15); - stbtt_GetFontVMetrics(&font, &ascent,0,0); - baseline = (int) (ascent*scale); - - while (text[ch]) { - int advance,lsb,x0,y0,x1,y1; - float x_shift = xpos - (float) floor(xpos); - stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); - stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); - stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); - /* note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong */ - /* because this API is really for baking character bitmaps into textures. if you want to render */ - /* a sequence of characters, you really need to render each bitmap to a temp buffer, then */ - /* "alpha blend" that into the working buffer */ - xpos += (advance * scale); - if (text[ch+1]) - xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); - ++ch; - } - - for (j=0; j < 20; ++j) { - for (i=0; i < 78; ++i) - putchar(" .:ioVM@"[screen[j][i]>>5]); - putchar('\n'); - } - - return 0; -} -#endif - - -/* //////////////////////////////////////////////////////////////////////////// */ -/* //////////////////////////////////////////////////////////////////////////// */ -/* // */ -/* // INTEGRATION WITH YOUR CODEBASE */ -/* // */ -/* // The following sections allow you to supply alternate definitions */ -/* // of C library functions used by stb_truetype, e.g. if you don't */ -/* // link with the C runtime library. */ - -#ifdef STB_TRUETYPE_IMPLEMENTATION - /* #define your own (u)stbtt_int8/16/32 before including to override this */ - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif - - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - - /* e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h */ - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif - - #ifndef STBTT_sqrt - #include - #define STBTT_sqrt(x) sqrt(x) - #define STBTT_pow(x,y) pow(x,y) - #endif - - #ifndef STBTT_fmod - #include - #define STBTT_fmod(x,y) fmod(x,y) - #endif - - #ifndef STBTT_cos - #include - #define STBTT_cos(x) cos(x) - #define STBTT_acos(x) acos(x) - #endif - - #ifndef STBTT_fabs - #include - #define STBTT_fabs(x) fabs(x) - #endif - - /* #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h */ - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif - - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif - - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif - - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif -#endif - -/* ///////////////////////////////////////////////////////////////////////////// */ -/* ///////////////////////////////////////////////////////////////////////////// */ -/* // */ -/* // INTERFACE */ -/* // */ -/* // */ - -#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ -#define __STB_INCLUDE_STB_TRUETYPE_H__ - -#ifdef STBTT_STATIC -#define STBTT_DEF static -#else -#define STBTT_DEF extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* private structure */ -typedef struct -{ - unsigned char *data; - int cursor; - int size; -} stbtt__buf; - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* TEXTURE BAKING API */ -/* */ -/* If you use this API, you only have to call two functions ever. */ -/* */ - -typedef struct -{ - unsigned short x0,y0,x1,y1; /* coordinates of bbox in bitmap */ - float xoff,yoff,xadvance; -} stbtt_bakedchar; - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, /* font location (use offset=0 for plain .ttf) */ - float pixel_height, /* height of font in pixels */ - unsigned char *pixels, int pw, int ph, /* bitmap to be filled in */ - int first_char, int num_chars, /* characters to bake */ - stbtt_bakedchar *chardata); /* you allocate this, it's num_chars long */ -/* if return is positive, the first unused row of the bitmap */ -/* if return is negative, returns the negative of the number of characters that fit */ -/* if return is 0, no characters fit and no rows were used */ -/* This uses a very crappy packing. */ - -typedef struct -{ - float x0,y0,s0,t0; /* top-left */ - float x1,y1,s1,t1; /* bottom-right */ -} stbtt_aligned_quad; - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, /* same data as above */ - int char_index, /* character to display */ - float *xpos, float *ypos, /* pointers to current position in screen pixel space */ - stbtt_aligned_quad *q, /* output: quad to draw */ - int opengl_fillrule); /* true if opengl fill rule; false if DX9 or earlier */ -/* Call GetBakedQuad with char_index = 'character - first_char', and it */ -/* creates the quad you need to draw and advances the current position. */ -/* */ -/* The coordinate system used assumes y increases downwards. */ -/* */ -/* Characters will extend both above and below the current position; */ -/* see discussion of "BASELINE" above. */ -/* */ -/* It's inefficient; you might want to c&p it and optimize it. */ - -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); -/* Query the font vertical metrics without having to create a font first. */ - - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* NEW TEXTURE BAKING API */ -/* */ -/* This provides options for packing multiple fonts into one atlas, not */ -/* perfectly but better than nothing. */ - -typedef struct -{ - unsigned short x0,y0,x1,y1; /* coordinates of bbox in bitmap */ - float xoff,yoff,xadvance; - float xoff2,yoff2; -} stbtt_packedchar; - -typedef struct stbtt_pack_context stbtt_pack_context; -typedef struct stbtt_fontinfo stbtt_fontinfo; -#ifndef STB_RECT_PACK_VERSION -typedef struct stbrp_rect stbrp_rect; -#endif - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); -/* Initializes a packing context stored in the passed-in stbtt_pack_context. */ -/* Future calls using this context will pack characters into the bitmap passed */ -/* in here: a 1-channel bitmap that is width * height. stride_in_bytes is */ -/* the distance from one row to the next (or 0 to mean they are packed tightly */ -/* together). "padding" is the amount of padding to leave between each */ -/* character (normally you want '1' for bitmaps you'll use as textures with */ -/* bilinear filtering). */ -/* */ -/* Returns 0 on failure, 1 on success. */ - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); -/* Cleans up the packing context and frees all memory. */ - -#define STBTT_POINT_SIZE(x) (-(x)) - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); -/* Creates character bitmaps from the font_index'th font found in fontdata (use */ -/* font_index=0 if you don't know what that is). It creates num_chars_in_range */ -/* bitmaps for characters with unicode values starting at first_unicode_char_in_range */ -/* and increasing. Data for how to render them is stored in chardata_for_range; */ -/* pass these to stbtt_GetPackedQuad to get back renderable quads. */ -/* */ -/* font_size is the full height of the character from ascender to descender, */ -/* as computed by stbtt_ScaleForPixelHeight. To use a point size as computed */ -/* by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() */ -/* and pass that result as 'font_size': */ -/* ..., 20 , ... // font max minus min y is 20 pixels tall */ -/* ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall */ - -typedef struct -{ - float font_size; - int first_unicode_codepoint_in_range; /* if non-zero, then the chars are continuous, and this is the first codepoint */ - int *array_of_unicode_codepoints; /* if non-zero, then this is an array of unicode codepoints */ - int num_chars; - stbtt_packedchar *chardata_for_range; /* output */ - unsigned char h_oversample, v_oversample; /* don't set these, they're used internally */ -} stbtt_pack_range; - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); -/* Creates character bitmaps from multiple ranges of characters stored in */ -/* ranges. This will usually create a better-packed bitmap than multiple */ -/* calls to stbtt_PackFontRange. Note that you can call this multiple */ -/* times within a single PackBegin/PackEnd. */ - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); -/* Oversampling a font increases the quality by allowing higher-quality subpixel */ -/* positioning, and is especially valuable at smaller text sizes. */ -/* */ -/* This function sets the amount of oversampling for all following calls to */ -/* stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given */ -/* pack context. The default (no oversampling) is achieved by h_oversample=1 */ -/* and v_oversample=1. The total number of pixels required is */ -/* h_oversample*v_oversample larger than the default; for example, 2x2 */ -/* oversampling requires 4x the storage of 1x1. For best results, render */ -/* oversampled textures with bilinear filtering. Look at the readme in */ -/* stb/tests/oversample for information about oversampled fonts */ -/* */ -/* To use with PackFontRangesGather etc., you must set it before calls */ -/* call to PackFontRangesGatherRects. */ - -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); -/* If skip != 0, this tells stb_truetype to skip any codepoints for which */ -/* there is no corresponding glyph. If skip=0, which is the default, then */ -/* codepoints without a glyph recived the font's "missing character" glyph, */ -/* typically an empty box by convention. */ - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, /* same data as above */ - int char_index, /* character to display */ - float *xpos, float *ypos, /* pointers to current position in screen pixel space */ - stbtt_aligned_quad *q, /* output: quad to draw */ - int align_to_integer); - -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -/* Calling these functions in sequence is roughly equivalent to calling */ -/* stbtt_PackFontRanges(). If you more control over the packing of multiple */ -/* fonts, or if you want to pack custom data into a font texture, take a look */ -/* at the source to of stbtt_PackFontRanges() and create a custom version */ -/* using these functions, e.g. call GatherRects multiple times, */ -/* building up a single array of rects, then call PackRects once, */ -/* then call RenderIntoRects repeatedly. This may result in a */ -/* better packing than calling PackFontRanges multiple times */ -/* (or it may not). */ - -/* this is an opaque structure that you shouldn't mess with which holds */ -/* all the context needed from PackBegin to PackEnd. */ -struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - int skip_missing; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; -}; - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* FONT LOADING */ -/* */ -/* */ - -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); -/* This function will determine the number of fonts in a font file. TrueType */ -/* collection (.ttc) files may contain multiple fonts, while TrueType font */ -/* (.ttf) files only contain one font. The number of fonts can be used for */ -/* indexing with the previous function where the index is between zero and one */ -/* less than the total fonts. If an error occurs, -1 is returned. */ - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); -/* Each .ttf/.ttc file may have more than one font. Each font has a sequential */ -/* index number starting from 0. Call this function to get the font offset for */ -/* a given index; it returns -1 if the index is out of range. A regular .ttf */ -/* file will only define one font and it always be at offset 0, so it will */ -/* return '0' for index 0, and -1 for all other indices. */ - -/* The following structure is defined publicly so you can declare one on */ -/* the stack or as a global or etc, but you should treat it as opaque. */ -struct stbtt_fontinfo -{ - void * userdata; - unsigned char * data; /* pointer to .ttf file */ - int fontstart; /* offset of start of font */ - - int numGlyphs; /* number of glyphs, needed for range checking */ - - int loca,head,glyf,hhea,hmtx,kern,gpos,svg; /* table locations as offset from start of .ttf */ - int index_map; /* a cmap mapping for our chosen character encoding */ - int indexToLocFormat; /* format needed to map from glyph index to glyph */ - - stbtt__buf cff; /* cff font data */ - stbtt__buf charstrings; /* the charstring index */ - stbtt__buf gsubrs; /* global charstring subroutines index */ - stbtt__buf subrs; /* private charstring subroutines index */ - stbtt__buf fontdicts; /* array of font dicts */ - stbtt__buf fdselect; /* map from glyph to fontdict */ -}; - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); -/* Given an offset into the file that defines a font, this function builds */ -/* the necessary cached info for the rest of the system. You must allocate */ -/* the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't */ -/* need to do anything special to free it, because the contents are pure */ -/* value data with no additional data structures. Returns 0 on failure. */ - - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* CHARACTER TO GLYPH-INDEX CONVERSIOn */ - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); -/* If you're going to perform multiple operations on the same character */ -/* and you want a speed-up, call this function with the character you're */ -/* going to process, then use glyph-based functions instead of the */ -/* codepoint-based functions. */ -/* Returns 0 if the character codepoint is not defined in the font. */ - - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* CHARACTER PROPERTIES */ -/* */ - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); -/* computes a scale factor to produce a font whose "height" is 'pixels' tall. */ -/* Height is measured as the distance from the highest ascender to the lowest */ -/* descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics */ -/* and computing: */ -/* scale = pixels / (ascent - descent) */ -/* so if you prefer to measure height by the ascent only, use a similar calculation. */ - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); -/* computes a scale factor to produce a font whose EM size is mapped to */ -/* 'pixels' tall. This is probably what traditional APIs compute, but */ -/* I'm not positive. */ - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); -/* ascent is the coordinate above the baseline the font extends; descent */ -/* is the coordinate below the baseline the font extends (i.e. it is typically negative) */ -/* lineGap is the spacing between one row's descent and the next row's ascent... */ -/* so you should advance the vertical position by "*ascent - *descent + *lineGap" */ -/* these are expressed in unscaled coordinates, so you must multiply by */ -/* the scale factor for a given size */ - -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); -/* analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 */ -/* table (specific to MS/Windows TTF files). */ -/* */ -/* Returns 1 on success (table present), 0 on failure. */ - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); -/* the bounding box around all possible characters */ - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); -/* leftSideBearing is the offset from the current horizontal position to the left edge of the character */ -/* advanceWidth is the offset from the current horizontal position to the next horizontal position */ -/* these are expressed in unscaled coordinates */ - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); -/* an additional amount to add to the 'advance' value between ch1 and ch2 */ - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); -/* Gets the bounding box of the visible part of the glyph, in unscaled coordinates */ - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); -/* as above, but takes one or more glyph indices for greater efficiency */ - -typedef struct stbtt_kerningentry -{ - int glyph1; /* use stbtt_FindGlyphIndex */ - int glyph2; - int advance; -} stbtt_kerningentry; - -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); -/* Retrieves a complete list of all of the kerning pairs provided by the font */ -/* stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. */ -/* The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) */ - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* GLYPH SHAPES (you probably don't need these, but they have to go before */ -/* the bitmaps for C declaration-order reasons) */ -/* */ - -#ifndef STBTT_vmove /* you can predefine these to use different values (but why?) */ - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve, - STBTT_vcubic - }; -#endif - -#ifndef stbtt_vertex /* you can predefine this to use different values */ - /* (we share this with other code at RAD) */ - #define stbtt_vertex_type short /* can't use stbtt_int16 because that's not visible in the header file */ - typedef struct - { - stbtt_vertex_type x,y,cx,cy,cx1,cy1; - unsigned char type,padding; - } stbtt_vertex; -#endif - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); -/* returns non-zero if nothing is drawn for this glyph */ - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); -/* returns # of vertices and fills *vertices with the pointer to them */ -/* these are expressed in "unscaled" coordinates */ -/* */ -/* The shape is a series of contours. Each one starts with */ -/* a STBTT_moveto, then consists of a series of mixed */ -/* STBTT_lineto and STBTT_curveto segments. A lineto */ -/* draws a line from previous endpoint to its x,y; a curveto */ -/* draws a quadratic bezier from previous endpoint to */ -/* its x,y, using cx,cy as the bezier control point. */ - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); -/* frees the data allocated above */ - -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); -/* fills svg with the character's SVG data. */ -/* returns data size or 0 if SVG not found. */ - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* BITMAP RENDERING */ -/* */ - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); -/* frees the bitmap allocated below */ - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -/* allocates a large-enough single-channel 8bpp bitmap and renders the */ -/* specified character/glyph at the specified scale into it, with */ -/* antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). */ -/* *width & *height are filled out with the width & height of the bitmap, */ -/* which is stored left-to-right, top-to-bottom. */ -/* */ -/* xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap */ - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -/* the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel */ -/* shift for the character */ - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); -/* the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap */ -/* in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap */ -/* is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the */ -/* width and height and positioning info for it first. */ - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); -/* same as stbtt_MakeCodepointBitmap, but you can specify a subpixel */ -/* shift for the character */ - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); -/* same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering */ -/* is performed (see stbtt_PackSetOversampling) */ - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -/* get the bbox of the bitmap centered around the glyph origin; so the */ -/* bitmap width is ix1-ix0, height is iy1-iy0, and location to place */ -/* the bitmap top left is (leftSideBearing*scale,iy0). */ -/* (Note that the bitmap uses y-increases-down, but the shape uses */ -/* y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) */ - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); -/* same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel */ -/* shift for the character */ - -/* the following functions are equivalent to the above functions, but operate */ -/* on glyph indices instead of Unicode codepoints (for efficiency) */ -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); - - -/* @TODO: don't expose this structure */ -typedef struct -{ - int w,h,stride; - unsigned char *pixels; -} stbtt__bitmap; - -/* rasterize a shape with quadratic beziers into a bitmap */ -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, /* 1-channel bitmap to draw into */ - float flatness_in_pixels, /* allowable error of curve in pixels */ - stbtt_vertex *vertices, /* array of vertices defining shape */ - int num_verts, /* number of vertices in above array */ - float scale_x, float scale_y, /* scale applied to input vertices */ - float shift_x, float shift_y, /* translation applied to input vertices */ - int x_off, int y_off, /* another translation applied to input */ - int invert, /* if non-zero, vertically flip shape */ - void *userdata); /* context for to STBTT_MALLOC */ - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* Signed Distance Function (or Field) rendering */ - -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); -/* frees the SDF bitmap allocated below */ - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -/* These functions compute a discretized SDF field for a single character, suitable for storing */ -/* in a single-channel texture, sampling with bilinear filtering, and testing against */ -/* larger than some threshold to produce scalable fonts. */ -/* info -- the font */ -/* scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap */ -/* glyph/codepoint -- the character to generate the SDF for */ -/* padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), */ -/* which allows effects like bit outlines */ -/* onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) */ -/* pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) */ -/* if positive, > onedge_value is inside; if negative, < onedge_value is inside */ -/* width,height -- output height & width of the SDF bitmap (including padding) */ -/* xoff,yoff -- output origin of the character */ -/* return value -- a 2D array of bytes 0..255, width*height in size */ -/* */ -/* pixel_dist_scale & onedge_value are a scale & bias that allows you to make */ -/* optimal use of the limited 0..255 for your application, trading off precision */ -/* and special effects. SDF values outside the range 0..255 are clamped to 0..255. */ -/* */ -/* Example: */ -/* scale = stbtt_ScaleForPixelHeight(22) */ -/* padding = 5 */ -/* onedge_value = 180 */ -/* pixel_dist_scale = 180/5.0 = 36.0 */ -/* */ -/* This will create an SDF bitmap in which the character is about 22 pixels */ -/* high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled */ -/* shape, sample the SDF at each pixel and fill the pixel if the SDF value */ -/* is greater than or equal to 180/255. (You'll actually want to antialias, */ -/* which is beyond the scope of this example.) Additionally, you can compute */ -/* offset outlines (e.g. to stroke the character border inside & outside, */ -/* or only outside). For example, to fill outside the character up to 3 SDF */ -/* pixels, you would compare against (180-36.0*3)/255 = 72/255. The above */ -/* choice of variables maps a range from 5 pixels outside the shape to */ -/* 2 pixels inside the shape to 0..255; this is intended primarily for apply */ -/* outside effects only (the interior range is needed to allow proper */ -/* antialiasing of the font at *smaller* sizes) */ -/* */ -/* The function computes the SDF analytically at each SDF pixel, not by e.g. */ -/* building a higher-res bitmap and approximating it. In theory the quality */ -/* should be as high as possible for an SDF of this size & representation, but */ -/* unclear if this is true in practice (perhaps building a higher-res bitmap */ -/* and computing from that can allow drop-out prevention). */ -/* */ -/* The algorithm has not been optimized at all, so expect it to be slow */ -/* if computing lots of characters or very large sizes. */ - - - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* Finding the right font... */ -/* */ -/* You should really just solve this offline, keep your own tables */ -/* of what font is what, and don't try to get it out of the .ttf file. */ -/* That's because getting it out of the .ttf file is really hard, because */ -/* the names in the file can appear in many possible encodings, in many */ -/* possible languages, and e.g. if you need a case-insensitive comparison, */ -/* the details of that depend on the encoding & language in a complex way */ -/* (actually underspecified in truetype, but also gigantic). */ -/* */ -/* But you can use the provided functions in two possible ways: */ -/* stbtt_FindMatchingFont() will use *case-sensitive* comparisons on */ -/* unicode-encoded names to try to find the font you want; */ -/* you can run this before calling stbtt_InitFont() */ -/* */ -/* stbtt_GetFontNameString() lets you get any of the various strings */ -/* from the file yourself and do your own comparisons on them. */ -/* You have to have called stbtt_InitFont() first. */ - - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); -/* returns the offset (not index) of the font that matches, or -1 if none */ -/* if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". */ -/* if you use any other flag, use a font name like "Arial"; this checks */ -/* the 'macStyle' header field; i don't know if fonts set this consistently */ -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 /* <= not same as 0, this makes us check the bitfield is 0 */ - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); -/* returns 1/0 whether the first string interpreted as utf8 is identical to */ -/* the second string interpreted as big-endian utf16... useful for strings from next func */ - -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); -/* returns the string (which may be big-endian double byte, e.g. for unicode) */ -/* and puts the length in bytes in *length. */ -/* */ -/* some of the values for the IDs are below; for more see the truetype spec: */ -/* http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html */ -/* http://www.microsoft.com/typography/otspec/name.htm */ - -enum { /* platformID */ - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { /* encodingID for STBTT_PLATFORM_ID_UNICODE */ - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 -}; - -enum { /* encodingID for STBTT_PLATFORM_ID_MICROSOFT */ - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10 -}; - -enum { /* encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes */ - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 -}; - -enum { /* languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... */ - /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */ - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D -}; - -enum { /* languageID for STBTT_PLATFORM_ID_MAC */ - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 -}; - -#ifdef __cplusplus -} -#endif - -#endif /* __STB_INCLUDE_STB_TRUETYPE_H__ */ - -/* ///////////////////////////////////////////////////////////////////////////// */ -/* ///////////////////////////////////////////////////////////////////////////// */ -/* // */ -/* // IMPLEMENTATION */ -/* // */ -/* // */ - -#ifdef STB_TRUETYPE_IMPLEMENTATION - -#ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 -#endif - -#if STBTT_MAX_OVERSAMPLE > 255 -#error "STBTT_MAX_OVERSAMPLE cannot be > 255" -#endif - -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; - -#ifndef STBTT_RASTERIZER_VERSION -#define STBTT_RASTERIZER_VERSION 2 -#endif - -#ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) -#else -#define STBTT__NOTUSED(v) (void)sizeof(v) -#endif - -/* //////////////////////////////////////////////////////////////////////// */ -/* */ -/* stbtt__buf helpers to parse data from file */ -/* */ - -static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor++]; -} - -static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor]; -} - -static void stbtt__buf_seek(stbtt__buf *b, int o) -{ - STBTT_assert(!(o > b->size || o < 0)); - b->cursor = (o > b->size || o < 0) ? b->size : o; -} - -static void stbtt__buf_skip(stbtt__buf *b, int o) -{ - stbtt__buf_seek(b, b->cursor + o); -} - -static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) -{ - stbtt_uint32 v = 0; - int i; - STBTT_assert(n >= 1 && n <= 4); - for (i = 0; i < n; i++) - v = (v << 8) | stbtt__buf_get8(b); - return v; -} - -static stbtt__buf stbtt__new_buf(const void *p, size_t size) -{ - stbtt__buf r; - STBTT_assert(size < 0x40000000); - r.data = (stbtt_uint8*) p; - r.size = (int) size; - r.cursor = 0; - return r; -} - -#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) -#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) - -static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) -{ - stbtt__buf r = stbtt__new_buf(NULL, 0); - if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; - r.data = b->data + o; - r.size = s; - return r; -} - -static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) -{ - int count, start, offsize; - start = b->cursor; - count = stbtt__buf_get16(b); - if (count) { - offsize = stbtt__buf_get8(b); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(b, offsize * count); - stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); - } - return stbtt__buf_range(b, start, b->cursor - start); -} - -static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) -{ - int b0 = stbtt__buf_get8(b); - if (b0 >= 32 && b0 <= 246) return b0 - 139; - else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; - else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; - else if (b0 == 28) return stbtt__buf_get16(b); - else if (b0 == 29) return stbtt__buf_get32(b); - STBTT_assert(0); - return 0; -} - -static void stbtt__cff_skip_operand(stbtt__buf *b) { - int v, b0 = stbtt__buf_peek8(b); - STBTT_assert(b0 >= 28); - if (b0 == 30) { - stbtt__buf_skip(b, 1); - while (b->cursor < b->size) { - v = stbtt__buf_get8(b); - if ((v & 0xF) == 0xF || (v >> 4) == 0xF) - break; - } - } else { - stbtt__cff_int(b); - } -} - -static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) -{ - stbtt__buf_seek(b, 0); - while (b->cursor < b->size) { - int start = b->cursor, end, op; - while (stbtt__buf_peek8(b) >= 28) - stbtt__cff_skip_operand(b); - end = b->cursor; - op = stbtt__buf_get8(b); - if (op == 12) op = stbtt__buf_get8(b) | 0x100; - if (op == key) return stbtt__buf_range(b, start, end-start); - } - return stbtt__buf_range(b, 0, 0); -} - -static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) -{ - int i; - stbtt__buf operands = stbtt__dict_get(b, key); - for (i = 0; i < outcount && operands.cursor < operands.size; i++) - out[i] = stbtt__cff_int(&operands); -} - -static int stbtt__cff_index_count(stbtt__buf *b) -{ - stbtt__buf_seek(b, 0); - return stbtt__buf_get16(b); -} - -static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) -{ - int count, offsize, start, end; - stbtt__buf_seek(&b, 0); - count = stbtt__buf_get16(&b); - offsize = stbtt__buf_get8(&b); - STBTT_assert(i >= 0 && i < count); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(&b, i*offsize); - start = stbtt__buf_get(&b, offsize); - end = stbtt__buf_get(&b, offsize); - return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); -} - -/* //////////////////////////////////////////////////////////////////////// */ -/* */ -/* accessors to parse data from file */ -/* */ - -/* on platforms that don't allow misaligned reads, if we want to allow */ -/* truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE */ - -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) - -static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } -static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) - -static int stbtt__isfont(stbtt_uint8 *font) -{ - /* check the version number */ - if (stbtt_tag4(font, '1',0,0,0)) return 1; /* TrueType 1 */ - if (stbtt_tag(font, "typ1")) return 1; /* TrueType with type 1 font -- we don't support this! */ - if (stbtt_tag(font, "OTTO")) return 1; /* OpenType with CFF */ - if (stbtt_tag4(font, 0,1,0,0)) return 1; /* OpenType 1.0 */ - if (stbtt_tag(font, "true")) return 1; /* Apple specification for TrueType fonts */ - return 0; -} - -/* @OPTIMIZE: binary search */ -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; -} - -static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) -{ - /* if it's just a font, there's only one valid index */ - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; - - /* check if it's a TTC */ - if (stbtt_tag(font_collection, "ttcf")) { - /* version 1? */ - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*4); - } - } - return -1; -} - -static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) -{ - /* if it's just a font, there's only one valid font */ - if (stbtt__isfont(font_collection)) - return 1; - - /* check if it's a TTC */ - if (stbtt_tag(font_collection, "ttcf")) { - /* version 1? */ - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - return ttLONG(font_collection+8); - } - } - return 0; -} - -static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) -{ - stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; - stbtt__buf pdict; - stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); - if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); - pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); - stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); - if (!subrsoff) return stbtt__new_buf(NULL, 0); - stbtt__buf_seek(&cff, private_loc[1]+subrsoff); - return stbtt__cff_get_index(&cff); -} - -/* since most people won't use this, find this table the first time it's needed */ -static int stbtt__get_svg(stbtt_fontinfo *info) -{ - stbtt_uint32 t; - if (info->svg < 0) { - t = stbtt__find_table(info->data, info->fontstart, "SVG "); - if (t) { - stbtt_uint32 offset = ttULONG(info->data + t + 2); - info->svg = t + offset; - } else { - info->svg = 0; - } - } - return info->svg; -} - -static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) -{ - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; - - info->data = data; - info->fontstart = fontstart; - info->cff = stbtt__new_buf(NULL, 0); - - cmap = stbtt__find_table(data, fontstart, "cmap"); /* required */ - info->loca = stbtt__find_table(data, fontstart, "loca"); /* required */ - info->head = stbtt__find_table(data, fontstart, "head"); /* required */ - info->glyf = stbtt__find_table(data, fontstart, "glyf"); /* required */ - info->hhea = stbtt__find_table(data, fontstart, "hhea"); /* required */ - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); /* required */ - info->kern = stbtt__find_table(data, fontstart, "kern"); /* not required */ - info->gpos = stbtt__find_table(data, fontstart, "GPOS"); /* not required */ - - if (!cmap || !info->head || !info->hhea || !info->hmtx) - return 0; - if (info->glyf) { - /* required for truetype */ - if (!info->loca) return 0; - } else { - /* initialization for CFF / Type2 fonts (OTF) */ - stbtt__buf b, topdict, topdictidx; - stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; - stbtt_uint32 cff; - - cff = stbtt__find_table(data, fontstart, "CFF "); - if (!cff) return 0; - - info->fontdicts = stbtt__new_buf(NULL, 0); - info->fdselect = stbtt__new_buf(NULL, 0); - - /* @TODO this should use size from table (not 512MB) */ - info->cff = stbtt__new_buf(data+cff, 512*1024*1024); - b = info->cff; - - /* read the header */ - stbtt__buf_skip(&b, 2); - stbtt__buf_seek(&b, stbtt__buf_get8(&b)); /* hdrsize */ - - /* @TODO the name INDEX could list multiple fonts, */ - /* but we just use the first one. */ - stbtt__cff_get_index(&b); /* name INDEX */ - topdictidx = stbtt__cff_get_index(&b); - topdict = stbtt__cff_index_get(topdictidx, 0); - stbtt__cff_get_index(&b); /* string INDEX */ - info->gsubrs = stbtt__cff_get_index(&b); - - stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); - stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); - stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); - stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); - info->subrs = stbtt__get_subrs(b, topdict); - - /* we only support Type 2 charstrings */ - if (cstype != 2) return 0; - if (charstrings == 0) return 0; - - if (fdarrayoff) { - /* looks like a CID font */ - if (!fdselectoff) return 0; - stbtt__buf_seek(&b, fdarrayoff); - info->fontdicts = stbtt__cff_get_index(&b); - info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); - } - - stbtt__buf_seek(&b, charstrings); - info->charstrings = stbtt__cff_get_index(&b); - } - - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - info->svg = -1; - - /* find a cmap encoding table we understand *now* to avoid searching */ - /* later. (todo: could make this installable) */ - /* the same regardless of glyph. */ - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - /* find an encoding we understand: */ - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - /* MS/Unicode */ - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - break; - case STBTT_PLATFORM_ID_UNICODE: - /* Mac/iOS has these */ - /* all the encodingIDs are unicode, so we don't bother to check it */ - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { /* apple byte encoding */ - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); /* @TODO: high-byte mapping for japanese/chinese/korean */ - return 0; - } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */ - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - - /* do a binary search of the segments */ - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - /* they lie from endCount .. endCount + segCount */ - /* but searchRange is the nearest power of two, so... */ - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - /* now decrement to bias correctly to find smallest */ - search -= 2; - while (entrySelector) { - stbtt_uint16 end; - searchRange >>= 1; - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - { - stbtt_uint16 offset, start; - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; - - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - stbtt_uint32 ngroups = ttULONG(data+index_map+12); - stbtt_int32 low,high; - low = 0; high = (stbtt_int32)ngroups; - /* Binary search the right group. */ - while (low < high) { - stbtt_int32 mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */ - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else /* format == 13 */ - return start_glyph; - } - } - return 0; /* not found */ - } - /* @TODO */ - STBTT_assert(0); - return 0; -} - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); -} - -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) -{ - v->type = type; - v->x = (stbtt_int16) x; - v->y = (stbtt_int16) y; - v->cx = (stbtt_int16) cx; - v->cy = (stbtt_int16) cy; -} - -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; - - STBTT_assert(!info->cff.size); - - if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */ - if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */ - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - - return g1==g2 ? -1 : g1; /* if length is 0, return -1 */ -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); - -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - if (info->cff.size) { - stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); - } else { - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - } - return 1; -} - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt_int16 numberOfContours; - int g; - if (info->cff.size) - return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; - g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 1; - numberOfContours = ttSHORT(info->data + g); - return numberOfContours == 0; -} - -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) -{ - if (start_off) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - return num_vertices; -} - -static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */ - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - /* in first pass, we load uninterpreted data into the allocated array */ - /* above, shifted to the end of the array so we won't overwrite it when */ - /* we create our final data starting from the front */ - - off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */ - - /* first load flags */ - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - /* now load x coordinates */ - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; /* ??? */ - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (stbtt_int16) x; - } - - /* now load y coordinates */ - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; /* ??? */ - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (stbtt_int16) y; - } - - /* now convert them to our format */ - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - /* now start the new one */ - start_off = !(flags & 1); - if (start_off) { - /* if we start off with an off-curve point, then when we need to find a point on the curve */ - /* where we can start, and we need to save some state for when we wraparound. */ - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - /* next point is also a curve point, so interpolate an on-point curve */ - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; - } else { - /* otherwise just use the next point as our start point */ - sx = (stbtt_int32) vertices[off+i+1].x; - sy = (stbtt_int32) vertices[off+i+1].y; - ++i; /* we're using point i+1 as the starting point, so skip it */ - } - } else { - sx = x; - sy = y; - } - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) { /* if it's a curve */ - if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */ - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours < 0) { - /* Compound shapes. */ - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { /* XY values */ - if (flags & 1) { /* shorts */ - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; - } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; - } - } - else { - /* @TODO handle matching point */ - STBTT_assert(0); - } - if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */ - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */ - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */ - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - /* Find transformation scales. */ - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - /* Get indexed glyph. */ - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - /* Transform vertices. */ - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - /* Append vertices. */ - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; - } - if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; - STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - /* More components ? */ - more = flags & (1<<5); - } - } else { - /* numberOfCounters == 0, do nothing */ - } - - *pvertices = vertices; - return num_vertices; -} - -typedef struct -{ - int bounds; - int started; - float first_x, first_y; - float x, y; - stbtt_int32 min_x, max_x, min_y, max_y; - - stbtt_vertex *pvertices; - int num_vertices; -} stbtt__csctx; - -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} - -static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) -{ - if (x > c->max_x || !c->started) c->max_x = x; - if (y > c->max_y || !c->started) c->max_y = y; - if (x < c->min_x || !c->started) c->min_x = x; - if (y < c->min_y || !c->started) c->min_y = y; - c->started = 1; -} - -static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) -{ - if (c->bounds) { - stbtt__track_vertex(c, x, y); - if (type == STBTT_vcubic) { - stbtt__track_vertex(c, cx, cy); - stbtt__track_vertex(c, cx1, cy1); - } - } else { - stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); - c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; - c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; - } - c->num_vertices++; -} - -static void stbtt__csctx_close_shape(stbtt__csctx *ctx) -{ - if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) -{ - stbtt__csctx_close_shape(ctx); - ctx->first_x = ctx->x = ctx->x + dx; - ctx->first_y = ctx->y = ctx->y + dy; - stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) -{ - ctx->x += dx; - ctx->y += dy; - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) -{ - float cx1 = ctx->x + dx1; - float cy1 = ctx->y + dy1; - float cx2 = cx1 + dx2; - float cy2 = cy1 + dy2; - ctx->x = cx2 + dx3; - ctx->y = cy2 + dy3; - stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); -} - -static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) -{ - int count = stbtt__cff_index_count(&idx); - int bias = 107; - if (count >= 33900) - bias = 32768; - else if (count >= 1240) - bias = 1131; - n += bias; - if (n < 0 || n >= count) - return stbtt__new_buf(NULL, 0); - return stbtt__cff_index_get(idx, n); -} - -static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt__buf fdselect = info->fdselect; - int nranges, start, end, v, fmt, fdselector = -1, i; - - stbtt__buf_seek(&fdselect, 0); - fmt = stbtt__buf_get8(&fdselect); - if (fmt == 0) { - /* untested */ - stbtt__buf_skip(&fdselect, glyph_index); - fdselector = stbtt__buf_get8(&fdselect); - } else if (fmt == 3) { - nranges = stbtt__buf_get16(&fdselect); - start = stbtt__buf_get16(&fdselect); - for (i = 0; i < nranges; i++) { - v = stbtt__buf_get8(&fdselect); - end = stbtt__buf_get16(&fdselect); - if (glyph_index >= start && glyph_index < end) { - fdselector = v; - break; - } - start = end; - } - } - if (fdselector == -1) stbtt__new_buf(NULL, 0); - return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); -} - -static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) -{ - int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; - int has_subrs = 0, clear_stack; - float s[48]; - stbtt__buf subr_stack[10], subrs = info->subrs, b; - float f; - -#define STBTT__CSERR(s) (0) - - /* this currently ignores the initial width value, which isn't needed if we have hmtx */ - b = stbtt__cff_index_get(info->charstrings, glyph_index); - while (b.cursor < b.size) { - i = 0; - clear_stack = 1; - b0 = stbtt__buf_get8(&b); - switch (b0) { - /* @TODO implement hinting */ - case 0x13: /* hintmask */ - case 0x14: /* cntrmask */ - if (in_header) - maskbits += (sp / 2); /* implicit "vstem" */ - in_header = 0; - stbtt__buf_skip(&b, (maskbits + 7) / 8); - break; - - case 0x01: /* hstem */ - case 0x03: /* vstem */ - case 0x12: /* hstemhm */ - case 0x17: /* vstemhm */ - maskbits += (sp / 2); - break; - - case 0x15: /* rmoveto */ - in_header = 0; - if (sp < 2) return STBTT__CSERR("rmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); - break; - case 0x04: /* vmoveto */ - in_header = 0; - if (sp < 1) return STBTT__CSERR("vmoveto stack"); - stbtt__csctx_rmove_to(c, 0, s[sp-1]); - break; - case 0x16: /* hmoveto */ - in_header = 0; - if (sp < 1) return STBTT__CSERR("hmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-1], 0); - break; - - case 0x05: /* rlineto */ - if (sp < 2) return STBTT__CSERR("rlineto stack"); - for (; i + 1 < sp; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - /* hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical */ - /* starting from a different place. */ - - case 0x07: /* vlineto */ - if (sp < 1) return STBTT__CSERR("vlineto stack"); - goto vlineto; - case 0x06: /* hlineto */ - if (sp < 1) return STBTT__CSERR("hlineto stack"); - for (;;) { - if (i >= sp) break; - stbtt__csctx_rline_to(c, s[i], 0); - i++; - vlineto: - if (i >= sp) break; - stbtt__csctx_rline_to(c, 0, s[i]); - i++; - } - break; - - case 0x1F: /* hvcurveto */ - if (sp < 4) return STBTT__CSERR("hvcurveto stack"); - goto hvcurveto; - case 0x1E: /* vhcurveto */ - if (sp < 4) return STBTT__CSERR("vhcurveto stack"); - for (;;) { - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); - i += 4; - hvcurveto: - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); - i += 4; - } - break; - - case 0x08: /* rrcurveto */ - if (sp < 6) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x18: /* rcurveline */ - if (sp < 8) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp - 2; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - case 0x19: /* rlinecurve */ - if (sp < 8) return STBTT__CSERR("rlinecurve stack"); - for (; i + 1 < sp - 6; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x1A: /* vvcurveto */ - case 0x1B: /* hhcurveto */ - if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); - f = 0.0; - if (sp & 1) { f = s[i]; i++; } - for (; i + 3 < sp; i += 4) { - if (b0 == 0x1B) - stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); - else - stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); - f = 0.0; - } - break; - - case 0x0A: /* callsubr */ - if (!has_subrs) { - if (info->fdselect.size) - subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); - has_subrs = 1; - } - /* fallthrough */ - case 0x1D: /* callgsubr */ - if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); - v = (int) s[--sp]; - if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); - subr_stack[subr_stack_height++] = b; - b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); - if (b.size == 0) return STBTT__CSERR("subr not found"); - b.cursor = 0; - clear_stack = 0; - break; - - case 0x0B: /* return */ - if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); - b = subr_stack[--subr_stack_height]; - clear_stack = 0; - break; - - case 0x0E: /* endchar */ - stbtt__csctx_close_shape(c); - return 1; - - case 0x0C: { /* two-byte escape */ - float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; - float dx, dy; - int b1 = stbtt__buf_get8(&b); - switch (b1) { - /* @TODO These "flex" implementations ignore the flex-depth and resolution, */ - /* and always draw beziers. */ - case 0x22: /* hflex */ - if (sp < 7) return STBTT__CSERR("hflex stack"); - dx1 = s[0]; - dx2 = s[1]; - dy2 = s[2]; - dx3 = s[3]; - dx4 = s[4]; - dx5 = s[5]; - dx6 = s[6]; - stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); - break; - - case 0x23: /* flex */ - if (sp < 13) return STBTT__CSERR("flex stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = s[10]; - dy6 = s[11]; - /* fd is s[12] */ - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - case 0x24: /* hflex1 */ - if (sp < 9) return STBTT__CSERR("hflex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dx4 = s[5]; - dx5 = s[6]; - dy5 = s[7]; - dx6 = s[8]; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); - break; - - case 0x25: /* flex1 */ - if (sp < 11) return STBTT__CSERR("flex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = dy6 = s[10]; - dx = dx1+dx2+dx3+dx4+dx5; - dy = dy1+dy2+dy3+dy4+dy5; - if (STBTT_fabs(dx) > STBTT_fabs(dy)) - dy6 = -dy; - else - dx6 = -dx; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - default: - return STBTT__CSERR("unimplemented"); - } - } break; - - default: - if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) - return STBTT__CSERR("reserved operator"); - - /* push immediate */ - if (b0 == 255) { - f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; - } else { - stbtt__buf_skip(&b, -1); - f = (float)(stbtt_int16)stbtt__cff_int(&b); - } - if (sp >= 48) return STBTT__CSERR("push stack overflow"); - s[sp++] = f; - clear_stack = 0; - break; - } - if (clear_stack) sp = 0; - } - return STBTT__CSERR("no endchar"); - -#undef STBTT__CSERR -} - -static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - /* runs the charstring twice, once to count and once to output (to avoid realloc) */ - stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); - stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); - if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { - *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); - output_ctx.pvertices = *pvertices; - if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { - STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); - return output_ctx.num_vertices; - } - } - *pvertices = NULL; - return 0; -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - stbtt__csctx c = STBTT__CSCTX_INIT(1); - int r = stbtt__run_charstring(info, glyph_index, &c); - if (x0) *x0 = r ? c.min_x : 0; - if (y0) *y0 = r ? c.min_y : 0; - if (x1) *x1 = r ? c.max_x : 0; - if (y1) *y1 = r ? c.max_y : 0; - return r ? c.num_vertices : 0; -} - -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - if (!info->cff.size) - return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); - else - return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); -} - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) -{ - stbtt_uint8 *data = info->data + info->kern; - - /* we only look at the first table. it must be 'horizontal' and format 0. */ - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) /* number of tables, need at least 1 */ - return 0; - if (ttUSHORT(data+8) != 1) /* horizontal flag must be set in format */ - return 0; - - return ttUSHORT(data+10); -} - -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) -{ - stbtt_uint8 *data = info->data + info->kern; - int k, length; - - /* we only look at the first table. it must be 'horizontal' and format 0. */ - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) /* number of tables, need at least 1 */ - return 0; - if (ttUSHORT(data+8) != 1) /* horizontal flag must be set in format */ - return 0; - - length = ttUSHORT(data+10); - if (table_length < length) - length = table_length; - - for (k = 0; k < length; k++) - { - table[k].glyph1 = ttUSHORT(data+18+(k*6)); - table[k].glyph2 = ttUSHORT(data+20+(k*6)); - table[k].advance = ttSHORT(data+22+(k*6)); - } - - return length; -} - -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint8 *data = info->data + info->kern; - stbtt_uint32 needle, straw; - int l, r, m; - - /* we only look at the first table. it must be 'horizontal' and format 0. */ - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) /* number of tables, need at least 1 */ - return 0; - if (ttUSHORT(data+8) != 1) /* horizontal flag must be set in format */ - return 0; - - l = 0; - r = ttUSHORT(data+10) - 1; - needle = glyph1 << 16 | glyph2; - while (l <= r) { - m = (l + r) >> 1; - straw = ttULONG(data+18+(m*6)); /* note: unaligned read */ - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else - return ttSHORT(data+22+(m*6)); - } - return 0; -} - -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) -{ - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); - switch(coverageFormat) { - case 1: { - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); - - /* Binary search. */ - stbtt_int32 l=0, r=glyphCount-1, m; - int straw, needle=glyph; - while (l <= r) { - stbtt_uint8 *glyphArray = coverageTable + 4; - stbtt_uint16 glyphID; - m = (l + r) >> 1; - glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - return m; - } - } - } break; - - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; - - /* Binary search. */ - stbtt_int32 l=0, r=rangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *rangeRecord; - m = (l + r) >> 1; - rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; - } - } - } break; - - default: { - /* There are no other cases. */ - STBTT_assert(0); - } break; - } - - return -1; -} - -static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) -{ - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); - switch(classDefFormat) - { - case 1: { - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; - - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) - return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - - classDefTable = classDef1ValueArray + 2 * glyphCount; - } break; - - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; - - /* Binary search. */ - stbtt_int32 l=0, r=classRangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *classRangeRecord; - m = (l + r) >> 1; - classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } - - classDefTable = classRangeRecords + 6 * classRangeCount; - } break; - - default: { - /* There are no other cases. */ - STBTT_assert(0); - } break; - } - - return -1; -} - -/* Define to STBTT_assert(x) if you want to break on unimplemented formats. */ -#define STBTT_GPOS_TODO_assert(x) - -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint16 lookupListOffset; - stbtt_uint8 *lookupList; - stbtt_uint16 lookupCount; - stbtt_uint8 *data; - stbtt_int32 i; - - if (!info->gpos) return 0; - - data = info->data + info->gpos; - - if (ttUSHORT(data+0) != 1) return 0; /* Major version 1 */ - if (ttUSHORT(data+2) != 0) return 0; /* Minor version 0 */ - - lookupListOffset = ttUSHORT(data+8); - lookupList = data + lookupListOffset; - lookupCount = ttUSHORT(lookupList); - - for (i=0; i> 1; - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; - secondGlyph = ttUSHORT(pairValue); - straw = secondGlyph; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); - return xAdvance; - } - } - } break; - - case 2: { - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); - - stbtt_uint16 class1Count = ttUSHORT(table + 12); - stbtt_uint16 class2Count = ttUSHORT(table + 14); - STBTT_assert(glyph1class < class1Count); - STBTT_assert(glyph2class < class2Count); - - /* TODO: Support more formats. */ - STBTT_GPOS_TODO_assert(valueFormat1 == 4); - if (valueFormat1 != 4) return 0; - STBTT_GPOS_TODO_assert(valueFormat2 == 0); - if (valueFormat2 != 0) return 0; - - if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { - stbtt_uint8 *class1Records = table + 16; - stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); - stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); - return xAdvance; - } - } break; - - default: { - /* There are no other cases. */ - STBTT_assert(0); - break; - }; - } - } - break; - }; - - default: - /* TODO: Implement other stuff. */ - break; - } - } - - return 0; -} - -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) -{ - int xAdvance = 0; - - if (info->gpos) - xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); - else if (info->kern) - xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); - - return xAdvance; -} - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - if (!info->kern && !info->gpos) /* if no kerning table, don't waste time looking up both codepoint->glyphs */ - return 0; - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); -} - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); -} - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); -} - -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) -{ - int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); - if (!tab) - return 0; - if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); - if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); - if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); - return 1; -} - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) -{ - *x0 = ttSHORT(info->data + info->head + 36); - *y0 = ttSHORT(info->data + info->head + 38); - *x1 = ttSHORT(info->data + info->head + 40); - *y1 = ttSHORT(info->data + info->head + 42); -} - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; -} - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) -{ - int unitsPerEm = ttUSHORT(info->data + info->head + 18); - return pixels / unitsPerEm; -} - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); -} - -STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) -{ - int i; - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); - - int numEntries = ttUSHORT(svg_doc_list); - stbtt_uint8 *svg_docs = svg_doc_list + 2; - - for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) - return svg_doc; - } - return 0; -} - -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) -{ - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc; - - if (info->svg == 0) - return 0; - - svg_doc = stbtt_FindSVGDoc(info, gl); - if (svg_doc != NULL) { - *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); - return ttULONG(svg_doc + 8); - } else { - return 0; - } -} - -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) -{ - return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); -} - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* antialiasing software rasterizer */ -/* */ - -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0=0,y0=0,x1,y1; /* =0 suppresses compiler warning */ - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - /* e.g. space character */ - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */ - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); - } -} - -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); -} - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* Rasterizer */ - -typedef struct stbtt__hheap_chunk -{ - struct stbtt__hheap_chunk *next; -} stbtt__hheap_chunk; - -typedef struct stbtt__hheap -{ - struct stbtt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; -} stbtt__hheap; - -static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); - if (c == NULL) - return NULL; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; - } -} - -static void stbtt__hheap_free(stbtt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; -} - -static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) -{ - stbtt__hheap_chunk *c = hh->head; - while (c) { - stbtt__hheap_chunk *n = c->next; - STBTT_free(c, userdata); - c = n; - } -} - -typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; -} stbtt__edge; - - -typedef struct stbtt__active_edge -{ - struct stbtt__active_edge *next; - #if STBTT_RASTERIZER_VERSION==1 - int x,dx; - float ey; - int direction; - #elif STBTT_RASTERIZER_VERSION==2 - float fx,fdx,fdy; - float direction; - float sy; - float ey; - #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" - #endif -} stbtt__active_edge; - -#if STBTT_RASTERIZER_VERSION == 1 -#define STBTT_FIXSHIFT 10 -#define STBTT_FIX (1 << STBTT_FIXSHIFT) -#define STBTT_FIXMASK (STBTT_FIX-1) - -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - if (!z) return z; - - /* round dx down to avoid overshooting */ - if (dxdy < 0) - z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); - else - z->dx = STBTT_ifloor(STBTT_FIX * dxdy); - - z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); /* use z->dx so when we offset later it's by the same amount */ - z->x -= off_x * STBTT_FIX; - - z->ey = e->y1; - z->next = 0; - z->direction = e->invert ? 1 : -1; - return z; -} -#elif STBTT_RASTERIZER_VERSION == 2 -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - /* STBTT_assert(e->y0 <= start_point); */ - if (!z) return z; - z->fdx = dxdy; - z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; -} -#else -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - -#if STBTT_RASTERIZER_VERSION == 1 -/* note: this routine clips fills that extend off the edges... ideally this */ -/* wouldn't happen, but it could happen if the truetype glyph bounding boxes */ -/* are wrong, or if the user supplies a too-small bitmap */ -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - /* non-zero winding fill */ - int x0=0, w=0; - - while (e) { - if (w == 0) { - /* if we're currently at zero, we need to record the edge start point */ - x0 = e->x; w += e->direction; - } else { - int x1 = e->x; w += e->direction; - /* if we went to zero, we need to draw */ - if (w == 0) { - int i = x0 >> STBTT_FIXSHIFT; - int j = x1 >> STBTT_FIXSHIFT; - - if (i < len && j >= 0) { - if (i == j) { - /* x0,x1 are the same pixel, so compute combined coverage */ - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); - } else { - if (i >= 0) /* add antialiasing for x0 */ - scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); - else - i = -1; /* clip */ - - if (j < len) /* add antialiasing for x1 */ - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); - else - j = len; /* clip */ - - for (++i; i < j; ++i) /* fill pixels between x0 and x1 */ - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } - } - } - } - - e = e->next; - } -} - -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); /* weight per vertical scanline */ - int s; /* vertical subsample index */ - unsigned char scanline_data[512], *scanline; - - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; - - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; - - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - /* find center of pixel for this scanline */ - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; - - /* update all active edges; */ - /* remove all active edges that terminate before the center of this scanline */ - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; /* delete from list */ - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - z->x += z->dx; /* advance to position for current scanline */ - step = &((*step)->next); /* advance through list */ - } - } - - /* resort the list if needed */ - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - /* insert all edges that start before the center of this scanline -- omit ones that also end on this scanline */ - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); - if (z != NULL) { - /* find insertion point */ - if (active == NULL) - active = z; - else if (z->x < active->x) { - /* insert at front */ - z->next = active; - active = z; - } else { - /* find thing to insert AFTER */ - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - /* at this point, p->next->x is NOT < z->x */ - z->next = p->next; - p->next = z; - } - } - } - ++e; - } - - /* now process all active edges in XOR fashion */ - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); - - ++y; - } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } - - stbtt__hheap_cleanup(&hh, userdata); - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} - -#elif STBTT_RASTERIZER_VERSION == 2 - -/* the edge passed in here does not cross the vertical line at x or the vertical line at x+1 */ -/* (i.e. it has already been clipped to those) */ -static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - STBTT_assert(y0 < y1); - STBTT_assert(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } - - if (x0 == x) - STBTT_assert(x1 <= x+1); - else if (x0 == x+1) - STBTT_assert(x1 >= x); - else if (x0 <= x) - STBTT_assert(x1 <= x); - else if (x0 >= x+1) - STBTT_assert(x1 >= x+1); - else - STBTT_assert(x1 >= x && x1 <= x+1); - - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1) - ; - else { - STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); /* coverage = 1 - average x position */ - } -} - -static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; - - while (e) { - /* brute force every pixel */ - - /* compute intersection points with top & bottom */ - STBTT_assert(e->ey >= y_top); - - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); - } else { - stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); - } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float sy0,sy1; - float dy = e->fdy; - STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); - - /* compute endpoints of line segment clipped to this scanline (if the */ - /* line segment starts on this scanline. x0 is the intersection of the */ - /* line with y_top, but that may be off the line segment. */ - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - sy0 = e->sy; - } else { - x_top = x0; - sy0 = y_top; - } - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - sy1 = e->ey; - } else { - x_bottom = xb; - sy1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { - /* from here on, we don't have to range check x values */ - - if ((int) x_top == (int) x_bottom) { - float height; - /* simple case, only spans one pixel */ - int x = (int) x_top; - height = sy1 - sy0; - STBTT_assert(x >= 0 && x < len); - scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; - scanline_fill[x] += e->direction * height; /* everything right of this pixel is filled */ - } else { - int x,x1,x2; - float y_crossing, step, sign, area; - /* covers 2+ pixels */ - if (x_top > x_bottom) { - /* flip scanline vertically; signed area is the same */ - float t; - sy0 = y_bottom - (sy0 - y_top); - sy1 = y_bottom - (sy1 - y_top); - t = sy0, sy0 = sy1, sy1 = t; - t = x_bottom, x_bottom = x_top, x_top = t; - dx = -dx; - dy = -dy; - t = x0, x0 = xb, xb = t; - } - - x1 = (int) x_top; - x2 = (int) x_bottom; - /* compute intersection with y axis at x1+1 */ - y_crossing = (x1+1 - x0) * dy + y_top; - - sign = e->direction; - /* area of the rectangle covered from y0..y_crossing */ - area = sign * (y_crossing-sy0); - /* area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) */ - scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); - - step = sign * dy; - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; - area += step; - } - y_crossing += dy * (x2 - (x1+1)); - - STBTT_assert(STBTT_fabs(area) <= 1.01f); - - scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); - - scanline_fill[x2] += sign * (sy1-sy0); - } - } else { - /* if edge goes outside of box we're drawing, we require */ - /* clipping logic. since this does not match the intended use */ - /* of this library, we use a different, very slow brute */ - /* force implementation */ - int x; - for (x=0; x < len; ++x) { - /* cases: */ - /* */ - /* there can be up to two intersections with the pixel. any intersection */ - /* with left or right edges can be handled by splitting into two (or three) */ - /* regions. intersections with top & bottom do not necessitate case-wise logic. */ - /* */ - /* the old way of doing this found the intersections with the left & right edges, */ - /* then used some simple logic to produce up to three segments in sorted order */ - /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */ - /* across the x border, then the corresponding y position might not be distinct */ - /* from the other y segment, and it might ignored as an empty segment. to avoid */ - /* that, we need to explicitly produce segments based on x positions. */ - - /* rename variables to clearly-defined pairs */ - float y0 = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - - /* x = e->x + e->dx * (y-y_top) */ - /* (y-y_top) = (x - e->x) / e->dx */ - /* y = (x - e->x) / e->dx + y_top */ - float y1 = (x - x0) / dx + y_top; - float y2 = (x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { /* three segments descending down-right */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { /* one segment */ - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); - } - } - } - } - e = e->next; - } -} - -/* directly AA rasterize edges w/o supersampling */ -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; - - STBTT__NOTUSED(vsubsample); - - if (result->w > 64) - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); - else - scanline = scanline_data; - - scanline2 = scanline + result->w; - - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; - - while (j < result->h) { - /* find center of pixel for this scanline */ - float scan_y_top = y + 0.0f; - float scan_y_bottom = y + 1.0f; - stbtt__active_edge **step = &active; - - STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); - STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); - - /* update all active edges; */ - /* remove all active edges that terminate before the top of this scanline */ - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; /* delete from list */ - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - step = &((*step)->next); /* advance through list */ - } - } - - /* insert all edges that start before the bottom of this scanline */ - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); - if (z != NULL) { - if (j == 0 && off_y != 0) { - if (z->ey < scan_y_top) { - /* this can happen due to subpixel positioning and some kind of fp rounding error i think */ - z->ey = scan_y_top; - } - } - STBTT_assert(z->ey >= scan_y_top); /* if we get really unlucky a tiny bit of an edge can be out of bounds */ - /* insert at front */ - z->next = active; - active = z; - } - } - ++e; - } - - /* now process all active edges */ - if (active) - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); - - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) STBTT_fabs(k)*255 + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - /* advance all the edges */ - step = &active; - while (*step) { - stbtt__active_edge *z = *step; - z->fx += z->fdx; /* advance to position for current scanline */ - step = &((*step)->next); /* advance through list */ - } - - ++y; - ++j; - } - - stbtt__hheap_cleanup(&hh, userdata); - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} -#else -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - -#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) - -static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - stbtt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - stbtt__edge *b = &p[j-1]; - int c = STBTT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } -} - -static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) -{ - /* threshold for transitioning to insertion sort */ - while (n > 12) { - stbtt__edge t; - int c01,c12,c,m,i,j; - - /* compute median of three */ - m = n >> 1; - c01 = STBTT__COMPARE(&p[0],&p[m]); - c12 = STBTT__COMPARE(&p[m],&p[n-1]); - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = STBTT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; - p[m] = t; - - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!STBTT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!STBTT__COMPARE(&p[0], &p[j])) break; - } - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; - - ++i; - --j; - } - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - stbtt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - stbtt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } -} - -static void stbtt__sort_edges(stbtt__edge *p, int n) -{ - stbtt__sort_edges_quicksort(p, n); - stbtt__sort_edges_ins_sort(p, n); -} - -typedef struct -{ - float x,y; -} stbtt__point; - -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; -#if STBTT_RASTERIZER_VERSION == 1 - int vsubsample = result->h < 8 ? 15 : 5; -#elif STBTT_RASTERIZER_VERSION == 2 - int vsubsample = 1; -#else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */ - - /* now we have to blow out the windings into explicit edge lists */ - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); /* add an extra one as a sentinel */ - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - /* skip the edge if horizontal */ - if (p[j].y == p[k].y) - continue; - /* add edge from j to k to the list */ - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; - ++n; - } - } - - /* now sort the edges by their highest point (should snap to integer, and then by x) */ - /* STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */ - stbtt__sort_edges(e, n); - - /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */ - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); - - STBTT_free(e, userdata); -} - -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; /* during first pass, it's unallocated */ - points[n].x = x; - points[n].y = y; -} - -/* tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching */ -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - /* midpoint */ - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - /* versus directly drawn line */ - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) /* 65536 segments on one curve better be enough! */ - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { /* half-pixel error allowed... need to be smaller if AA */ - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) -{ - /* @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough */ - float dx0 = x1-x0; - float dy0 = y1-y0; - float dx1 = x2-x1; - float dy1 = y2-y1; - float dx2 = x3-x2; - float dy2 = y3-y2; - float dx = x3-x0; - float dy = y3-y0; - float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); - float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); - float flatness_squared = longlen*longlen-shortlen*shortlen; - - if (n > 16) /* 65536 segments on one curve better be enough! */ - return; - - if (flatness_squared > objspace_flatness_squared) { - float x01 = (x0+x1)/2; - float y01 = (y0+y1)/2; - float x12 = (x1+x2)/2; - float y12 = (y1+y2)/2; - float x23 = (x2+x3)/2; - float y23 = (y2+y3)/2; - - float xa = (x01+x12)/2; - float ya = (y01+y12)/2; - float xb = (x12+x23)/2; - float yb = (y12+y23)/2; - - float mx = (xa+xb)/2; - float my = (ya+yb)/2; - - stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x3,y3); - *num_points = *num_points+1; - } -} - -/* returns number of contours */ -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; - - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; - - /* count how many "moves" there are to get the contour count */ - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - /* make two passes through the points so we don't need to realloc */ - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; - } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { - case STBTT_vmove: - /* start the next contour */ - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; - case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; - case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - case STBTT_vcubic: - stbtt__tesselate_cubic(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].cx1, vertices[i].cy1, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } - - return points; -error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; -} - -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count = 0; - int *winding_lengths = NULL; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } -} - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) { - STBTT_free(vertices, info->userdata); - return NULL; - } - scale_y = scale_x; - } - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); - - /* now we get the size */ - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; /* in case we error */ - - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; - - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); - - STBTT_free(vertices, info->userdata); -} - -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); -} - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* bitmap baking */ -/* */ -/* This is SUPER-CRAPPY packing to keep source code small */ - -static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, /* font location (use offset=0 for plain .ttf) */ - float pixel_height, /* height of font in pixels */ - unsigned char *pixels, int pw, int ph, /* bitmap to be filled in */ - int first_char, int num_chars, /* characters to bake */ - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - f.userdata = NULL; - if (!stbtt_InitFont(&f, data, offset)) - return -1; - STBTT_memset(pixels, 0, pw*ph); /* background of 0 around pixels */ - x=y=1; - bottom_y = 1; - - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; /* advance to next row */ - if (y + gh + 1 >= ph) /* check if it fits vertically AFTER potentially moving to next row */ - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 1; - if (y+gh+1 > bottom_y) - bottom_y = y+gh+1; - } - return bottom_y; -} - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); - - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* rectangle packing replacement routines if you don't have stb_rect_pack.h */ -/* */ - -#ifndef STB_RECT_PACK_VERSION - -typedef int stbrp_coord; - -/* ////////////////////////////////////////////////////////////////////////////////// */ -/* // */ -/* // */ -/* COMPILER WARNING ?!?!? // */ -/* // */ -/* // */ -/* if you get a compile warning due to these symbols being defined more than // */ -/* once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // */ -/* // */ -/* ////////////////////////////////////////////////////////////////////////////////// */ - -typedef struct -{ - int width,height; - int x,y,bottom_y; -} stbrp_context; - -typedef struct -{ - unsigned char x; -} stbrp_node; - -struct stbrp_rect -{ - stbrp_coord x,y; - int id,w,h,was_packed; -}; - -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) -{ - con->width = pw; - con->height = ph; - con->x = 0; - con->y = 0; - con->bottom_y = 0; - STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); -} - -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) -{ - int i; - for (i=0; i < num_rects; ++i) { - if (con->x + rects[i].w > con->width) { - con->x = 0; - con->y = con->bottom_y; - } - if (con->y + rects[i].h > con->height) - break; - rects[i].x = con->x; - rects[i].y = con->y; - rects[i].was_packed = 1; - con->x += rects[i].w; - if (con->y + rects[i].h > con->bottom_y) - con->bottom_y = con->y + rects[i].h; - } - for ( ; i < num_rects; ++i) - rects[i].was_packed = 0; -} -#endif - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* bitmap baking */ -/* */ -/* This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If */ -/* stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. */ - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) -{ - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw - padding; - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); - - if (context == NULL || nodes == NULL) { - if (context != NULL) STBTT_free(context, alloc_context); - if (nodes != NULL) STBTT_free(nodes , alloc_context); - return 0; - } - - spc->user_allocator_context = alloc_context; - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - spc->skip_missing = 0; - - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - - if (pixels) - STBTT_memset(pixels, 0, pw*ph); /* background of 0 around pixels */ - - return 1; -} - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) -{ - STBTT_free(spc->nodes , spc->user_allocator_context); - STBTT_free(spc->pack_info, spc->user_allocator_context); -} - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) -{ - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); - if (h_oversample <= STBTT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= STBTT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) -{ - spc->skip_missing = skip; -} - -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) - -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); /* suppress bogus warning from VS2013 -analyze */ - for (j=0; j < h; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - /* make kernel_width a constant in common cases so compiler can optimize out the divide */ - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < w; ++i) { - STBTT_assert(pixels[i] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = (unsigned char) (total / kernel_width); - } - - pixels += stride_in_bytes; - } -} - -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); /* suppress bogus warning from VS2013 -analyze */ - for (j=0; j < w; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - /* make kernel_width a constant in common cases so compiler can optimize out the divide */ - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < h; ++i) { - STBTT_assert(pixels[i*stride_in_bytes] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - - pixels += 1; - } -} - -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; - - /* The prefilter is a box filter of width "oversample", */ - /* which shifts phase by (oversample - 1)/2 pixels in */ - /* oversampled space. We want to shift in the opposite */ - /* direction to counter this. */ - return (float)-(oversample - 1) / (2.0f * (float)oversample); -} - -/* rects array must be big enough to accommodate all characters in the given ranges */ -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k; - int missing_glyph_added = 0; - - k=0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { - rects[k].w = rects[k].h = 0; - } else { - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - if (glyph == 0) - missing_glyph_added = 1; - } - ++k; - } - } - - return k; -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, - output, - out_w - (prefilter_x - 1), - out_h - (prefilter_y - 1), - out_stride, - scale_x, - scale_y, - shift_x, - shift_y, - glyph); - - if (prefilter_x > 1) - stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); - - if (prefilter_y > 1) - stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); - - *sub_x = stbtt__oversample_shift(prefilter_x); - *sub_y = stbtt__oversample_shift(prefilter_y); -} - -/* rects array must be big enough to accommodate all characters in the given ranges */ -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k, missing_glyph = -1, return_value = 1; - - /* save current values */ - int old_h_over = spc->h_oversample; - int old_v_over = spc->v_oversample; - - k = 0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - float recip_h,recip_v,sub_x,sub_y; - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - recip_h = 1.0f / spc->h_oversample; - recip_v = 1.0f / spc->v_oversample; - sub_x = stbtt__oversample_shift(spc->h_oversample); - sub_y = stbtt__oversample_shift(spc->v_oversample); - for (j=0; j < ranges[i].num_chars; ++j) { - stbrp_rect *r = &rects[k]; - if (r->was_packed && r->w != 0 && r->h != 0) { - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbrp_coord pad = (stbrp_coord) spc->padding; - - /* pad on left and top */ - r->x += pad; - r->y += pad; - r->w -= pad; - r->h -= pad; - stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(info, glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - &x0,&y0,&x1,&y1); - stbtt_MakeGlyphBitmapSubpixel(info, - spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w - spc->h_oversample+1, - r->h - spc->v_oversample+1, - spc->stride_in_bytes, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - glyph); - - if (spc->h_oversample > 1) - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->h_oversample); - - if (spc->v_oversample > 1) - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->v_oversample); - - bc->x0 = (stbtt_int16) r->x; - bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w); - bc->y1 = (stbtt_int16) (r->y + r->h); - bc->xadvance = scale * advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; - - if (glyph == 0) - missing_glyph = j; - } else if (spc->skip_missing) { - return_value = 0; - } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { - ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; - } else { - return_value = 0; /* if any fail, report failure */ - } - - ++k; - } - } - - /* restore original values */ - spc->h_oversample = old_h_over; - spc->v_oversample = old_v_over; - - return return_value; -} - -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) -{ - stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); -} - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) -{ - stbtt_fontinfo info; - int i,j,n, return_value = 1; - /* stbrp_context *context = (stbrp_context *) spc->pack_info; */ - stbrp_rect *rects; - - /* flag all characters as NOT packed */ - for (i=0; i < num_ranges; ++i) - for (j=0; j < ranges[i].num_chars; ++j) - ranges[i].chardata_for_range[j].x0 = - ranges[i].chardata_for_range[j].y0 = - ranges[i].chardata_for_range[j].x1 = - ranges[i].chardata_for_range[j].y1 = 0; - - n = 0; - for (i=0; i < num_ranges; ++i) - n += ranges[i].num_chars; - - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); - if (rects == NULL) - return 0; - - info.userdata = spc->user_allocator_context; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); - - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); - - stbtt_PackFontRangesPackRects(spc, rects, n); - - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); - - STBTT_free(rects, spc->user_allocator_context); - return return_value; -} - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) -{ - stbtt_pack_range range; - range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; - range.array_of_unicode_codepoints = NULL; - range.num_chars = num_chars_in_range; - range.chardata_for_range = chardata_for_range; - range.font_size = font_size; - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); -} - -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) -{ - int i_ascent, i_descent, i_lineGap; - float scale; - stbtt_fontinfo info; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); - scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); - stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); - *ascent = (float) i_ascent * scale; - *descent = (float) i_descent * scale; - *lineGap = (float) i_lineGap * scale; -} - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) -{ - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_packedchar *b = chardata + char_index; - - if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* sdf computation */ -/* */ - -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) - -static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) -{ - float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; - float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; - float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; - float roperp = orig[1]*ray[0] - orig[0]*ray[1]; - - float a = q0perp - 2*q1perp + q2perp; - float b = q1perp - q0perp; - float c = q0perp - roperp; - - float s0 = 0., s1 = 0.; - int num_s = 0; - - if (a != 0.0) { - float discr = b*b - a*c; - if (discr > 0.0) { - float rcpna = -1 / a; - float d = (float) STBTT_sqrt(discr); - s0 = (b+d) * rcpna; - s1 = (b-d) * rcpna; - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { - if (num_s == 0) s0 = s1; - ++num_s; - } - } - } else { - /* 2*b*s + c = 0 */ - /* s = -c / (2*b) */ - s0 = c / (-2 * b); - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - } - - if (num_s == 0) - return 0; - else { - float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); - float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; - - float q0d = q0[0]*rayn_x + q0[1]*rayn_y; - float q1d = q1[0]*rayn_x + q1[1]*rayn_y; - float q2d = q2[0]*rayn_x + q2[1]*rayn_y; - float rod = orig[0]*rayn_x + orig[1]*rayn_y; - - float q10d = q1d - q0d; - float q20d = q2d - q0d; - float q0rd = q0d - rod; - - hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; - hits[0][1] = a*s0+b; - - if (num_s > 1) { - hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; - hits[1][1] = a*s1+b; - return 2; - } else { - return 1; - } - } -} - -static int equal(float *a, float *b) -{ - return (a[0] == b[0] && a[1] == b[1]); -} - -static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) -{ - int i; - float orig[2], ray[2] = { 1, 0 }; - float y_frac; - int winding = 0; - - orig[0] = x; - orig[1] = y; - - /* make sure y never passes through a vertex of the shape */ - y_frac = (float) STBTT_fmod(y, 1.0f); - if (y_frac < 0.01f) - y += 0.01f; - else if (y_frac > 0.99f) - y -= 0.01f; - orig[1] = y; - - /* test a ray from (-infinity,y) to (x,y) */ - for (i=0; i < nverts; ++i) { - if (verts[i].type == STBTT_vline) { - int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; - int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } - if (verts[i].type == STBTT_vcurve) { - int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; - int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; - int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; - int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); - int by = STBTT_max(y0,STBTT_max(y1,y2)); - if (y > ay && y < by && x > ax) { - float q0[2],q1[2],q2[2]; - float hits[2][2]; - q0[0] = (float)x0; - q0[1] = (float)y0; - q1[0] = (float)x1; - q1[1] = (float)y1; - q2[0] = (float)x2; - q2[1] = (float)y2; - if (equal(q0,q1) || equal(q1,q2)) { - x0 = (int)verts[i-1].x; - y0 = (int)verts[i-1].y; - x1 = (int)verts[i ].x; - y1 = (int)verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } else { - int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); - if (num_hits >= 1) - if (hits[0][0] < 0) - winding += (hits[0][1] < 0 ? -1 : 1); - if (num_hits >= 2) - if (hits[1][0] < 0) - winding += (hits[1][1] < 0 ? -1 : 1); - } - } - } - } - return winding; -} - -static float stbtt__cuberoot( float x ) -{ - if (x<0) - return -(float) STBTT_pow(-x,1.0f/3.0f); - else - return (float) STBTT_pow( x,1.0f/3.0f); -} - -/* x^3 + c*x^2 + b*x + a = 0 */ -static int stbtt__solve_cubic(float a, float b, float c, float* r) -{ - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; - float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; /* p3 must be negative, since d is negative */ - float m = (float) STBTT_cos(v); - float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); - - /* STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? */ - /* STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); */ - /* STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); */ - return 3; - } -} - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - float scale_x = scale, scale_y = scale; - int ix0,iy0,ix1,iy1; - int w,h; - unsigned char *data; - - if (scale == 0) return NULL; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); - - /* if empty, return NULL */ - if (ix0 == ix1 || iy0 == iy1) - return NULL; - - ix0 -= padding; - iy0 -= padding; - ix1 += padding; - iy1 += padding; - - w = (ix1 - ix0); - h = (iy1 - iy0); - - if (width ) *width = w; - if (height) *height = h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - /* invert for y-downwards bitmaps */ - scale_y = -scale_y; - - { - int x,y,i,j; - float *precompute; - stbtt_vertex *verts; - int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); - data = (unsigned char *) STBTT_malloc(w * h, info->userdata); - precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); - - for (i=0,j=num_verts-1; i < num_verts; j=i++) { - if (verts[i].type == STBTT_vline) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; - float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); - precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; - float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; - float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float len2 = bx*bx + by*by; - if (len2 != 0.0f) - precompute[i] = 1.0f / (bx*bx + by*by); - else - precompute[i] = 0.0f; - } else - precompute[i] = 0.0f; - } - - for (y=iy0; y < iy1; ++y) { - for (x=ix0; x < ix1; ++x) { - float val; - float min_dist = 999999.0f; - float sx = (float) x + 0.5f; - float sy = (float) y + 0.5f; - float x_gspace = (sx / scale_x); - float y_gspace = (sy / scale_y); - - int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); /* @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path */ - - for (i=0; i < num_verts; ++i) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - - /* check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve */ - float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - if (verts[i].type == STBTT_vline) { - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; - - /* coarse culling against bbox */ - /* if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && */ - /* sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) */ - float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; - STBTT_assert(i != 0); - if (dist < min_dist) { - /* check position along line */ - /* x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) */ - /* minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) */ - float dx = x1-x0, dy = y1-y0; - float px = x0-sx, py = y0-sy; - /* minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy */ - /* derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve */ - float t = -(px*dx + py*dy) / (dx*dx + dy*dy); - if (t >= 0.0f && t <= 1.0f) - min_dist = dist; - } - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; - float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; - float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); - float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); - float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); - float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); - /* coarse culling against bbox to avoid computing cubic unnecessarily */ - if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { - int num=0; - float ax = x1-x0, ay = y1-y0; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float mx = x0 - sx, my = y0 - sy; - float res[3],px,py,t,it; - float a_inv = precompute[i]; - if (a_inv == 0.0) { /* if a_inv is 0, it's 2nd degree so use quadratic formula */ - float a = 3*(ax*bx + ay*by); - float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); - float c = mx*ax+my*ay; - if (a == 0.0) { /* if a is 0, it's linear */ - if (b != 0.0) { - res[num++] = -c/b; - } - } else { - float discriminant = b*b - 4*a*c; - if (discriminant < 0) - num = 0; - else { - float root = (float) STBTT_sqrt(discriminant); - res[0] = (-b - root)/(2*a); - res[1] = (-b + root)/(2*a); - num = 2; /* don't bother distinguishing 1-solution case, as code below will still work */ - } - } - } else { - float b = 3*(ax*bx + ay*by) * a_inv; /* could precompute this as it doesn't depend on sample point */ - float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; - float d = (mx*ax+my*ay) * a_inv; - num = stbtt__solve_cubic(b, c, d, res); - } - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { - t = res[0], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { - t = res[1], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { - t = res[2], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - } - } - } - if (winding == 0) - min_dist = -min_dist; /* if outside the shape, value is negative */ - val = onedge_value + pixel_dist_scale * min_dist; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; - } - } - STBTT_free(precompute, info->userdata); - STBTT_free(verts, info->userdata); - } - return data; -} - -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -/* //////////////////////////////////////////////////////////////////////////// */ -/* */ -/* font name matching -- recommended not to use this */ -/* */ - -/* check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string */ -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; - - /* convert utf16 to utf8 and compare the results while converting */ - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; /* plus another 2 below */ - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; - len2 -= 2; - } - return i; -} - -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); -} - -/* returns results in whatever encoding you request... but note that 2-byte encodings */ -/* will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare */ -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; - - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; -} - -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); - - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - /* find the encoding */ - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); - - /* is this a Unicode encoding? */ - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8); - stbtt_int32 off = ttUSHORT(fc+loc+10); - - /* check if there's a prefix match */ - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - /* check for target_id+1 immediately following, with same encoding & language */ - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - slen = ttUSHORT(fc+loc+12+8); - off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - /* if nothing immediately following */ - if (matchlen == nlen) - return 1; - } - } - } - - /* @TODO handle other encodings */ - } - } - return 0; -} - -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; - - /* check italics/bold/underline flags in macStyle... */ - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } - - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; - - if (flags) { - /* if we checked the macStyle flags, then just check the family and ignore the subfamily */ - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } - - return 0; -} - -static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, - float pixel_height, unsigned char *pixels, int pw, int ph, - int first_char, int num_chars, stbtt_bakedchar *chardata) -{ - return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); -} - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) -{ - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); -} - -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) -{ - return stbtt_GetNumberOfFonts_internal((unsigned char *) data); -} - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) -{ - return stbtt_InitFont_internal(info, (unsigned char *) data, offset); -} - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) -{ - return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); -} - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#endif /* STB_TRUETYPE_IMPLEMENTATION */ - - -/* FULL VERSION HISTORY */ -/* */ -/* 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod */ -/* 1.18 (2018-01-29) add missing function */ -/* 1.17 (2017-07-23) make more arguments const; doc fix */ -/* 1.16 (2017-07-12) SDF support */ -/* 1.15 (2017-03-03) make more arguments const */ -/* 1.14 (2017-01-16) num-fonts-in-TTC function */ -/* 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts */ -/* 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual */ -/* 1.11 (2016-04-02) fix unused-variable warning */ -/* 1.10 (2016-04-02) allow user-defined fabs() replacement */ -/* fix memory leak if fontsize=0.0 */ -/* fix warning from duplicate typedef */ -/* 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges */ -/* 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges */ -/* 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; */ -/* allow PackFontRanges to pack and render in separate phases; */ -/* fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); */ -/* fixed an assert() bug in the new rasterizer */ -/* replace assert() with STBTT_assert() in new rasterizer */ -/* 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) */ -/* also more precise AA rasterizer, except if shapes overlap */ -/* remove need for STBTT_sort */ -/* 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC */ -/* 1.04 (2015-04-15) typo in example */ -/* 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes */ -/* 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ */ -/* 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match */ -/* non-oversampled; STBTT_POINT_SIZE for packed case only */ -/* 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling */ -/* 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) */ -/* 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID */ -/* 0.8b (2014-07-07) fix a warning */ -/* 0.8 (2014-05-25) fix a few more warnings */ -/* 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back */ -/* 0.6c (2012-07-24) improve documentation */ -/* 0.6b (2012-07-20) fix a few more warnings */ -/* 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, */ -/* stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty */ -/* 0.5 (2011-12-09) bugfixes: */ -/* subpixel glyph renderer computed wrong bounding box */ -/* first vertex of shape can be off-curve (FreeSans) */ -/* 0.4b (2011-12-03) fixed an error in the font baking example */ -/* 0.4 (2011-12-01) kerning, subpixel rendering (tor) */ -/* bugfixes for: */ -/* codepoint-to-glyph conversion using table fmt=12 */ -/* codepoint-to-glyph conversion using table fmt=4 */ -/* stbtt_GetBakedQuad with non-square texture (Zer) */ -/* updated Hello World! sample to use kerning and subpixel */ -/* fixed some warnings */ -/* 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) */ -/* userdata, malloc-from-userdata, non-zero fill (stb) */ -/* 0.2 (2009-03-11) Fix unsigned/signed char warnings */ -/* 0.1 (2009-03-09) First public release */ -/* */ - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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 NK_INCLUDE_FONT_BAKING -/* ------------------------------------------------------------- - * - * RECT PACK - * - * --------------------------------------------------------------*/ - - - -/* - * ============================================================== - * - * TRUETYPE - * - * =============================================================== - */ -#define STBTT_MAX_OVERSAMPLE 8 - - -/* ------------------------------------------------------------- - * - * FONT BAKING - * - * --------------------------------------------------------------*/ -struct nk_font_bake_data { - struct stbtt_fontinfo info; - struct stbrp_rect *rects; - stbtt_pack_range *ranges; - nk_rune range_count; -}; - -struct nk_font_baker { - struct nk_allocator alloc; - struct stbtt_pack_context spc; - struct nk_font_bake_data *build; - stbtt_packedchar *packed_chars; - struct stbrp_rect *rects; - stbtt_pack_range *ranges; -}; - -NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct stbrp_rect); -NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(stbtt_pack_range); -NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(stbtt_packedchar); -NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data); -NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker); - -NK_INTERN int -nk_range_count(const nk_rune *range) -{ - const nk_rune *iter = range; - NK_ASSERT(range); - if (!range) return 0; - while (*(iter++) != 0); - return (iter == range) ? 0 : (int)((iter - range)/2); -} -NK_INTERN int -nk_range_glyph_count(const nk_rune *range, int count) -{ - int i = 0; - int total_glyphs = 0; - for (i = 0; i < count; ++i) { - int diff; - nk_rune f = range[(i*2)+0]; - nk_rune t = range[(i*2)+1]; - NK_ASSERT(t >= f); - diff = (int)((t - f) + 1); - total_glyphs += diff; - } - return total_glyphs; -} -NK_API const nk_rune* -nk_font_default_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0}; - return ranges; -} -NK_API const nk_rune* -nk_font_chinese_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x3000, 0x30FF, - 0x31F0, 0x31FF, - 0xFF00, 0xFFEF, - 0x4e00, 0x9FAF, - 0 - }; - return ranges; -} -NK_API const nk_rune* -nk_font_cyrillic_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x0400, 0x052F, - 0x2DE0, 0x2DFF, - 0xA640, 0xA69F, - 0 - }; - return ranges; -} -NK_API const nk_rune* -nk_font_korean_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x3131, 0x3163, - 0xAC00, 0xD79D, - 0 - }; - return ranges; -} -NK_INTERN void -nk_font_baker_memory(nk_size *temp, int *glyph_count, - struct nk_font_config *config_list, int count) -{ - int range_count = 0; - int total_range_count = 0; - struct nk_font_config *iter, *i; - - NK_ASSERT(config_list); - NK_ASSERT(glyph_count); - if (!config_list) { - *temp = 0; - *glyph_count = 0; - return; - } - *glyph_count = 0; - for (iter = config_list; iter; iter = iter->next) { - i = iter; - do {if (!i->range) iter->range = nk_font_default_glyph_ranges(); - range_count = nk_range_count(i->range); - total_range_count += range_count; - *glyph_count += nk_range_glyph_count(i->range, range_count); - } while ((i = i->n) != iter); - } - *temp = (nk_size)*glyph_count * sizeof(struct stbrp_rect); - *temp += (nk_size)total_range_count * sizeof(stbtt_pack_range); - *temp += (nk_size)*glyph_count * sizeof(stbtt_packedchar); - *temp += (nk_size)count * sizeof(struct nk_font_bake_data); - *temp += sizeof(struct nk_font_baker); - *temp += nk_rect_align + nk_range_align + nk_char_align; - *temp += nk_build_align + nk_baker_align; -} -NK_INTERN struct nk_font_baker* -nk_font_baker(void *memory, int glyph_count, int count, struct nk_allocator *alloc) -{ - struct nk_font_baker *baker; - if (!memory) return 0; - /* setup baker inside a memory block */ - baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align); - baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align); - baker->packed_chars = (stbtt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align); - baker->rects = (struct stbrp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align); - baker->ranges = (stbtt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align); - baker->alloc = *alloc; - return baker; -} -NK_INTERN int -nk_font_bake_pack(struct nk_font_baker *baker, - nk_size *image_memory, int *width, int *height, struct nk_recti *custom, - const struct nk_font_config *config_list, int count, - struct nk_allocator *alloc) -{ - NK_STORAGE const nk_size max_height = 1024 * 32; - const struct nk_font_config *config_iter, *it; - int total_glyph_count = 0; - int total_range_count = 0; - int range_count = 0; - int i = 0; - - NK_ASSERT(image_memory); - NK_ASSERT(width); - NK_ASSERT(height); - NK_ASSERT(config_list); - NK_ASSERT(count); - NK_ASSERT(alloc); - - if (!image_memory || !width || !height || !config_list || !count) return nk_false; - for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - it = config_iter; - do {range_count = nk_range_count(it->range); - total_range_count += range_count; - total_glyph_count += nk_range_glyph_count(it->range, range_count); - } while ((it = it->n) != config_iter); - } - /* setup font baker from temporary memory */ - for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - struct stbtt_fontinfo *font_info = &baker->build[i++].info; - it = config_iter; - font_info->userdata = alloc; - do {if (!stbtt_InitFont(font_info, (const unsigned char*)it->ttf_blob, 0)) - return nk_false; - } while ((it = it->n) != config_iter); - } - *height = 0; - *width = (total_glyph_count > 1000) ? 1024 : 512; - stbtt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc); - { - int input_i = 0; - int range_n = 0; - int rect_n = 0; - int char_n = 0; - - if (custom) { - /* pack custom user data first so it will be in the upper left corner*/ - struct stbrp_rect custom_space; - nk_zero(&custom_space, sizeof(custom_space)); - custom_space.w = (stbrp_coord)(custom->w); - custom_space.h = (stbrp_coord)(custom->h); - - stbtt_PackSetOversampling(&baker->spc, 1, 1); - stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, &custom_space, 1); - *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h)); - - custom->x = (short)custom_space.x; - custom->y = (short)custom_space.y; - custom->w = (short)custom_space.w; - custom->h = (short)custom_space.h; - } - - /* first font pass: pack all glyphs */ - for (input_i = 0, config_iter = config_list; input_i < count && config_iter; - config_iter = config_iter->next) { - it = config_iter; - do {int n = 0; - int glyph_count; - const nk_rune *in_range; - const struct nk_font_config *cfg = it; - struct nk_font_bake_data *tmp = &baker->build[input_i++]; - - /* count glyphs + ranges in current font */ - glyph_count = 0; range_count = 0; - for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) { - glyph_count += (int)(in_range[1] - in_range[0]) + 1; - range_count++; - } - - /* setup ranges */ - tmp->ranges = baker->ranges + range_n; - tmp->range_count = (nk_rune)range_count; - range_n += range_count; - for (i = 0; i < range_count; ++i) { - in_range = &cfg->range[i * 2]; - tmp->ranges[i].font_size = cfg->size; - tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0]; - tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1; - tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n; - char_n += tmp->ranges[i].num_chars; - } - - /* pack */ - tmp->rects = baker->rects + rect_n; - rect_n += glyph_count; - stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - n = stbtt_PackFontRangesGatherRects(&baker->spc, &tmp->info, - tmp->ranges, (int)tmp->range_count, tmp->rects); - stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, tmp->rects, (int)n); - - /* texture height */ - for (i = 0; i < n; ++i) { - if (tmp->rects[i].was_packed) - *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h); - } - } while ((it = it->n) != config_iter); - } - NK_ASSERT(rect_n == total_glyph_count); - NK_ASSERT(char_n == total_glyph_count); - NK_ASSERT(range_n == total_range_count); - } - *height = (int)nk_round_up_pow2((nk_uint)*height); - *image_memory = (nk_size)(*width) * (nk_size)(*height); - return nk_true; -} -NK_INTERN void -nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height, - struct nk_font_glyph *glyphs, int glyphs_count, - const struct nk_font_config *config_list, int font_count) -{ - int input_i = 0; - nk_rune glyph_n = 0; - const struct nk_font_config *config_iter; - const struct nk_font_config *it; - - NK_ASSERT(image_memory); - NK_ASSERT(width); - NK_ASSERT(height); - NK_ASSERT(config_list); - NK_ASSERT(baker); - NK_ASSERT(font_count); - NK_ASSERT(glyphs_count); - if (!image_memory || !width || !height || !config_list || - !font_count || !glyphs || !glyphs_count) - return; - - /* second font pass: render glyphs */ - nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height)); - baker->spc.pixels = (unsigned char*)image_memory; - baker->spc.height = (int)height; - for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - config_iter = config_iter->next) { - it = config_iter; - do {const struct nk_font_config *cfg = it; - struct nk_font_bake_data *tmp = &baker->build[input_i++]; - stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - stbtt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, (int)tmp->range_count, tmp->rects); - } while ((it = it->n) != config_iter); - } stbtt_PackEnd(&baker->spc); - - /* third pass: setup font and glyphs */ - for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - config_iter = config_iter->next) { - it = config_iter; - do {nk_size i = 0; - int char_idx = 0; - nk_rune glyph_count = 0; - const struct nk_font_config *cfg = it; - struct nk_font_bake_data *tmp = &baker->build[input_i++]; - struct nk_baked_font *dst_font = cfg->font; - - float font_scale = stbtt_ScaleForPixelHeight(&tmp->info, cfg->size); - int unscaled_ascent, unscaled_descent, unscaled_line_gap; - stbtt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent, - &unscaled_line_gap); - - /* fill baked font */ - if (!cfg->merge_mode) { - dst_font->ranges = cfg->range; - dst_font->height = cfg->size; - dst_font->ascent = ((float)unscaled_ascent * font_scale); - dst_font->descent = ((float)unscaled_descent * font_scale); - dst_font->glyph_offset = glyph_n; - /* - Need to zero this, or it will carry over from a previous - bake, and cause a segfault when accessing glyphs[]. - */ - dst_font->glyph_count = 0; - } - - /* fill own baked font glyph array */ - for (i = 0; i < tmp->range_count; ++i) { - stbtt_pack_range *range = &tmp->ranges[i]; - for (char_idx = 0; char_idx < range->num_chars; char_idx++) - { - nk_rune codepoint = 0; - float dummy_x = 0, dummy_y = 0; - stbtt_aligned_quad q; - struct nk_font_glyph *glyph; - - /* query glyph bounds from stb_truetype */ - const stbtt_packedchar *pc = &range->chardata_for_range[char_idx]; - if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue; - codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx); - stbtt_GetPackedQuad(range->chardata_for_range, (int)width, - (int)height, char_idx, &dummy_x, &dummy_y, &q, 0); - - /* fill own glyph type with data */ - glyph = &glyphs[dst_font->glyph_offset + dst_font->glyph_count + (unsigned int)glyph_count]; - glyph->codepoint = codepoint; - glyph->x0 = q.x0; glyph->y0 = q.y0; - glyph->x1 = q.x1; glyph->y1 = q.y1; - glyph->y0 += (dst_font->ascent + 0.5f); - glyph->y1 += (dst_font->ascent + 0.5f); - glyph->w = glyph->x1 - glyph->x0 + 0.5f; - glyph->h = glyph->y1 - glyph->y0; - - if (cfg->coord_type == NK_COORD_PIXEL) { - glyph->u0 = q.s0 * (float)width; - glyph->v0 = q.t0 * (float)height; - glyph->u1 = q.s1 * (float)width; - glyph->v1 = q.t1 * (float)height; - } else { - glyph->u0 = q.s0; - glyph->v0 = q.t0; - glyph->u1 = q.s1; - glyph->v1 = q.t1; - } - glyph->xadvance = (pc->xadvance + cfg->spacing.x); - if (cfg->pixel_snap) - glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f); - glyph_count++; - } - } - dst_font->glyph_count += glyph_count; - glyph_n += glyph_count; - } while ((it = it->n) != config_iter); - } -} -NK_INTERN void -nk_font_bake_custom_data(void *img_memory, int img_width, int img_height, - struct nk_recti img_dst, const char *texture_data_mask, int tex_width, - int tex_height, char white, char black) -{ - nk_byte *pixels; - int y = 0; - int x = 0; - int n = 0; - - NK_ASSERT(img_memory); - NK_ASSERT(img_width); - NK_ASSERT(img_height); - NK_ASSERT(texture_data_mask); - NK_UNUSED(tex_height); - if (!img_memory || !img_width || !img_height || !texture_data_mask) - return; - - pixels = (nk_byte*)img_memory; - for (y = 0, n = 0; y < tex_height; ++y) { - for (x = 0; x < tex_width; ++x, ++n) { - const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width); - const int off1 = off0 + 1 + tex_width; - pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00; - pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00; - } - } -} -NK_INTERN void -nk_font_bake_convert(void *out_memory, int img_width, int img_height, - const void *in_memory) -{ - int n = 0; - nk_rune *dst; - const nk_byte *src; - - NK_ASSERT(out_memory); - NK_ASSERT(in_memory); - NK_ASSERT(img_width); - NK_ASSERT(img_height); - if (!out_memory || !in_memory || !img_height || !img_width) return; - - dst = (nk_rune*)out_memory; - src = (const nk_byte*)in_memory; - for (n = (int)(img_width * img_height); n > 0; n--) - *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF; -} - -/* ------------------------------------------------------------- - * - * FONT - * - * --------------------------------------------------------------*/ -NK_INTERN float -nk_font_text_width(nk_handle handle, float height, const char *text, int len) -{ - nk_rune unicode; - int text_len = 0; - float text_width = 0; - int glyph_len = 0; - float scale = 0; - - struct nk_font *font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !text || !len) - return 0; - - scale = height/font->info.height; - glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len); - if (!glyph_len) return 0; - while (text_len <= (int)len && glyph_len) { - const struct nk_font_glyph *g; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - g = nk_font_find_glyph(font, unicode); - text_width += g->xadvance * scale; - - /* offset next glyph */ - glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len); - text_len += glyph_len; - } - return text_width; -} -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_INTERN void -nk_font_query_font_glyph(nk_handle handle, float height, - struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) -{ - float scale; - const struct nk_font_glyph *g; - struct nk_font *font; - - NK_ASSERT(glyph); - NK_UNUSED(next_codepoint); - - font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !glyph) - return; - - scale = height/font->info.height; - g = nk_font_find_glyph(font, codepoint); - glyph->width = (g->x1 - g->x0) * scale; - glyph->height = (g->y1 - g->y0) * scale; - glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale); - glyph->xadvance = (g->xadvance * scale); - glyph->uv[0] = nk_vec2(g->u0, g->v0); - glyph->uv[1] = nk_vec2(g->u1, g->v1); -} -#endif -NK_API const struct nk_font_glyph* -nk_font_find_glyph(struct nk_font *font, nk_rune unicode) -{ - int i = 0; - int count; - int total_glyphs = 0; - const struct nk_font_glyph *glyph = 0; - const struct nk_font_config *iter = 0; - - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - NK_ASSERT(font->info.ranges); - if (!font || !font->glyphs) return 0; - - glyph = font->fallback; - iter = font->config; - do {count = nk_range_count(iter->range); - for (i = 0; i < count; ++i) { - nk_rune f = iter->range[(i*2)+0]; - nk_rune t = iter->range[(i*2)+1]; - int diff = (int)((t - f) + 1); - if (unicode >= f && unicode <= t) - return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; - total_glyphs += diff; - } - } while ((iter = iter->n) != font->config); - return glyph; -} -NK_INTERN void -nk_font_init(struct nk_font *font, float pixel_height, - nk_rune fallback_codepoint, struct nk_font_glyph *glyphs, - const struct nk_baked_font *baked_font, nk_handle atlas) -{ - struct nk_baked_font baked; - NK_ASSERT(font); - NK_ASSERT(glyphs); - NK_ASSERT(baked_font); - if (!font || !glyphs || !baked_font) - return; - - baked = *baked_font; - font->fallback = 0; - font->info = baked; - font->scale = (float)pixel_height / (float)font->info.height; - font->glyphs = &glyphs[baked_font->glyph_offset]; - font->texture = atlas; - font->fallback_codepoint = fallback_codepoint; - font->fallback = nk_font_find_glyph(font, fallback_codepoint); - - font->handle.height = font->info.height * font->scale; - font->handle.width = nk_font_text_width; - font->handle.userdata.ptr = font; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - font->handle.query = nk_font_query_font_glyph; - font->handle.texture = font->texture; -#endif -} - -/* --------------------------------------------------------------------------- - * - * DEFAULT FONT - * - * ProggyClean.ttf - * Copyright (c) 2004, 2005 Tristan Grimmer - * MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) - * Download and more information at http://upperbounds.net - *-----------------------------------------------------------------------------*/ -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Woverlength-strings" -#elif defined(__GNUC__) || defined(__GNUG__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverlength-strings" -#endif - -#ifdef NK_INCLUDE_DEFAULT_FONT - -NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] = - "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" - "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" - "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." - "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" - "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" - "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" - "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" - "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" - "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" - "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" - "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" - "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" - "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" - "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" - "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" - "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" - "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" - "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" - "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" - "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" - "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" - ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" - "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" - "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" - "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" - "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" - "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" - "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" - "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" - "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" - "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" - "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" - "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" - "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" - "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" - "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" - "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" - ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" - "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" - "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" - "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" - "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" - "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" - "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" - ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" - "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" - "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" - "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" - "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" - "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; - -#endif /* NK_INCLUDE_DEFAULT_FONT */ - -#define NK_CURSOR_DATA_W 90 -#define NK_CURSOR_DATA_H 27 -NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] = -{ - "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" - "..- -X.....X- X.X - X.X -X.....X - X.....X" - "--- -XXX.XXX- X...X - X...X -X....X - X....X" - "X - X.X - X.....X - X.....X -X...X - X...X" - "XX - X.X -X.......X- X.......X -X..X.X - X.X..X" - "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X" - "X..X - X.X - X.X - X.X -XX X.X - X.X XX" - "X...X - X.X - X.X - XX X.X XX - X.X - X.X " - "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X " - "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X " - "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X " - "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X " - "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X " - "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X " - "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X " - "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " - "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " - "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" - "X.X X..X - -X.......X- X.......X - XX XX - " - "XX X..X - - X.....X - X.....X - X.X X.X - " - " X..X - X...X - X...X - X..X X..X - " - " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - " - "------------ - X - X -X.....................X- " - " ----------------------------------- X...XXXXXXXXXXXXX...X - " - " - X..X X..X - " - " - X.X X.X - " - " - XX XX - " -}; - -#ifdef __clang__ -#pragma clang diagnostic pop -#elif defined(__GNUC__) || defined(__GNUG__) -#pragma GCC diagnostic pop -#endif - -NK_GLOBAL unsigned char *nk__barrier; -NK_GLOBAL unsigned char *nk__barrier2; -NK_GLOBAL unsigned char *nk__barrier3; -NK_GLOBAL unsigned char *nk__barrier4; -NK_GLOBAL unsigned char *nk__dout; - -NK_INTERN unsigned int -nk_decompress_length(unsigned char *input) -{ - return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]); -} -NK_INTERN void -nk__match(unsigned char *data, unsigned int length) -{ - /* INVERSE of memmove... write each byte before copying the next...*/ - NK_ASSERT (nk__dout + length <= nk__barrier); - if (nk__dout + length > nk__barrier) { nk__dout += length; return; } - if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; } - while (length--) *nk__dout++ = *data++; -} -NK_INTERN void -nk__lit(unsigned char *data, unsigned int length) -{ - NK_ASSERT (nk__dout + length <= nk__barrier); - if (nk__dout + length > nk__barrier) { nk__dout += length; return; } - if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; } - NK_MEMCPY(nk__dout, data, length); - nk__dout += length; -} -NK_INTERN unsigned char* -nk_decompress_token(unsigned char *i) -{ - #define nk__in2(x) ((i[x] << 8) + i[(x)+1]) - #define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1)) - #define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1)) - - if (*i >= 0x20) { /* use fewer if's for cases that expand small */ - if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2; - else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3; - else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); - } else { /* more ifs for cases that expand large, since overhead is amortized */ - if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4; - else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5; - else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1); - else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1); - else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5; - else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6; - } - return i; -} -NK_INTERN unsigned int -nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) -{ - const unsigned long ADLER_MOD = 65521; - unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; - unsigned long blocklen, i; - - blocklen = buflen % 5552; - while (buflen) { - for (i=0; i + 7 < blocklen; i += 8) { - s1 += buffer[0]; s2 += s1; - s1 += buffer[1]; s2 += s1; - s1 += buffer[2]; s2 += s1; - s1 += buffer[3]; s2 += s1; - s1 += buffer[4]; s2 += s1; - s1 += buffer[5]; s2 += s1; - s1 += buffer[6]; s2 += s1; - s1 += buffer[7]; s2 += s1; - buffer += 8; - } - for (; i < blocklen; ++i) { - s1 += *buffer++; s2 += s1; - } - - s1 %= ADLER_MOD; s2 %= ADLER_MOD; - buflen -= (unsigned int)blocklen; - blocklen = 5552; - } - return (unsigned int)(s2 << 16) + (unsigned int)s1; -} -NK_INTERN unsigned int -nk_decompress(unsigned char *output, unsigned char *i, unsigned int length) -{ - unsigned int olen; - if (nk__in4(0) != 0x57bC0000) return 0; - if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */ - olen = nk_decompress_length(i); - nk__barrier2 = i; - nk__barrier3 = i+length; - nk__barrier = output + olen; - nk__barrier4 = output; - i += 16; - - nk__dout = output; - for (;;) { - unsigned char *old_i = i; - i = nk_decompress_token(i); - if (i == old_i) { - if (*i == 0x05 && i[1] == 0xfa) { - NK_ASSERT(nk__dout == output + olen); - if (nk__dout != output + olen) return 0; - if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2)) - return 0; - return olen; - } else { - NK_ASSERT(0); /* NOTREACHED */ - return 0; - } - } - NK_ASSERT(nk__dout <= output + olen); - if (nk__dout > output + olen) - return 0; - } -} -NK_INTERN unsigned int -nk_decode_85_byte(char c) -{ - return (unsigned int)((c >= '\\') ? c-36 : c-35); -} -NK_INTERN void -nk_decode_85(unsigned char* dst, const unsigned char* src) -{ - while (*src) - { - unsigned int tmp = - nk_decode_85_byte((char)src[0]) + - 85 * (nk_decode_85_byte((char)src[1]) + - 85 * (nk_decode_85_byte((char)src[2]) + - 85 * (nk_decode_85_byte((char)src[3]) + - 85 * nk_decode_85_byte((char)src[4])))); - - /* we can't assume little-endianess. */ - dst[0] = (unsigned char)((tmp >> 0) & 0xFF); - dst[1] = (unsigned char)((tmp >> 8) & 0xFF); - dst[2] = (unsigned char)((tmp >> 16) & 0xFF); - dst[3] = (unsigned char)((tmp >> 24) & 0xFF); - - src += 5; - dst += 4; - } -} - -/* ------------------------------------------------------------- - * - * FONT ATLAS - * - * --------------------------------------------------------------*/ -NK_API struct nk_font_config -nk_font_config(float pixel_height) -{ - struct nk_font_config cfg; - nk_zero_struct(cfg); - cfg.ttf_blob = 0; - cfg.ttf_size = 0; - cfg.ttf_data_owned_by_atlas = 0; - cfg.size = pixel_height; - cfg.oversample_h = 3; - cfg.oversample_v = 1; - cfg.pixel_snap = 0; - cfg.coord_type = NK_COORD_UV; - cfg.spacing = nk_vec2(0,0); - cfg.range = nk_font_default_glyph_ranges(); - cfg.merge_mode = 0; - cfg.fallback_glyph = '?'; - cfg.font = 0; - cfg.n = 0; - return cfg; -} -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_font_atlas_init_default(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - if (!atlas) return; - nk_zero_struct(*atlas); - atlas->temporary.userdata.ptr = 0; - atlas->temporary.alloc = nk_malloc; - atlas->temporary.free = nk_mfree; - atlas->permanent.userdata.ptr = 0; - atlas->permanent.alloc = nk_malloc; - atlas->permanent.free = nk_mfree; -} -#endif -NK_API void -nk_font_atlas_init(struct nk_font_atlas *atlas, struct nk_allocator *alloc) -{ - NK_ASSERT(atlas); - NK_ASSERT(alloc); - if (!atlas || !alloc) return; - nk_zero_struct(*atlas); - atlas->permanent = *alloc; - atlas->temporary = *alloc; -} -NK_API void -nk_font_atlas_init_custom(struct nk_font_atlas *atlas, - struct nk_allocator *permanent, struct nk_allocator *temporary) -{ - NK_ASSERT(atlas); - NK_ASSERT(permanent); - NK_ASSERT(temporary); - if (!atlas || !permanent || !temporary) return; - nk_zero_struct(*atlas); - atlas->permanent = *permanent; - atlas->temporary = *temporary; -} -NK_API void -nk_font_atlas_begin(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free || - !atlas->temporary.alloc || !atlas->temporary.free) return; - if (atlas->glyphs) { - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - atlas->glyphs = 0; - } - if (atlas->pixel) { - atlas->permanent.free(atlas->permanent.userdata, atlas->pixel); - atlas->pixel = 0; - } -} -NK_API struct nk_font* -nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config) -{ - struct nk_font *font = 0; - struct nk_font_config *cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - - NK_ASSERT(config); - NK_ASSERT(config->ttf_blob); - NK_ASSERT(config->ttf_size); - NK_ASSERT(config->size > 0.0f); - - if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f|| - !atlas->permanent.alloc || !atlas->permanent.free || - !atlas->temporary.alloc || !atlas->temporary.free) - return 0; - - /* allocate font config */ - cfg = (struct nk_font_config*) - atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config)); - NK_MEMCPY(cfg, config, sizeof(*config)); - cfg->n = cfg; - cfg->p = cfg; - - if (!config->merge_mode) { - /* insert font config into list */ - if (!atlas->config) { - atlas->config = cfg; - cfg->next = 0; - } else { - struct nk_font_config *i = atlas->config; - while (i->next) i = i->next; - i->next = cfg; - cfg->next = 0; - } - /* allocate new font */ - font = (struct nk_font*) - atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font)); - NK_ASSERT(font); - nk_zero(font, sizeof(*font)); - if (!font) return 0; - font->config = cfg; - - /* insert font into list */ - if (!atlas->fonts) { - atlas->fonts = font; - font->next = 0; - } else { - struct nk_font *i = atlas->fonts; - while (i->next) i = i->next; - i->next = font; - font->next = 0; - } - cfg->font = &font->info; - } else { - /* extend previously added font */ - struct nk_font *f = 0; - struct nk_font_config *c = 0; - NK_ASSERT(atlas->font_num); - f = atlas->fonts; - c = f->config; - cfg->font = &f->info; - - cfg->n = c; - cfg->p = c->p; - c->p->n = cfg; - c->p = cfg; - } - /* create own copy of .TTF font blob */ - if (!config->ttf_data_owned_by_atlas) { - cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size); - NK_ASSERT(cfg->ttf_blob); - if (!cfg->ttf_blob) { - atlas->font_num++; - return 0; - } - NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size); - cfg->ttf_data_owned_by_atlas = 1; - } - atlas->font_num++; - return font; -} -NK_API struct nk_font* -nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, - nk_size size, float height, const struct nk_font_config *config) -{ - struct nk_font_config cfg; - NK_ASSERT(memory); - NK_ASSERT(size); - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = memory; - cfg.ttf_size = size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 0; - return nk_font_atlas_add(atlas, &cfg); -} -#ifdef NK_INCLUDE_STANDARD_IO -NK_API struct nk_font* -nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, - float height, const struct nk_font_config *config) -{ - nk_size size; - char *memory; - struct nk_font_config cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - if (!atlas || !file_path) return 0; - memory = nk_file_load(file_path, &size, &atlas->permanent); - if (!memory) return 0; - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = memory; - cfg.ttf_size = size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 1; - return nk_font_atlas_add(atlas, &cfg); -} -#endif -NK_API struct nk_font* -nk_font_atlas_add_compressed(struct nk_font_atlas *atlas, - void *compressed_data, nk_size compressed_size, float height, - const struct nk_font_config *config) -{ - unsigned int decompressed_size; - void *decompressed_data; - struct nk_font_config cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(compressed_data); - NK_ASSERT(compressed_size); - if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - decompressed_size = nk_decompress_length((unsigned char*)compressed_data); - decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size); - NK_ASSERT(decompressed_data); - if (!decompressed_data) return 0; - nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data, - (unsigned int)compressed_size); - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = decompressed_data; - cfg.ttf_size = decompressed_size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 1; - return nk_font_atlas_add(atlas, &cfg); -} -NK_API struct nk_font* -nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas, - const char *data_base85, float height, const struct nk_font_config *config) -{ - int compressed_size; - void *compressed_data; - struct nk_font *font; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(data_base85); - if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4; - compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size); - NK_ASSERT(compressed_data); - if (!compressed_data) return 0; - nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85); - font = nk_font_atlas_add_compressed(atlas, compressed_data, - (nk_size)compressed_size, height, config); - atlas->temporary.free(atlas->temporary.userdata, compressed_data); - return font; -} - -#ifdef NK_INCLUDE_DEFAULT_FONT -NK_API struct nk_font* -nk_font_atlas_add_default(struct nk_font_atlas *atlas, - float pixel_height, const struct nk_font_config *config) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - return nk_font_atlas_add_compressed_base85(atlas, - nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config); -} -#endif -NK_API const void* -nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height, - enum nk_font_atlas_format fmt) -{ - int i = 0; - void *tmp = 0; - nk_size tmp_size, img_size; - struct nk_font *font_iter; - struct nk_font_baker *baker; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(width); - NK_ASSERT(height); - if (!atlas || !width || !height || - !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - -#ifdef NK_INCLUDE_DEFAULT_FONT - /* no font added so just use default font */ - if (!atlas->font_num) - atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0); -#endif - NK_ASSERT(atlas->font_num); - if (!atlas->font_num) return 0; - - /* allocate temporary baker memory required for the baking process */ - nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num); - tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size); - NK_ASSERT(tmp); - if (!tmp) goto failed; - memset(tmp,0,tmp_size); - - /* allocate glyph memory for all fonts */ - baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary); - atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc( - atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count); - NK_ASSERT(atlas->glyphs); - if (!atlas->glyphs) - goto failed; - - /* pack all glyphs into a tight fit space */ - atlas->custom.w = (NK_CURSOR_DATA_W*2)+1; - atlas->custom.h = NK_CURSOR_DATA_H + 1; - if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom, - atlas->config, atlas->font_num, &atlas->temporary)) - goto failed; - - /* allocate memory for the baked image font atlas */ - atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size); - NK_ASSERT(atlas->pixel); - if (!atlas->pixel) - goto failed; - - /* bake glyphs and custom white pixel into image */ - nk_font_bake(baker, atlas->pixel, *width, *height, - atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num); - nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom, - nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X'); - - if (fmt == NK_FONT_ATLAS_RGBA32) { - /* convert alpha8 image into rgba32 image */ - void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0, - (nk_size)(*width * *height * 4)); - NK_ASSERT(img_rgba); - if (!img_rgba) goto failed; - nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel); - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = img_rgba; - } - atlas->tex_width = *width; - atlas->tex_height = *height; - - /* initialize each font */ - for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { - struct nk_font *font = font_iter; - struct nk_font_config *config = font->config; - nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs, - config->font, nk_handle_ptr(0)); - } - - /* initialize each cursor */ - {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = { - /* Pos Size Offset */ - {{ 0, 3}, {12,19}, { 0, 0}}, - {{13, 0}, { 7,16}, { 4, 8}}, - {{31, 0}, {23,23}, {11,11}}, - {{21, 0}, { 9, 23}, { 5,11}}, - {{55,18}, {23, 9}, {11, 5}}, - {{73, 0}, {17,17}, { 9, 9}}, - {{55, 0}, {17,17}, { 9, 9}} - }; - for (i = 0; i < NK_CURSOR_COUNT; ++i) { - struct nk_cursor *cursor = &atlas->cursors[i]; - cursor->img.w = (unsigned short)*width; - cursor->img.h = (unsigned short)*height; - cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x); - cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y); - cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x; - cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y; - cursor->size = nk_cursor_data[i][1]; - cursor->offset = nk_cursor_data[i][2]; - }} - /* free temporary memory */ - atlas->temporary.free(atlas->temporary.userdata, tmp); - return atlas->pixel; - -failed: - /* error so cleanup all memory */ - if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp); - if (atlas->glyphs) { - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - atlas->glyphs = 0; - } - if (atlas->pixel) { - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = 0; - } - return 0; -} -NK_API void -nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture, - struct nk_draw_null_texture *null) -{ - int i = 0; - struct nk_font *font_iter; - NK_ASSERT(atlas); - if (!atlas) { - if (!null) return; - null->texture = texture; - null->uv = nk_vec2(0.5f,0.5f); - } - if (null) { - null->texture = texture; - null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width; - null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height; - } - for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { - font_iter->texture = texture; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - font_iter->handle.texture = texture; -#endif - } - for (i = 0; i < NK_CURSOR_COUNT; ++i) - atlas->cursors[i].img.handle = texture; - - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = 0; - atlas->tex_width = 0; - atlas->tex_height = 0; - atlas->custom.x = 0; - atlas->custom.y = 0; - atlas->custom.w = 0; - atlas->custom.h = 0; -} -NK_API void -nk_font_atlas_cleanup(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - if (atlas->config) { - struct nk_font_config *iter; - for (iter = atlas->config; iter; iter = iter->next) { - struct nk_font_config *i; - for (i = iter->n; i != iter; i = i->n) { - atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob); - i->ttf_blob = 0; - } - atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); - iter->ttf_blob = 0; - } - } -} -NK_API void -nk_font_atlas_clear(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - - if (atlas->config) { - struct nk_font_config *iter, *next; - for (iter = atlas->config; iter; iter = next) { - struct nk_font_config *i, *n; - for (i = iter->n; i != iter; i = n) { - n = i->n; - if (i->ttf_blob) - atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob); - atlas->permanent.free(atlas->permanent.userdata, i); - } - next = iter->next; - if (i->ttf_blob) - atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); - atlas->permanent.free(atlas->permanent.userdata, iter); - } - atlas->config = 0; - } - if (atlas->fonts) { - struct nk_font *iter, *next; - for (iter = atlas->fonts; iter; iter = next) { - next = iter->next; - atlas->permanent.free(atlas->permanent.userdata, iter); - } - atlas->fonts = 0; - } - if (atlas->glyphs) - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - nk_zero_struct(*atlas); -} -#endif - - - - - -/* =============================================================== - * - * INPUT - * - * ===============================================================*/ -NK_API void -nk_input_begin(struct nk_context *ctx) -{ - int i; - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - for (i = 0; i < NK_BUTTON_MAX; ++i) - in->mouse.buttons[i].clicked = 0; - - in->keyboard.text_len = 0; - in->mouse.scroll_delta = nk_vec2(0,0); - in->mouse.prev.x = in->mouse.pos.x; - in->mouse.prev.y = in->mouse.pos.y; - in->mouse.delta.x = 0; - in->mouse.delta.y = 0; - for (i = 0; i < NK_KEY_MAX; i++) - in->keyboard.keys[i].clicked = 0; -} -NK_API void -nk_input_end(struct nk_context *ctx) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->mouse.grab) - in->mouse.grab = 0; - if (in->mouse.ungrab) { - in->mouse.grabbed = 0; - in->mouse.ungrab = 0; - in->mouse.grab = 0; - } -} -NK_API void -nk_input_motion(struct nk_context *ctx, int x, int y) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - in->mouse.pos.x = (float)x; - in->mouse.pos.y = (float)y; - in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x; - in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y; -} -NK_API void -nk_input_key(struct nk_context *ctx, enum nk_keys key, nk_bool down) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; -#ifdef NK_KEYSTATE_BASED_INPUT - if (in->keyboard.keys[key].down != down) - in->keyboard.keys[key].clicked++; -#else - in->keyboard.keys[key].clicked++; -#endif - in->keyboard.keys[key].down = down; -} -NK_API void -nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, nk_bool down) -{ - struct nk_mouse_button *btn; - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->mouse.buttons[id].down == down) return; - - btn = &in->mouse.buttons[id]; - btn->clicked_pos.x = (float)x; - btn->clicked_pos.y = (float)y; - btn->down = down; - btn->clicked++; -} -NK_API void -nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val) -{ - NK_ASSERT(ctx); - if (!ctx) return; - ctx->input.mouse.scroll_delta.x += val.x; - ctx->input.mouse.scroll_delta.y += val.y; -} -NK_API void -nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph) -{ - int len = 0; - nk_rune unicode; - struct nk_input *in; - - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - - len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE); - if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) { - nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len], - NK_INPUT_MAX - in->keyboard.text_len); - in->keyboard.text_len += len; - } -} -NK_API void -nk_input_char(struct nk_context *ctx, char c) -{ - nk_glyph glyph; - NK_ASSERT(ctx); - if (!ctx) return; - glyph[0] = c; - nk_input_glyph(ctx, glyph); -} -NK_API void -nk_input_unicode(struct nk_context *ctx, nk_rune unicode) -{ - nk_glyph rune; - NK_ASSERT(ctx); - if (!ctx) return; - nk_utf_encode(unicode, rune, NK_UTF_SIZE); - nk_input_glyph(ctx, rune); -} -NK_API nk_bool -nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false; -} -NK_API nk_bool -nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)) - return nk_false; - return nk_true; -} -NK_API nk_bool -nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b, nk_bool down) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down); -} -NK_API nk_bool -nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) && - btn->clicked) ? nk_true : nk_false; -} -NK_API nk_bool -nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b, nk_bool down) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) && - btn->clicked) ? nk_true : nk_false; -} -NK_API nk_bool -nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b) -{ - int i, down = 0; - for (i = 0; i < NK_BUTTON_MAX; ++i) - down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b); - return down; -} -NK_API nk_bool -nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect) -{ - if (!i) return nk_false; - return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h); -} -NK_API nk_bool -nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect) -{ - if (!i) return nk_false; - return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h); -} -NK_API nk_bool -nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect) -{ - if (!i) return nk_false; - if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false; - return nk_input_is_mouse_click_in_rect(i, id, rect); -} -NK_API nk_bool -nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id) -{ - if (!i) return nk_false; - return i->mouse.buttons[id].down; -} -NK_API nk_bool -nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id) -{ - const struct nk_mouse_button *b; - if (!i) return nk_false; - b = &i->mouse.buttons[id]; - if (b->down && b->clicked) - return nk_true; - return nk_false; -} -NK_API nk_bool -nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id) -{ - if (!i) return nk_false; - return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked); -} -NK_API nk_bool -nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if ((k->down && k->clicked) || (!k->down && k->clicked >= 2)) - return nk_true; - return nk_false; -} -NK_API nk_bool -nk_input_is_key_released(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if ((!k->down && k->clicked) || (k->down && k->clicked >= 2)) - return nk_true; - return nk_false; -} -NK_API nk_bool -nk_input_is_key_down(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if (k->down) return nk_true; - return nk_false; -} - - - - - -/* =============================================================== - * - * STYLE - * - * ===============================================================*/ -NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);} -#define NK_COLOR_MAP(NK_COLOR)\ - NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \ - NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \ - NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \ - NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \ - NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \ - NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \ - NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \ - NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \ - NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \ - NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT, 255, 0, 0, 255) \ - NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, 150,150,150,255) \ - NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255) - -NK_GLOBAL const struct nk_color -nk_default_color_style[NK_COLOR_COUNT] = { -#define NK_COLOR(a,b,c,d,e) {b,c,d,e}, - NK_COLOR_MAP(NK_COLOR) -#undef NK_COLOR -}; -NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = { -#define NK_COLOR(a,b,c,d,e) #a, - NK_COLOR_MAP(NK_COLOR) -#undef NK_COLOR -}; - -NK_API const char* -nk_style_get_color_by_name(enum nk_style_colors c) -{ - return nk_color_names[c]; -} -NK_API struct nk_style_item -nk_style_item_image(struct nk_image img) -{ - struct nk_style_item i; - i.type = NK_STYLE_ITEM_IMAGE; - i.data.image = img; - return i; -} -NK_API struct nk_style_item -nk_style_item_color(struct nk_color col) -{ - struct nk_style_item i; - i.type = NK_STYLE_ITEM_COLOR; - i.data.color = col; - return i; -} -NK_API struct nk_style_item -nk_style_item_hide(void) -{ - struct nk_style_item i; - i.type = NK_STYLE_ITEM_COLOR; - i.data.color = nk_rgba(0,0,0,0); - return i; -} -NK_API void -nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) -{ - struct nk_style *style; - struct nk_style_text *text; - struct nk_style_button *button; - struct nk_style_toggle *toggle; - struct nk_style_selectable *select; - struct nk_style_slider *slider; - struct nk_style_progress *prog; - struct nk_style_scrollbar *scroll; - struct nk_style_edit *edit; - struct nk_style_property *property; - struct nk_style_combo *combo; - struct nk_style_chart *chart; - struct nk_style_tab *tab; - struct nk_style_window *win; - - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - table = (!table) ? nk_default_color_style: table; - - /* default text */ - text = &style->text; - text->color = table[NK_COLOR_TEXT]; - text->padding = nk_vec2(0,0); - - /* default button */ - button = &style->button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]); - button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); - button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); - button->border_color = table[NK_COLOR_BORDER]; - button->text_background = table[NK_COLOR_BUTTON]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->image_padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f, 0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 4.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* contextual button */ - button = &style->contextual_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); - button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); - button->border_color = table[NK_COLOR_WINDOW]; - button->text_background = table[NK_COLOR_WINDOW]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* menu button */ - button = &style->menu_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->border_color = table[NK_COLOR_WINDOW]; - button->text_background = table[NK_COLOR_WINDOW]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 1.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* checkbox toggle */ - toggle = &style->checkbox; - nk_zero_struct(*toggle); - toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); - toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->userdata = nk_handle_ptr(0); - toggle->text_background = table[NK_COLOR_WINDOW]; - toggle->text_normal = table[NK_COLOR_TEXT]; - toggle->text_hover = table[NK_COLOR_TEXT]; - toggle->text_active = table[NK_COLOR_TEXT]; - toggle->padding = nk_vec2(2.0f, 2.0f); - toggle->touch_padding = nk_vec2(0,0); - toggle->border_color = nk_rgba(0,0,0,0); - toggle->border = 0.0f; - toggle->spacing = 4; - - /* option toggle */ - toggle = &style->option; - nk_zero_struct(*toggle); - toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); - toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->userdata = nk_handle_ptr(0); - toggle->text_background = table[NK_COLOR_WINDOW]; - toggle->text_normal = table[NK_COLOR_TEXT]; - toggle->text_hover = table[NK_COLOR_TEXT]; - toggle->text_active = table[NK_COLOR_TEXT]; - toggle->padding = nk_vec2(3.0f, 3.0f); - toggle->touch_padding = nk_vec2(0,0); - toggle->border_color = nk_rgba(0,0,0,0); - toggle->border = 0.0f; - toggle->spacing = 4; - - /* selectable */ - select = &style->selectable; - nk_zero_struct(*select); - select->normal = nk_style_item_color(table[NK_COLOR_SELECT]); - select->hover = nk_style_item_color(table[NK_COLOR_SELECT]); - select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]); - select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->text_normal = table[NK_COLOR_TEXT]; - select->text_hover = table[NK_COLOR_TEXT]; - select->text_pressed = table[NK_COLOR_TEXT]; - select->text_normal_active = table[NK_COLOR_TEXT]; - select->text_hover_active = table[NK_COLOR_TEXT]; - select->text_pressed_active = table[NK_COLOR_TEXT]; - select->padding = nk_vec2(2.0f,2.0f); - select->image_padding = nk_vec2(2.0f,2.0f); - select->touch_padding = nk_vec2(0,0); - select->userdata = nk_handle_ptr(0); - select->rounding = 0.0f; - select->draw_begin = 0; - select->draw_end = 0; - - /* slider */ - slider = &style->slider; - nk_zero_struct(*slider); - slider->normal = nk_style_item_hide(); - slider->hover = nk_style_item_hide(); - slider->active = nk_style_item_hide(); - slider->bar_normal = table[NK_COLOR_SLIDER]; - slider->bar_hover = table[NK_COLOR_SLIDER]; - slider->bar_active = table[NK_COLOR_SLIDER]; - slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR]; - slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); - slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); - slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); - slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT; - slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT; - slider->cursor_size = nk_vec2(16,16); - slider->padding = nk_vec2(2,2); - slider->spacing = nk_vec2(2,2); - slider->userdata = nk_handle_ptr(0); - slider->show_buttons = nk_false; - slider->bar_height = 8; - slider->rounding = 0; - slider->draw_begin = 0; - slider->draw_end = 0; - - /* slider buttons */ - button = &style->slider.inc_button; - button->normal = nk_style_item_color(nk_rgb(40,40,40)); - button->hover = nk_style_item_color(nk_rgb(42,42,42)); - button->active = nk_style_item_color(nk_rgb(44,44,44)); - button->border_color = nk_rgb(65,65,65); - button->text_background = nk_rgb(40,40,40); - button->text_normal = nk_rgb(175,175,175); - button->text_hover = nk_rgb(175,175,175); - button->text_active = nk_rgb(175,175,175); - button->padding = nk_vec2(8.0f,8.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->slider.dec_button = style->slider.inc_button; - - /* progressbar */ - prog = &style->progress; - nk_zero_struct(*prog); - prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); - prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); - prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); - prog->border_color = nk_rgba(0,0,0,0); - prog->cursor_border_color = nk_rgba(0,0,0,0); - prog->userdata = nk_handle_ptr(0); - prog->padding = nk_vec2(4,4); - prog->rounding = 0; - prog->border = 0; - prog->cursor_rounding = 0; - prog->cursor_border = 0; - prog->draw_begin = 0; - prog->draw_end = 0; - - /* scrollbars */ - scroll = &style->scrollh; - nk_zero_struct(*scroll); - scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]); - scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]); - scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]); - scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID; - scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID; - scroll->userdata = nk_handle_ptr(0); - scroll->border_color = table[NK_COLOR_SCROLLBAR]; - scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR]; - scroll->padding = nk_vec2(0,0); - scroll->show_buttons = nk_false; - scroll->border = 0; - scroll->rounding = 0; - scroll->border_cursor = 0; - scroll->rounding_cursor = 0; - scroll->draw_begin = 0; - scroll->draw_end = 0; - style->scrollv = style->scrollh; - - /* scrollbars buttons */ - button = &style->scrollh.inc_button; - button->normal = nk_style_item_color(nk_rgb(40,40,40)); - button->hover = nk_style_item_color(nk_rgb(42,42,42)); - button->active = nk_style_item_color(nk_rgb(44,44,44)); - button->border_color = nk_rgb(65,65,65); - button->text_background = nk_rgb(40,40,40); - button->text_normal = nk_rgb(175,175,175); - button->text_hover = nk_rgb(175,175,175); - button->text_active = nk_rgb(175,175,175); - button->padding = nk_vec2(4.0f,4.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->scrollh.dec_button = style->scrollh.inc_button; - style->scrollv.inc_button = style->scrollh.inc_button; - style->scrollv.dec_button = style->scrollh.inc_button; - - /* edit */ - edit = &style->edit; - nk_zero_struct(*edit); - edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->active = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->cursor_normal = table[NK_COLOR_TEXT]; - edit->cursor_hover = table[NK_COLOR_TEXT]; - edit->cursor_text_normal= table[NK_COLOR_EDIT]; - edit->cursor_text_hover = table[NK_COLOR_EDIT]; - edit->border_color = table[NK_COLOR_BORDER]; - edit->text_normal = table[NK_COLOR_TEXT]; - edit->text_hover = table[NK_COLOR_TEXT]; - edit->text_active = table[NK_COLOR_TEXT]; - edit->selected_normal = table[NK_COLOR_TEXT]; - edit->selected_hover = table[NK_COLOR_TEXT]; - edit->selected_text_normal = table[NK_COLOR_EDIT]; - edit->selected_text_hover = table[NK_COLOR_EDIT]; - edit->scrollbar_size = nk_vec2(10,10); - edit->scrollbar = style->scrollv; - edit->padding = nk_vec2(4,4); - edit->row_padding = 2; - edit->cursor_size = 4; - edit->border = 1; - edit->rounding = 0; - - /* property */ - property = &style->property; - nk_zero_struct(*property); - property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->border_color = table[NK_COLOR_BORDER]; - property->label_normal = table[NK_COLOR_TEXT]; - property->label_hover = table[NK_COLOR_TEXT]; - property->label_active = table[NK_COLOR_TEXT]; - property->sym_left = NK_SYMBOL_TRIANGLE_LEFT; - property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT; - property->userdata = nk_handle_ptr(0); - property->padding = nk_vec2(4,4); - property->border = 1; - property->rounding = 10; - property->draw_begin = 0; - property->draw_end = 0; - - /* property buttons */ - button = &style->property.dec_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_PROPERTY]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->property.inc_button = style->property.dec_button; - - /* property edit */ - edit = &style->property.edit; - nk_zero_struct(*edit); - edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->border_color = nk_rgba(0,0,0,0); - edit->cursor_normal = table[NK_COLOR_TEXT]; - edit->cursor_hover = table[NK_COLOR_TEXT]; - edit->cursor_text_normal= table[NK_COLOR_EDIT]; - edit->cursor_text_hover = table[NK_COLOR_EDIT]; - edit->text_normal = table[NK_COLOR_TEXT]; - edit->text_hover = table[NK_COLOR_TEXT]; - edit->text_active = table[NK_COLOR_TEXT]; - edit->selected_normal = table[NK_COLOR_TEXT]; - edit->selected_hover = table[NK_COLOR_TEXT]; - edit->selected_text_normal = table[NK_COLOR_EDIT]; - edit->selected_text_hover = table[NK_COLOR_EDIT]; - edit->padding = nk_vec2(0,0); - edit->cursor_size = 8; - edit->border = 0; - edit->rounding = 0; - - /* chart */ - chart = &style->chart; - nk_zero_struct(*chart); - chart->background = nk_style_item_color(table[NK_COLOR_CHART]); - chart->border_color = table[NK_COLOR_BORDER]; - chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT]; - chart->color = table[NK_COLOR_CHART_COLOR]; - chart->padding = nk_vec2(4,4); - chart->border = 0; - chart->rounding = 0; - - /* combo */ - combo = &style->combo; - combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->active = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->border_color = table[NK_COLOR_BORDER]; - combo->label_normal = table[NK_COLOR_TEXT]; - combo->label_hover = table[NK_COLOR_TEXT]; - combo->label_active = table[NK_COLOR_TEXT]; - combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN; - combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN; - combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN; - combo->content_padding = nk_vec2(4,4); - combo->button_padding = nk_vec2(0,4); - combo->spacing = nk_vec2(4,0); - combo->border = 1; - combo->rounding = 0; - - /* combo button */ - button = &style->combo.button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_COMBO]); - button->hover = nk_style_item_color(table[NK_COLOR_COMBO]); - button->active = nk_style_item_color(table[NK_COLOR_COMBO]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_COMBO]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* tab */ - tab = &style->tab; - tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - tab->border_color = table[NK_COLOR_BORDER]; - tab->text = table[NK_COLOR_TEXT]; - tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT; - tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN; - tab->padding = nk_vec2(4,4); - tab->spacing = nk_vec2(4,4); - tab->indent = 10.0f; - tab->border = 1; - tab->rounding = 0; - - /* tab button */ - button = &style->tab.tab_minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_TAB_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->tab.tab_maximize_button =*button; - - /* node button */ - button = &style->tab.node_minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_TAB_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->tab.node_maximize_button =*button; - - /* window header */ - win = &style->window; - win->header.align = NK_HEADER_RIGHT; - win->header.close_symbol = NK_SYMBOL_X; - win->header.minimize_symbol = NK_SYMBOL_MINUS; - win->header.maximize_symbol = NK_SYMBOL_PLUS; - win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.label_normal = table[NK_COLOR_TEXT]; - win->header.label_hover = table[NK_COLOR_TEXT]; - win->header.label_active = table[NK_COLOR_TEXT]; - win->header.label_padding = nk_vec2(4,4); - win->header.padding = nk_vec2(4,4); - win->header.spacing = nk_vec2(0,0); - - /* window header close button */ - button = &style->window.header.close_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* window header minimize button */ - button = &style->window.header.minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* window */ - win->background = table[NK_COLOR_WINDOW]; - win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]); - win->border_color = table[NK_COLOR_BORDER]; - win->popup_border_color = table[NK_COLOR_BORDER]; - win->combo_border_color = table[NK_COLOR_BORDER]; - win->contextual_border_color = table[NK_COLOR_BORDER]; - win->menu_border_color = table[NK_COLOR_BORDER]; - win->group_border_color = table[NK_COLOR_BORDER]; - win->tooltip_border_color = table[NK_COLOR_BORDER]; - win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]); - - win->rounding = 0.0f; - win->spacing = nk_vec2(4,4); - win->scrollbar_size = nk_vec2(10,10); - win->min_size = nk_vec2(64,64); - - win->combo_border = 1.0f; - win->contextual_border = 1.0f; - win->menu_border = 1.0f; - win->group_border = 1.0f; - win->tooltip_border = 1.0f; - win->popup_border = 1.0f; - win->border = 2.0f; - win->min_row_height_padding = 8; - - win->padding = nk_vec2(4,4); - win->group_padding = nk_vec2(4,4); - win->popup_padding = nk_vec2(4,4); - win->combo_padding = nk_vec2(4,4); - win->contextual_padding = nk_vec2(4,4); - win->menu_padding = nk_vec2(4,4); - win->tooltip_padding = nk_vec2(4,4); -} -NK_API void -nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_style *style; - NK_ASSERT(ctx); - - if (!ctx) return; - style = &ctx->style; - style->font = font; - ctx->stacks.fonts.head = 0; - if (ctx->current) - nk_layout_reset_min_row_height(ctx); -} -NK_API nk_bool -nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_config_stack_user_font *font_stack; - struct nk_config_stack_user_font_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - font_stack = &ctx->stacks.fonts; - NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements)); - if (font_stack->head >= (int)NK_LEN(font_stack->elements)) - return 0; - - element = &font_stack->elements[font_stack->head++]; - element->address = &ctx->style.font; - element->old_value = ctx->style.font; - ctx->style.font = font; - return 1; -} -NK_API nk_bool -nk_style_pop_font(struct nk_context *ctx) -{ - struct nk_config_stack_user_font *font_stack; - struct nk_config_stack_user_font_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - font_stack = &ctx->stacks.fonts; - NK_ASSERT(font_stack->head > 0); - if (font_stack->head < 1) - return 0; - - element = &font_stack->elements[--font_stack->head]; - *element->address = element->old_value; - return 1; -} -#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \ -nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\ -{\ - struct nk_config_stack_##type * type_stack;\ - struct nk_config_stack_##type##_element *element;\ - NK_ASSERT(ctx);\ - if (!ctx) return 0;\ - type_stack = &ctx->stacks.stack;\ - NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\ - if (type_stack->head >= (int)NK_LEN(type_stack->elements))\ - return 0;\ - element = &type_stack->elements[type_stack->head++];\ - element->address = address;\ - element->old_value = *address;\ - *address = value;\ - return 1;\ -} -#define NK_STYLE_POP_IMPLEMENATION(type, stack) \ -nk_style_pop_##type(struct nk_context *ctx)\ -{\ - struct nk_config_stack_##type *type_stack;\ - struct nk_config_stack_##type##_element *element;\ - NK_ASSERT(ctx);\ - if (!ctx) return 0;\ - type_stack = &ctx->stacks.stack;\ - NK_ASSERT(type_stack->head > 0);\ - if (type_stack->head < 1)\ - return 0;\ - element = &type_stack->elements[--type_stack->head];\ - *element->address = element->old_value;\ - return 1;\ -} -NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items) -NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats) -NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors) -NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags) -NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors) - -NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(style_item, style_items) -NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(float,floats) -NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(vec2, vectors) -NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(flags,flags) -NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(color,colors) - -NK_API nk_bool -nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c) -{ - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return 0; - style = &ctx->style; - if (style->cursors[c]) { - style->cursor_active = style->cursors[c]; - return 1; - } - return 0; -} -NK_API void -nk_style_show_cursor(struct nk_context *ctx) -{ - ctx->style.cursor_visible = nk_true; -} -NK_API void -nk_style_hide_cursor(struct nk_context *ctx) -{ - ctx->style.cursor_visible = nk_false; -} -NK_API void -nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor, - const struct nk_cursor *c) -{ - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - style->cursors[cursor] = c; -} -NK_API void -nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors) -{ - int i = 0; - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - for (i = 0; i < NK_CURSOR_COUNT; ++i) - style->cursors[i] = &cursors[i]; - style->cursor_visible = nk_true; -} - - - - - -/* ============================================================== - * - * CONTEXT - * - * ===============================================================*/ -NK_INTERN void -nk_setup(struct nk_context *ctx, const struct nk_user_font *font) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_zero_struct(*ctx); - nk_style_default(ctx); - ctx->seq = 1; - if (font) ctx->style.font = font; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_draw_list_init(&ctx->draw_list); -#endif -} -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API nk_bool -nk_init_default(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - return nk_init(ctx, &alloc, font); -} -#endif -NK_API nk_bool -nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, - const struct nk_user_font *font) -{ - NK_ASSERT(memory); - if (!memory) return 0; - nk_setup(ctx, font); - nk_buffer_init_fixed(&ctx->memory, memory, size); - ctx->use_pool = nk_false; - return 1; -} -NK_API nk_bool -nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, - struct nk_buffer *pool, const struct nk_user_font *font) -{ - NK_ASSERT(cmds); - NK_ASSERT(pool); - if (!cmds || !pool) return 0; - - nk_setup(ctx, font); - ctx->memory = *cmds; - if (pool->type == NK_BUFFER_FIXED) { - /* take memory from buffer and alloc fixed pool */ - nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size); - } else { - /* create dynamic pool from buffer allocator */ - struct nk_allocator *alloc = &pool->pool; - nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); - } - ctx->use_pool = nk_true; - return 1; -} -NK_API nk_bool -nk_init(struct nk_context *ctx, struct nk_allocator *alloc, - const struct nk_user_font *font) -{ - NK_ASSERT(alloc); - if (!alloc) return 0; - nk_setup(ctx, font); - nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE); - nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); - ctx->use_pool = nk_true; - return 1; -} -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void -nk_set_user_data(struct nk_context *ctx, nk_handle handle) -{ - if (!ctx) return; - ctx->userdata = handle; - if (ctx->current) - ctx->current->buffer.userdata = handle; -} -#endif -NK_API void -nk_free(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_buffer_free(&ctx->memory); - if (ctx->use_pool) - nk_pool_free(&ctx->pool); - - nk_zero(&ctx->input, sizeof(ctx->input)); - nk_zero(&ctx->style, sizeof(ctx->style)); - nk_zero(&ctx->memory, sizeof(ctx->memory)); - - ctx->seq = 0; - ctx->build = 0; - ctx->begin = 0; - ctx->end = 0; - ctx->active = 0; - ctx->current = 0; - ctx->freelist = 0; - ctx->count = 0; -} -NK_API void -nk_clear(struct nk_context *ctx) -{ - struct nk_window *iter; - struct nk_window *next; - NK_ASSERT(ctx); - - if (!ctx) return; - if (ctx->use_pool) - nk_buffer_clear(&ctx->memory); - else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT); - - ctx->build = 0; - ctx->memory.calls = 0; - ctx->last_widget_state = 0; - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; - NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay)); - - /* garbage collector */ - iter = ctx->begin; - while (iter) { - /* make sure valid minimized windows do not get removed */ - if ((iter->flags & NK_WINDOW_MINIMIZED) && - !(iter->flags & NK_WINDOW_CLOSED) && - iter->seq == ctx->seq) { - iter = iter->next; - continue; - } - /* remove hotness from hidden or closed windows*/ - if (((iter->flags & NK_WINDOW_HIDDEN) || - (iter->flags & NK_WINDOW_CLOSED)) && - iter == ctx->active) { - ctx->active = iter->prev; - ctx->end = iter->prev; - if (!ctx->end) - ctx->begin = 0; - if (ctx->active) - ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM; - } - /* free unused popup windows */ - if (iter->popup.win && iter->popup.win->seq != ctx->seq) { - nk_free_window(ctx, iter->popup.win); - iter->popup.win = 0; - } - /* remove unused window state tables */ - {struct nk_table *n, *it = iter->tables; - while (it) { - n = it->next; - if (it->seq != ctx->seq) { - nk_remove_table(iter, it); - nk_zero(it, sizeof(union nk_page_data)); - nk_free_table(ctx, it); - if (it == iter->tables) - iter->tables = n; - } it = n; - }} - /* window itself is not used anymore so free */ - if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) { - next = iter->next; - nk_remove_window(ctx, iter); - nk_free_window(ctx, iter); - iter = next; - } else iter = iter->next; - } - ctx->seq++; -} -NK_LIB void -nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) -{ - NK_ASSERT(ctx); - NK_ASSERT(buffer); - if (!ctx || !buffer) return; - buffer->begin = ctx->memory.allocated; - buffer->end = buffer->begin; - buffer->last = buffer->begin; - buffer->clip = nk_null_rect; -} -NK_LIB void -nk_start(struct nk_context *ctx, struct nk_window *win) -{ - NK_ASSERT(ctx); - NK_ASSERT(win); - nk_start_buffer(ctx, &win->buffer); -} -NK_LIB void -nk_start_popup(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - - /* save buffer fill state for popup */ - buf = &win->popup.buf; - buf->begin = win->buffer.end; - buf->end = win->buffer.end; - buf->parent = win->buffer.last; - buf->last = buf->begin; - buf->active = nk_true; -} -NK_LIB void -nk_finish_popup(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - - buf = &win->popup.buf; - buf->last = win->buffer.last; - buf->end = win->buffer.end; -} -NK_LIB void -nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) -{ - NK_ASSERT(ctx); - NK_ASSERT(buffer); - if (!ctx || !buffer) return; - buffer->end = ctx->memory.allocated; -} -NK_LIB void -nk_finish(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - struct nk_command *parent_last; - void *memory; - - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - nk_finish_buffer(ctx, &win->buffer); - if (!win->popup.buf.active) return; - - buf = &win->popup.buf; - memory = ctx->memory.memory.ptr; - parent_last = nk_ptr_add(struct nk_command, memory, buf->parent); - parent_last->next = buf->end; -} -NK_LIB void -nk_build(struct nk_context *ctx) -{ - struct nk_window *it = 0; - struct nk_command *cmd = 0; - nk_byte *buffer = 0; - - /* draw cursor overlay */ - if (!ctx->style.cursor_active) - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; - if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) { - struct nk_rect mouse_bounds; - const struct nk_cursor *cursor = ctx->style.cursor_active; - nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF); - nk_start_buffer(ctx, &ctx->overlay); - - mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x; - mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y; - mouse_bounds.w = cursor->size.x; - mouse_bounds.h = cursor->size.y; - - nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white); - nk_finish_buffer(ctx, &ctx->overlay); - } - /* build one big draw command list out of all window buffers */ - it = ctx->begin; - buffer = (nk_byte*)ctx->memory.memory.ptr; - while (it != 0) { - struct nk_window *next = it->next; - if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)|| - it->seq != ctx->seq) - goto cont; - - cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last); - while (next && ((next->buffer.last == next->buffer.begin) || - (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq)) - next = next->next; /* skip empty command buffers */ - - if (next) cmd->next = next->buffer.begin; - cont: it = next; - } - /* append all popup draw commands into lists */ - it = ctx->begin; - while (it != 0) { - struct nk_window *next = it->next; - struct nk_popup_buffer *buf; - if (!it->popup.buf.active) - goto skip; - - buf = &it->popup.buf; - cmd->next = buf->begin; - cmd = nk_ptr_add(struct nk_command, buffer, buf->last); - buf->active = nk_false; - skip: it = next; - } - if (cmd) { - /* append overlay commands */ - if (ctx->overlay.end != ctx->overlay.begin) - cmd->next = ctx->overlay.begin; - else cmd->next = ctx->memory.allocated; - } -} -NK_API const struct nk_command* -nk__begin(struct nk_context *ctx) -{ - struct nk_window *iter; - nk_byte *buffer; - NK_ASSERT(ctx); - if (!ctx) return 0; - if (!ctx->count) return 0; - - buffer = (nk_byte*)ctx->memory.memory.ptr; - if (!ctx->build) { - nk_build(ctx); - ctx->build = nk_true; - } - iter = ctx->begin; - while (iter && ((iter->buffer.begin == iter->buffer.end) || - (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq)) - iter = iter->next; - if (!iter) return 0; - return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin); -} - -NK_API const struct nk_command* -nk__next(struct nk_context *ctx, const struct nk_command *cmd) -{ - nk_byte *buffer; - const struct nk_command *next; - NK_ASSERT(ctx); - if (!ctx || !cmd || !ctx->count) return 0; - if (cmd->next >= ctx->memory.allocated) return 0; - buffer = (nk_byte*)ctx->memory.memory.ptr; - next = nk_ptr_add_const(struct nk_command, buffer, cmd->next); - return next; -} - - - - - - -/* =============================================================== - * - * POOL - * - * ===============================================================*/ -NK_LIB void -nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, - unsigned int capacity) -{ - NK_ASSERT(capacity >= 1); - nk_zero(pool, sizeof(*pool)); - pool->alloc = *alloc; - pool->capacity = capacity; - pool->type = NK_BUFFER_DYNAMIC; - pool->pages = 0; -} -NK_LIB void -nk_pool_free(struct nk_pool *pool) -{ - struct nk_page *iter; - if (!pool) return; - iter = pool->pages; - if (pool->type == NK_BUFFER_FIXED) return; - while (iter) { - struct nk_page *next = iter->next; - pool->alloc.free(pool->alloc.userdata, iter); - iter = next; - } -} -NK_LIB void -nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size) -{ - nk_zero(pool, sizeof(*pool)); - NK_ASSERT(size >= sizeof(struct nk_page)); - if (size < sizeof(struct nk_page)) return; - /* first nk_page_element is embedded in nk_page, additional elements follow in adjacent space */ - pool->capacity = 1 + (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element); - pool->pages = (struct nk_page*)memory; - pool->type = NK_BUFFER_FIXED; - pool->size = size; -} -NK_LIB struct nk_page_element* -nk_pool_alloc(struct nk_pool *pool) -{ - if (!pool->pages || pool->pages->size >= pool->capacity) { - /* allocate new page */ - struct nk_page *page; - if (pool->type == NK_BUFFER_FIXED) { - NK_ASSERT(pool->pages); - if (!pool->pages) return 0; - NK_ASSERT(pool->pages->size < pool->capacity); - return 0; - } else { - nk_size size = sizeof(struct nk_page); - size += (pool->capacity - 1) * sizeof(struct nk_page_element); - page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size); - page->next = pool->pages; - pool->pages = page; - page->size = 0; - } - } return &pool->pages->win[pool->pages->size++]; -} - - - - - -/* =============================================================== - * - * PAGE ELEMENT - * - * ===============================================================*/ -NK_LIB struct nk_page_element* -nk_create_page_element(struct nk_context *ctx) -{ - struct nk_page_element *elem; - if (ctx->freelist) { - /* unlink page element from free list */ - elem = ctx->freelist; - ctx->freelist = elem->next; - } else if (ctx->use_pool) { - /* allocate page element from memory pool */ - elem = nk_pool_alloc(&ctx->pool); - NK_ASSERT(elem); - if (!elem) return 0; - } else { - /* allocate new page element from back of fixed size memory buffer */ - NK_STORAGE const nk_size size = sizeof(struct nk_page_element); - NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element); - elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align); - NK_ASSERT(elem); - if (!elem) return 0; - } - nk_zero_struct(*elem); - elem->next = 0; - elem->prev = 0; - return elem; -} -NK_LIB void -nk_link_page_element_into_freelist(struct nk_context *ctx, - struct nk_page_element *elem) -{ - /* link table into freelist */ - if (!ctx->freelist) { - ctx->freelist = elem; - } else { - elem->next = ctx->freelist; - ctx->freelist = elem; - } -} -NK_LIB void -nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem) -{ - /* we have a pool so just add to free list */ - if (ctx->use_pool) { - nk_link_page_element_into_freelist(ctx, elem); - return; - } - /* if possible remove last element from back of fixed memory buffer */ - {void *elem_end = (void*)(elem + 1); - void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size; - if (elem_end == buffer_end) - ctx->memory.size -= sizeof(struct nk_page_element); - else nk_link_page_element_into_freelist(ctx, elem);} -} - - - - - -/* =============================================================== - * - * TABLE - * - * ===============================================================*/ -NK_LIB struct nk_table* -nk_create_table(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - nk_zero_struct(*elem); - return &elem->data.tbl; -} -NK_LIB void -nk_free_table(struct nk_context *ctx, struct nk_table *tbl) -{ - union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe); -} -NK_LIB void -nk_push_table(struct nk_window *win, struct nk_table *tbl) -{ - if (!win->tables) { - win->tables = tbl; - tbl->next = 0; - tbl->prev = 0; - tbl->size = 0; - win->table_count = 1; - return; - } - win->tables->prev = tbl; - tbl->next = win->tables; - tbl->prev = 0; - tbl->size = 0; - win->tables = tbl; - win->table_count++; -} -NK_LIB void -nk_remove_table(struct nk_window *win, struct nk_table *tbl) -{ - if (win->tables == tbl) - win->tables = tbl->next; - if (tbl->next) - tbl->next->prev = tbl->prev; - if (tbl->prev) - tbl->prev->next = tbl->next; - tbl->next = 0; - tbl->prev = 0; -} -NK_LIB nk_uint* -nk_add_value(struct nk_context *ctx, struct nk_window *win, - nk_hash name, nk_uint value) -{ - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!win || !ctx) return 0; - if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) { - struct nk_table *tbl = nk_create_table(ctx); - NK_ASSERT(tbl); - if (!tbl) return 0; - nk_push_table(win, tbl); - } - win->tables->seq = win->seq; - win->tables->keys[win->tables->size] = name; - win->tables->values[win->tables->size] = value; - return &win->tables->values[win->tables->size++]; -} -NK_LIB nk_uint* -nk_find_value(struct nk_window *win, nk_hash name) -{ - struct nk_table *iter = win->tables; - while (iter) { - unsigned int i = 0; - unsigned int size = iter->size; - for (i = 0; i < size; ++i) { - if (iter->keys[i] == name) { - iter->seq = win->seq; - return &iter->values[i]; - } - } size = NK_VALUE_PAGE_CAPACITY; - iter = iter->next; - } - return 0; -} - - - - - -/* =============================================================== - * - * PANEL - * - * ===============================================================*/ -NK_LIB void* -nk_create_panel(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - nk_zero_struct(*elem); - return &elem->data.pan; -} -NK_LIB void -nk_free_panel(struct nk_context *ctx, struct nk_panel *pan) -{ - union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe); -} -NK_LIB nk_bool -nk_panel_has_header(nk_flags flags, const char *title) -{ - nk_bool active = 0; - active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE)); - active = active || (flags & NK_WINDOW_TITLE); - active = active && !(flags & NK_WINDOW_HIDDEN) && title; - return active; -} -NK_LIB struct nk_vec2 -nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type) -{ - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.padding; - case NK_PANEL_GROUP: return style->window.group_padding; - case NK_PANEL_POPUP: return style->window.popup_padding; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding; - case NK_PANEL_COMBO: return style->window.combo_padding; - case NK_PANEL_MENU: return style->window.menu_padding; - case NK_PANEL_TOOLTIP: return style->window.menu_padding;} -} -NK_LIB float -nk_panel_get_border(const struct nk_style *style, nk_flags flags, - enum nk_panel_type type) -{ - if (flags & NK_WINDOW_BORDER) { - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.border; - case NK_PANEL_GROUP: return style->window.group_border; - case NK_PANEL_POPUP: return style->window.popup_border; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_border; - case NK_PANEL_COMBO: return style->window.combo_border; - case NK_PANEL_MENU: return style->window.menu_border; - case NK_PANEL_TOOLTIP: return style->window.menu_border; - }} else return 0; -} -NK_LIB struct nk_color -nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type) -{ - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.border_color; - case NK_PANEL_GROUP: return style->window.group_border_color; - case NK_PANEL_POPUP: return style->window.popup_border_color; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color; - case NK_PANEL_COMBO: return style->window.combo_border_color; - case NK_PANEL_MENU: return style->window.menu_border_color; - case NK_PANEL_TOOLTIP: return style->window.menu_border_color;} -} -NK_LIB nk_bool -nk_panel_is_sub(enum nk_panel_type type) -{ - return (type & NK_PANEL_SET_SUB)?1:0; -} -NK_LIB nk_bool -nk_panel_is_nonblock(enum nk_panel_type type) -{ - return (type & NK_PANEL_SET_NONBLOCK)?1:0; -} -NK_LIB nk_bool -nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type) -{ - struct nk_input *in; - struct nk_window *win; - struct nk_panel *layout; - struct nk_command_buffer *out; - const struct nk_style *style; - const struct nk_user_font *font; - - struct nk_vec2 scrollbar_size; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - nk_zero(ctx->current->layout, sizeof(*ctx->current->layout)); - if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) { - nk_zero(ctx->current->layout, sizeof(struct nk_panel)); - ctx->current->layout->type = panel_type; - return 0; - } - /* pull state into local stack */ - style = &ctx->style; - font = style->font; - win = ctx->current; - layout = win->layout; - out = &win->buffer; - in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input; -#ifdef NK_INCLUDE_COMMAND_USERDATA - win->buffer.userdata = ctx->userdata; -#endif - /* pull style configuration into local stack */ - scrollbar_size = style->window.scrollbar_size; - panel_padding = nk_panel_get_padding(style, panel_type); - - /* window movement */ - if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) { - int left_mouse_down; - int left_mouse_clicked; - int left_mouse_click_in_cursor; - - /* calculate draggable window space */ - struct nk_rect header; - header.x = win->bounds.x; - header.y = win->bounds.y; - header.w = win->bounds.w; - if (nk_panel_has_header(win->flags, title)) { - header.h = font->height + 2.0f * style->window.header.padding.y; - header.h += 2.0f * style->window.header.label_padding.y; - } else header.h = panel_padding.y; - - /* window movement by dragging */ - left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_clicked = (int)in->mouse.buttons[NK_BUTTON_LEFT].clicked; - left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, header, nk_true); - if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) { - win->bounds.x = win->bounds.x + in->mouse.delta.x; - win->bounds.y = win->bounds.y + in->mouse.delta.y; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y; - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE]; - } - } - - /* setup panel */ - layout->type = panel_type; - layout->flags = win->flags; - layout->bounds = win->bounds; - layout->bounds.x += panel_padding.x; - layout->bounds.w -= 2*panel_padding.x; - if (win->flags & NK_WINDOW_BORDER) { - layout->border = nk_panel_get_border(style, win->flags, panel_type); - layout->bounds = nk_shrink_rect(layout->bounds, layout->border); - } else layout->border = 0; - layout->at_y = layout->bounds.y; - layout->at_x = layout->bounds.x; - layout->max_x = 0; - layout->header_height = 0; - layout->footer_height = 0; - nk_layout_reset_min_row_height(ctx); - layout->row.index = 0; - layout->row.columns = 0; - layout->row.ratio = 0; - layout->row.item_width = 0; - layout->row.tree_depth = 0; - layout->row.height = panel_padding.y; - layout->has_scrolling = nk_true; - if (!(win->flags & NK_WINDOW_NO_SCROLLBAR)) - layout->bounds.w -= scrollbar_size.x; - if (!nk_panel_is_nonblock(panel_type)) { - layout->footer_height = 0; - if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE) - layout->footer_height = scrollbar_size.y; - layout->bounds.h -= layout->footer_height; - } - - /* panel header */ - if (nk_panel_has_header(win->flags, title)) - { - struct nk_text text; - struct nk_rect header; - const struct nk_style_item *background = 0; - - /* calculate header bounds */ - header.x = win->bounds.x; - header.y = win->bounds.y; - header.w = win->bounds.w; - header.h = font->height + 2.0f * style->window.header.padding.y; - header.h += (2.0f * style->window.header.label_padding.y); - - /* shrink panel by header */ - layout->header_height = header.h; - layout->bounds.y += header.h; - layout->bounds.h -= header.h; - layout->at_y += header.h; - - /* select correct header background and text color */ - if (ctx->active == win) { - background = &style->window.header.active; - text.text = style->window.header.label_active; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) { - background = &style->window.header.hover; - text.text = style->window.header.label_hover; - } else { - background = &style->window.header.normal; - text.text = style->window.header.label_normal; - } - - /* draw header background */ - header.h += 1.0f; - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(out, header, 0, background->data.color); - } - - /* window close button */ - {struct nk_rect button; - button.y = header.y + style->window.header.padding.y; - button.h = header.h - 2 * style->window.header.padding.y; - button.w = button.h; - if (win->flags & NK_WINDOW_CLOSABLE) { - nk_flags ws = 0; - if (style->window.header.align == NK_HEADER_RIGHT) { - button.x = (header.w + header.x) - (button.w + style->window.header.padding.x); - header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x; - } else { - button.x = header.x + style->window.header.padding.x; - header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; - } - - if (nk_do_button_symbol(&ws, &win->buffer, button, - style->window.header.close_symbol, NK_BUTTON_DEFAULT, - &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) - { - layout->flags |= NK_WINDOW_HIDDEN; - layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED; - } - } - - /* window minimize button */ - if (win->flags & NK_WINDOW_MINIMIZABLE) { - nk_flags ws = 0; - if (style->window.header.align == NK_HEADER_RIGHT) { - button.x = (header.w + header.x) - button.w; - if (!(win->flags & NK_WINDOW_CLOSABLE)) { - button.x -= style->window.header.padding.x; - header.w -= style->window.header.padding.x; - } - header.w -= button.w + style->window.header.spacing.x; - } else { - button.x = header.x; - header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; - } - if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)? - style->window.header.maximize_symbol: style->window.header.minimize_symbol, - NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) - layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ? - layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED: - layout->flags | NK_WINDOW_MINIMIZED; - }} - - {/* window header title */ - int text_len = nk_strlen(title); - struct nk_rect label = {0,0,0,0}; - float t = font->width(font->userdata, font->height, title, text_len); - text.padding = nk_vec2(0,0); - - label.x = header.x + style->window.header.padding.x; - label.x += style->window.header.label_padding.x; - label.y = header.y + style->window.header.label_padding.y; - label.h = font->height + 2 * style->window.header.label_padding.y; - label.w = t + 2 * style->window.header.spacing.x; - label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x); - nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);} - } - - /* draw window background */ - if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) { - struct nk_rect body; - body.x = win->bounds.x; - body.w = win->bounds.w; - body.y = (win->bounds.y + layout->header_height); - body.h = (win->bounds.h - layout->header_height); - if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white); - else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color); - } - - /* set clipping rectangle */ - {struct nk_rect clip; - layout->clip = layout->bounds; - nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y, - layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h); - nk_push_scissor(out, clip); - layout->clip = clip;} - return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED); -} -NK_LIB void -nk_panel_end(struct nk_context *ctx) -{ - struct nk_input *in; - struct nk_window *window; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - - struct nk_vec2 scrollbar_size; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - window = ctx->current; - layout = window->layout; - style = &ctx->style; - out = &window->buffer; - in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input; - if (!nk_panel_is_sub(layout->type)) - nk_push_scissor(out, nk_null_rect); - - /* cache configuration data */ - scrollbar_size = style->window.scrollbar_size; - panel_padding = nk_panel_get_padding(style, layout->type); - - /* update the current cursor Y-position to point over the last added widget */ - layout->at_y += layout->row.height; - - /* dynamic panels */ - if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED)) - { - /* update panel height to fit dynamic growth */ - struct nk_rect empty_space; - if (layout->at_y < (layout->bounds.y + layout->bounds.h)) - layout->bounds.h = layout->at_y - layout->bounds.y; - - /* fill top empty space */ - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y; - empty_space.h = panel_padding.y; - empty_space.w = window->bounds.w; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill left empty space */ - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y; - empty_space.w = panel_padding.x + layout->border; - empty_space.h = layout->bounds.h; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill right empty space */ - empty_space.x = layout->bounds.x + layout->bounds.w; - empty_space.y = layout->bounds.y; - empty_space.w = panel_padding.x + layout->border; - empty_space.h = layout->bounds.h; - if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) - empty_space.w += scrollbar_size.x; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill bottom empty space */ - if (layout->footer_height > 0) { - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y + layout->bounds.h; - empty_space.w = window->bounds.w; - empty_space.h = layout->footer_height; - nk_fill_rect(out, empty_space, 0, style->window.background); - } - } - - /* scrollbars */ - if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) && - !(layout->flags & NK_WINDOW_MINIMIZED) && - window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT) - { - struct nk_rect scroll; - int scroll_has_scrolling; - float scroll_target; - float scroll_offset; - float scroll_step; - float scroll_inc; - - /* mouse wheel scrolling */ - if (nk_panel_is_sub(layout->type)) - { - /* sub-window mouse wheel scrolling */ - struct nk_window *root_window = window; - struct nk_panel *root_panel = window->layout; - while (root_panel->parent) - root_panel = root_panel->parent; - while (root_window->parent) - root_window = root_window->parent; - - /* only allow scrolling if parent window is active */ - scroll_has_scrolling = 0; - if ((root_window == ctx->active) && layout->has_scrolling) { - /* and panel is being hovered and inside clip rect*/ - if (nk_input_is_mouse_hovering_rect(in, layout->bounds) && - NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h, - root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h)) - { - /* deactivate all parent scrolling */ - root_panel = window->layout; - while (root_panel->parent) { - root_panel->has_scrolling = nk_false; - root_panel = root_panel->parent; - } - root_panel->has_scrolling = nk_false; - scroll_has_scrolling = nk_true; - } - } - } else if (!nk_panel_is_sub(layout->type)) { - /* window mouse wheel scrolling */ - scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling; - if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling) - window->scrolled = nk_true; - else window->scrolled = nk_false; - } else scroll_has_scrolling = nk_false; - - { - /* vertical scrollbar */ - nk_flags state = 0; - scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x; - scroll.y = layout->bounds.y; - scroll.w = scrollbar_size.x; - scroll.h = layout->bounds.h; - - scroll_offset = (float)*layout->offset_y; - scroll_step = scroll.h * 0.10f; - scroll_inc = scroll.h * 0.01f; - scroll_target = (float)(int)(layout->at_y - scroll.y); - scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollv, in, style->font); - *layout->offset_y = (nk_uint)scroll_offset; - if (in && scroll_has_scrolling) - in->mouse.scroll_delta.y = 0; - } - { - /* horizontal scrollbar */ - nk_flags state = 0; - scroll.x = layout->bounds.x; - scroll.y = layout->bounds.y + layout->bounds.h; - scroll.w = layout->bounds.w; - scroll.h = scrollbar_size.y; - - scroll_offset = (float)*layout->offset_x; - scroll_target = (float)(int)(layout->max_x - scroll.x); - scroll_step = layout->max_x * 0.05f; - scroll_inc = layout->max_x * 0.005f; - scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollh, in, style->font); - *layout->offset_x = (nk_uint)scroll_offset; - } - } - - /* hide scroll if no user input */ - if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) { - int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0; - int is_window_hovered = nk_window_is_hovered(ctx); - int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); - if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active)) - window->scrollbar_hiding_timer += ctx->delta_time_seconds; - else window->scrollbar_hiding_timer = 0; - } else window->scrollbar_hiding_timer = 0; - - /* window border */ - if (layout->flags & NK_WINDOW_BORDER) - { - struct nk_color border_color = nk_panel_get_border_color(style, layout->type); - const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED) - ? (style->window.border + window->bounds.y + layout->header_height) - : ((layout->flags & NK_WINDOW_DYNAMIC) - ? (layout->bounds.y + layout->bounds.h + layout->footer_height) - : (window->bounds.y + window->bounds.h)); - struct nk_rect b = window->bounds; - b.h = padding_y - window->bounds.y; - nk_stroke_rect(out, b, 0, layout->border, border_color); - } - - /* scaler */ - if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED)) - { - /* calculate scaler bounds */ - struct nk_rect scaler; - scaler.w = scrollbar_size.x; - scaler.h = scrollbar_size.y; - scaler.y = layout->bounds.y + layout->bounds.h; - if (layout->flags & NK_WINDOW_SCALE_LEFT) - scaler.x = layout->bounds.x - panel_padding.x * 0.5f; - else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x; - if (layout->flags & NK_WINDOW_NO_SCROLLBAR) - scaler.x -= scaler.w; - - /* draw scaler */ - {const struct nk_style_item *item = &style->window.scaler; - if (item->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, scaler, &item->data.image, nk_white); - else { - if (layout->flags & NK_WINDOW_SCALE_LEFT) { - nk_fill_triangle(out, scaler.x, scaler.y, scaler.x, - scaler.y + scaler.h, scaler.x + scaler.w, - scaler.y + scaler.h, item->data.color); - } else { - nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w, - scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color); - } - }} - - /* do window scaling */ - if (!(window->flags & NK_WINDOW_ROM)) { - struct nk_vec2 window_size = style->window.min_size; - int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, scaler, nk_true); - - if (left_mouse_down && left_mouse_click_in_scaler) { - float delta_x = in->mouse.delta.x; - if (layout->flags & NK_WINDOW_SCALE_LEFT) { - delta_x = -delta_x; - window->bounds.x += in->mouse.delta.x; - } - /* dragging in x-direction */ - if (window->bounds.w + delta_x >= window_size.x) { - if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) { - window->bounds.w = window->bounds.w + delta_x; - scaler.x += in->mouse.delta.x; - } - } - /* dragging in y-direction (only possible if static window) */ - if (!(layout->flags & NK_WINDOW_DYNAMIC)) { - if (window_size.y < window->bounds.h + in->mouse.delta.y) { - if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) { - window->bounds.h = window->bounds.h + in->mouse.delta.y; - scaler.y += in->mouse.delta.y; - } - } - } - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; - } - } - } - if (!nk_panel_is_sub(layout->type)) { - /* window is hidden so clear command buffer */ - if (layout->flags & NK_WINDOW_HIDDEN) - nk_command_buffer_reset(&window->buffer); - /* window is visible and not tab */ - else nk_finish(ctx, window); - } - - /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */ - if (layout->flags & NK_WINDOW_REMOVE_ROM) { - layout->flags &= ~(nk_flags)NK_WINDOW_ROM; - layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; - } - window->flags = layout->flags; - - /* property garbage collector */ - if (window->property.active && window->property.old != window->property.seq && - window->property.active == window->property.prev) { - nk_zero(&window->property, sizeof(window->property)); - } else { - window->property.old = window->property.seq; - window->property.prev = window->property.active; - window->property.seq = 0; - } - /* edit garbage collector */ - if (window->edit.active && window->edit.old != window->edit.seq && - window->edit.active == window->edit.prev) { - nk_zero(&window->edit, sizeof(window->edit)); - } else { - window->edit.old = window->edit.seq; - window->edit.prev = window->edit.active; - window->edit.seq = 0; - } - /* contextual garbage collector */ - if (window->popup.active_con && window->popup.con_old != window->popup.con_count) { - window->popup.con_count = 0; - window->popup.con_old = 0; - window->popup.active_con = 0; - } else { - window->popup.con_old = window->popup.con_count; - window->popup.con_count = 0; - } - window->popup.combo_count = 0; - /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */ - NK_ASSERT(!layout->row.tree_depth); -} - - - - - -/* =============================================================== - * - * WINDOW - * - * ===============================================================*/ -NK_LIB void* -nk_create_window(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - elem->data.win.seq = ctx->seq; - return &elem->data.win; -} -NK_LIB void -nk_free_window(struct nk_context *ctx, struct nk_window *win) -{ - /* unlink windows from list */ - struct nk_table *it = win->tables; - if (win->popup.win) { - nk_free_window(ctx, win->popup.win); - win->popup.win = 0; - } - win->next = 0; - win->prev = 0; - - while (it) { - /*free window state tables */ - struct nk_table *n = it->next; - nk_remove_table(win, it); - nk_free_table(ctx, it); - if (it == win->tables) - win->tables = n; - it = n; - } - - /* link windows into freelist */ - {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe);} -} -NK_LIB struct nk_window* -nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name) -{ - struct nk_window *iter; - iter = ctx->begin; - while (iter) { - NK_ASSERT(iter != iter->next); - if (iter->name == hash) { - int max_len = nk_strlen(iter->name_string); - if (!nk_stricmpn(iter->name_string, name, max_len)) - return iter; - } - iter = iter->next; - } - return 0; -} -NK_LIB void -nk_insert_window(struct nk_context *ctx, struct nk_window *win, - enum nk_window_insert_location loc) -{ - const struct nk_window *iter; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!win || !ctx) return; - - iter = ctx->begin; - while (iter) { - NK_ASSERT(iter != iter->next); - NK_ASSERT(iter != win); - if (iter == win) return; - iter = iter->next; - } - - if (!ctx->begin) { - win->next = 0; - win->prev = 0; - ctx->begin = win; - ctx->end = win; - ctx->count = 1; - return; - } - if (loc == NK_INSERT_BACK) { - struct nk_window *end; - end = ctx->end; - end->flags |= NK_WINDOW_ROM; - end->next = win; - win->prev = ctx->end; - win->next = 0; - ctx->end = win; - ctx->active = ctx->end; - ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; - } else { - /*ctx->end->flags |= NK_WINDOW_ROM;*/ - ctx->begin->prev = win; - win->next = ctx->begin; - win->prev = 0; - ctx->begin = win; - ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM; - } - ctx->count++; -} -NK_LIB void -nk_remove_window(struct nk_context *ctx, struct nk_window *win) -{ - if (win == ctx->begin || win == ctx->end) { - if (win == ctx->begin) { - ctx->begin = win->next; - if (win->next) - win->next->prev = 0; - } - if (win == ctx->end) { - ctx->end = win->prev; - if (win->prev) - win->prev->next = 0; - } - } else { - if (win->next) - win->next->prev = win->prev; - if (win->prev) - win->prev->next = win->next; - } - if (win == ctx->active || !ctx->active) { - ctx->active = ctx->end; - if (ctx->end) - ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; - } - win->next = 0; - win->prev = 0; - ctx->count--; -} -NK_API nk_bool -nk_begin(struct nk_context *ctx, const char *title, - struct nk_rect bounds, nk_flags flags) -{ - return nk_begin_titled(ctx, title, title, bounds, flags); -} -NK_API nk_bool -nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, - struct nk_rect bounds, nk_flags flags) -{ - struct nk_window *win; - struct nk_style *style; - nk_hash name_hash; - int name_len; - int ret = 0; - - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(title); - NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font"); - NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call"); - if (!ctx || ctx->current || !title || !name) - return 0; - - /* find or create window */ - style = &ctx->style; - name_len = (int)nk_strlen(name); - name_hash = nk_murmur_hash(name, (int)name_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, name_hash, name); - if (!win) { - /* create new window */ - nk_size name_length = (nk_size)name_len; - win = (struct nk_window*)nk_create_window(ctx); - NK_ASSERT(win); - if (!win) return 0; - - if (flags & NK_WINDOW_BACKGROUND) - nk_insert_window(ctx, win, NK_INSERT_FRONT); - else nk_insert_window(ctx, win, NK_INSERT_BACK); - nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON); - - win->flags = flags; - win->bounds = bounds; - win->name = name_hash; - name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1); - NK_MEMCPY(win->name_string, name, name_length); - win->name_string[name_length] = 0; - win->popup.win = 0; - if (!ctx->active) - ctx->active = win; - } else { - /* update window */ - win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1); - win->flags |= flags; - if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE))) - win->bounds = bounds; - /* If this assert triggers you either: - * - * I.) Have more than one window with the same name or - * II.) You forgot to actually draw the window. - * More specific you did not call `nk_clear` (nk_clear will be - * automatically called for you if you are using one of the - * provided demo backends). */ - NK_ASSERT(win->seq != ctx->seq); - win->seq = ctx->seq; - if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) { - ctx->active = win; - ctx->end = win; - } - } - if (win->flags & NK_WINDOW_HIDDEN) { - ctx->current = win; - win->layout = 0; - return 0; - } else nk_start(ctx, win); - - /* window overlapping */ - if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT)) - { - int inpanel, ishovered; - struct nk_window *iter = win; - float h = ctx->style.font->height + 2.0f * style->window.header.padding.y + - (2.0f * style->window.header.label_padding.y); - struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))? - win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h); - - /* activate window if hovered and no other window is overlapping this window */ - inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true); - inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked; - ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds); - if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) { - iter = win->next; - while (iter) { - struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? - iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); - if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - (!(iter->flags & NK_WINDOW_HIDDEN))) - break; - - if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && - NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter->popup.win->bounds.x, iter->popup.win->bounds.y, - iter->popup.win->bounds.w, iter->popup.win->bounds.h)) - break; - iter = iter->next; - } - } - - /* activate window if clicked */ - if (iter && inpanel && (win != ctx->end)) { - iter = win->next; - while (iter) { - /* try to find a panel with higher priority in the same position */ - struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? - iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); - if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y, - iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - !(iter->flags & NK_WINDOW_HIDDEN)) - break; - if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && - NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter->popup.win->bounds.x, iter->popup.win->bounds.y, - iter->popup.win->bounds.w, iter->popup.win->bounds.h)) - break; - iter = iter->next; - } - } - if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) { - win->flags |= (nk_flags)NK_WINDOW_ROM; - iter->flags &= ~(nk_flags)NK_WINDOW_ROM; - ctx->active = iter; - if (!(iter->flags & NK_WINDOW_BACKGROUND)) { - /* current window is active in that position so transfer to top - * at the highest priority in stack */ - nk_remove_window(ctx, iter); - nk_insert_window(ctx, iter, NK_INSERT_BACK); - } - } else { - if (!iter && ctx->end != win) { - if (!(win->flags & NK_WINDOW_BACKGROUND)) { - /* current window is active in that position so transfer to top - * at the highest priority in stack */ - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); - } - win->flags &= ~(nk_flags)NK_WINDOW_ROM; - ctx->active = win; - } - if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND)) - win->flags |= NK_WINDOW_ROM; - } - } - win->layout = (struct nk_panel*)nk_create_panel(ctx); - ctx->current = win; - ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW); - win->layout->offset_x = &win->scrollbar.x; - win->layout->offset_y = &win->scrollbar.y; - return ret; -} -NK_API void -nk_end(struct nk_context *ctx) -{ - struct nk_panel *layout; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`"); - if (!ctx || !ctx->current) - return; - - layout = ctx->current->layout; - if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) { - ctx->current = 0; - return; - } - nk_panel_end(ctx); - nk_free_panel(ctx, ctx->current->layout); - ctx->current = 0; -} -NK_API struct nk_rect -nk_window_get_bounds(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_rect(0,0,0,0); - return ctx->current->bounds; -} -NK_API struct nk_vec2 -nk_window_get_position(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y); -} -NK_API struct nk_vec2 -nk_window_get_size(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h); -} -NK_API float -nk_window_get_width(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->bounds.w; -} -NK_API float -nk_window_get_height(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->bounds.h; -} -NK_API struct nk_rect -nk_window_get_content_region(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_rect(0,0,0,0); - return ctx->current->layout->clip; -} -NK_API struct nk_vec2 -nk_window_get_content_region_min(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y); -} -NK_API struct nk_vec2 -nk_window_get_content_region_max(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w, - ctx->current->layout->clip.y + ctx->current->layout->clip.h); -} -NK_API struct nk_vec2 -nk_window_get_content_region_size(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h); -} -NK_API struct nk_command_buffer* -nk_window_get_canvas(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return 0; - return &ctx->current->buffer; -} -NK_API struct nk_panel* -nk_window_get_panel(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->layout; -} -NK_API void -nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return ; - win = ctx->current; - if (offset_x) - *offset_x = win->scrollbar.x; - if (offset_y) - *offset_y = win->scrollbar.y; -} -NK_API nk_bool -nk_window_has_focus(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return 0; - return ctx->current == ctx->active; -} -NK_API nk_bool -nk_window_is_hovered(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - if(ctx->current->flags & NK_WINDOW_HIDDEN) - return 0; - return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds); -} -NK_API nk_bool -nk_window_is_any_hovered(struct nk_context *ctx) -{ - struct nk_window *iter; - NK_ASSERT(ctx); - if (!ctx) return 0; - iter = ctx->begin; - while (iter) { - /* check if window is being hovered */ - if(!(iter->flags & NK_WINDOW_HIDDEN)) { - /* check if window popup is being hovered */ - if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds)) - return 1; - - if (iter->flags & NK_WINDOW_MINIMIZED) { - struct nk_rect header = iter->bounds; - header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y; - if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) - return 1; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) { - return 1; - } - } - iter = iter->next; - } - return 0; -} -NK_API nk_bool -nk_item_is_any_active(struct nk_context *ctx) -{ - int any_hovered = nk_window_is_any_hovered(ctx); - int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); - return any_hovered || any_active; -} -NK_API nk_bool -nk_window_is_collapsed(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 0; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 0; - return win->flags & NK_WINDOW_MINIMIZED; -} -NK_API nk_bool -nk_window_is_closed(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 1; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 1; - return (win->flags & NK_WINDOW_CLOSED); -} -NK_API nk_bool -nk_window_is_hidden(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 1; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 1; - return (win->flags & NK_WINDOW_HIDDEN); -} -NK_API nk_bool -nk_window_is_active(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 0; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 0; - return win == ctx->active; -} -NK_API struct nk_window* -nk_window_find(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - return nk_find_window(ctx, title_hash, name); -} -NK_API void -nk_window_close(struct nk_context *ctx, const char *name) -{ - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - win = nk_window_find(ctx, name); - if (!win) return; - NK_ASSERT(ctx->current != win && "You cannot close a currently active window"); - if (ctx->current == win) return; - win->flags |= NK_WINDOW_HIDDEN; - win->flags |= NK_WINDOW_CLOSED; -} -NK_API void -nk_window_set_bounds(struct nk_context *ctx, - const char *name, struct nk_rect bounds) -{ - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - win = nk_window_find(ctx, name); - if (!win) return; - NK_ASSERT(ctx->current != win && "You cannot update a currently in procecss window"); - win->bounds = bounds; -} -NK_API void -nk_window_set_position(struct nk_context *ctx, - const char *name, struct nk_vec2 pos) -{ - struct nk_window *win = nk_window_find(ctx, name); - if (!win) return; - win->bounds.x = pos.x; - win->bounds.y = pos.y; -} -NK_API void -nk_window_set_size(struct nk_context *ctx, - const char *name, struct nk_vec2 size) -{ - struct nk_window *win = nk_window_find(ctx, name); - if (!win) return; - win->bounds.w = size.x; - win->bounds.h = size.y; -} -NK_API void -nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - win = ctx->current; - win->scrollbar.x = offset_x; - win->scrollbar.y = offset_y; -} -NK_API void -nk_window_collapse(struct nk_context *ctx, const char *name, - enum nk_collapse_states c) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return; - if (c == NK_MINIMIZED) - win->flags |= NK_WINDOW_MINIMIZED; - else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED; -} -NK_API void -nk_window_collapse_if(struct nk_context *ctx, const char *name, - enum nk_collapse_states c, int cond) -{ - NK_ASSERT(ctx); - if (!ctx || !cond) return; - nk_window_collapse(ctx, name, c); -} -NK_API void -nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return; - if (s == NK_HIDDEN) { - win->flags |= NK_WINDOW_HIDDEN; - } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN; -} -NK_API void -nk_window_show_if(struct nk_context *ctx, const char *name, - enum nk_show_states s, int cond) -{ - NK_ASSERT(ctx); - if (!ctx || !cond) return; - nk_window_show(ctx, name, s); -} - -NK_API void -nk_window_set_focus(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (win && ctx->end != win) { - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); - } - ctx->active = win; -} - - - - -/* =============================================================== - * - * POPUP - * - * ===============================================================*/ -NK_API nk_bool -nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type, - const char *title, nk_flags flags, struct nk_rect rect) -{ - struct nk_window *popup; - struct nk_window *win; - struct nk_panel *panel; - - int title_len; - nk_hash title_hash; - nk_size allocated; - - NK_ASSERT(ctx); - NK_ASSERT(title); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - panel = win->layout; - NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups"); - (void)panel; - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP); - - popup = win->popup.win; - if (!popup) { - popup = (struct nk_window*)nk_create_window(ctx); - popup->parent = win; - win->popup.win = popup; - win->popup.active = 0; - win->popup.type = NK_PANEL_POPUP; - } - - /* make sure we have correct popup */ - if (win->popup.name != title_hash) { - if (!win->popup.active) { - nk_zero(popup, sizeof(*popup)); - win->popup.name = title_hash; - win->popup.active = 1; - win->popup.type = NK_PANEL_POPUP; - } else return 0; - } - - /* popup position is local to window */ - ctx->current = popup; - rect.x += win->layout->clip.x; - rect.y += win->layout->clip.y; - - /* setup popup data */ - popup->parent = win; - popup->bounds = rect; - popup->seq = ctx->seq; - popup->layout = (struct nk_panel*)nk_create_panel(ctx); - popup->flags = flags; - popup->flags |= NK_WINDOW_BORDER; - if (type == NK_POPUP_DYNAMIC) - popup->flags |= NK_WINDOW_DYNAMIC; - - popup->buffer = win->buffer; - nk_start_popup(ctx, win); - allocated = ctx->memory.allocated; - nk_push_scissor(&popup->buffer, nk_null_rect); - - if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) { - /* popup is running therefore invalidate parent panels */ - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_ROM; - root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.active = 1; - popup->layout->offset_x = &popup->scrollbar.x; - popup->layout->offset_y = &popup->scrollbar.y; - popup->layout->parent = win->layout; - return 1; - } else { - /* popup was closed/is invalid so cleanup */ - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.buf.active = 0; - win->popup.active = 0; - ctx->memory.allocated = allocated; - ctx->current = win; - nk_free_panel(ctx, popup->layout); - popup->layout = 0; - return 0; - } -} -NK_LIB nk_bool -nk_nonblock_begin(struct nk_context *ctx, - nk_flags flags, struct nk_rect body, struct nk_rect header, - enum nk_panel_type panel_type) -{ - struct nk_window *popup; - struct nk_window *win; - struct nk_panel *panel; - int is_active = nk_true; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* popups cannot have popups */ - win = ctx->current; - panel = win->layout; - NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP)); - (void)panel; - popup = win->popup.win; - if (!popup) { - /* create window for nonblocking popup */ - popup = (struct nk_window*)nk_create_window(ctx); - popup->parent = win; - win->popup.win = popup; - win->popup.type = panel_type; - nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON); - } else { - /* close the popup if user pressed outside or in the header */ - int pressed, in_body, in_header; -#ifdef NK_BUTTON_TRIGGER_ON_RELEASE - pressed = nk_input_is_mouse_released(&ctx->input, NK_BUTTON_LEFT); -#else - pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); -#endif - in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); - in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header); - if (pressed && (!in_body || in_header)) - is_active = nk_false; - } - win->popup.header = header; - - if (!is_active) { - /* remove read only mode from all parent panels */ - struct nk_panel *root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - return is_active; - } - popup->bounds = body; - popup->parent = win; - popup->layout = (struct nk_panel*)nk_create_panel(ctx); - popup->flags = flags; - popup->flags |= NK_WINDOW_BORDER; - popup->flags |= NK_WINDOW_DYNAMIC; - popup->seq = ctx->seq; - win->popup.active = 1; - NK_ASSERT(popup->layout); - - nk_start_popup(ctx, win); - popup->buffer = win->buffer; - nk_push_scissor(&popup->buffer, nk_null_rect); - ctx->current = popup; - - nk_panel_begin(ctx, 0, panel_type); - win->buffer = popup->buffer; - popup->layout->parent = win->layout; - popup->layout->offset_x = &popup->scrollbar.x; - popup->layout->offset_y = &popup->scrollbar.y; - - /* set read only mode to all parent panels */ - {struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_ROM; - root = root->parent; - }} - return is_active; -} -NK_API void -nk_popup_close(struct nk_context *ctx) -{ - struct nk_window *popup; - NK_ASSERT(ctx); - if (!ctx || !ctx->current) return; - - popup = ctx->current; - NK_ASSERT(popup->parent); - NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP); - popup->flags |= NK_WINDOW_HIDDEN; -} -NK_API void -nk_popup_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_window *popup; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - popup = ctx->current; - if (!popup->parent) return; - win = popup->parent; - if (popup->flags & NK_WINDOW_HIDDEN) { - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.active = 0; - } - nk_push_scissor(&popup->buffer, nk_null_rect); - nk_end(ctx); - - win->buffer = popup->buffer; - nk_finish_popup(ctx, win); - ctx->current = win; - nk_push_scissor(&win->buffer, win->layout->clip); -} -NK_API void -nk_popup_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y) -{ - struct nk_window *popup; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - popup = ctx->current; - if (offset_x) - *offset_x = popup->scrollbar.x; - if (offset_y) - *offset_y = popup->scrollbar.y; -} -NK_API void -nk_popup_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y) -{ - struct nk_window *popup; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - popup = ctx->current; - popup->scrollbar.x = offset_x; - popup->scrollbar.y = offset_y; -} - - - - -/* ============================================================== - * - * CONTEXTUAL - * - * ===============================================================*/ -NK_API nk_bool -nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size, - struct nk_rect trigger_bounds) -{ - struct nk_window *win; - struct nk_window *popup; - struct nk_rect body; - - NK_STORAGE const struct nk_rect null_rect = {-1,-1,0,0}; - int is_clicked = 0; - int is_open = 0; - int ret = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - ++win->popup.con_count; - if (ctx->current != ctx->active) - return 0; - - /* check if currently active contextual is active */ - popup = win->popup.win; - is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL); - is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds); - if (win->popup.active_con && win->popup.con_count != win->popup.active_con) - return 0; - if (!is_open && win->popup.active_con) - win->popup.active_con = 0; - if ((!is_open && !is_clicked)) - return 0; - - /* calculate contextual position on click */ - win->popup.active_con = win->popup.con_count; - if (is_clicked) { - body.x = ctx->input.mouse.pos.x; - body.y = ctx->input.mouse.pos.y; - } else { - body.x = popup->bounds.x; - body.y = popup->bounds.y; - } - body.w = size.x; - body.h = size.y; - - /* start nonblocking contextual popup */ - ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body, - null_rect, NK_PANEL_CONTEXTUAL); - if (ret) win->popup.type = NK_PANEL_CONTEXTUAL; - else { - win->popup.active_con = 0; - win->popup.type = NK_PANEL_NONE; - if (win->popup.win) - win->popup.win->flags = 0; - } - return ret; -} -NK_API nk_bool -nk_contextual_item_text(struct nk_context *ctx, const char *text, int len, - nk_flags alignment) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, - text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) { - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} -NK_API nk_bool -nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{ - return nk_contextual_item_text(ctx, label, nk_strlen(label), align); -} -NK_API nk_bool -nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds, - img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){ - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} -NK_API nk_bool -nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{ - return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align); -} -NK_API nk_bool -nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) { - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} -NK_API nk_bool -nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *text, nk_flags align) -{ - return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align); -} -NK_API void -nk_contextual_close(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - nk_popup_close(ctx); -} -NK_API void -nk_contextual_end(struct nk_context *ctx) -{ - struct nk_window *popup; - struct nk_panel *panel; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - popup = ctx->current; - panel = popup->layout; - NK_ASSERT(popup->parent); - NK_ASSERT(panel->type & NK_PANEL_SET_POPUP); - if (panel->flags & NK_WINDOW_DYNAMIC) { - /* Close behavior - This is a bit of a hack solution since we do not know before we end our popup - how big it will be. We therefore do not directly know when a - click outside the non-blocking popup must close it at that direct frame. - Instead it will be closed in the next frame.*/ - struct nk_rect body = {0,0,0,0}; - if (panel->at_y < (panel->bounds.y + panel->bounds.h)) { - struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type); - body = panel->bounds; - body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height); - body.h = (panel->bounds.y + panel->bounds.h) - body.y; - } - {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); - int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); - if (pressed && in_body) - popup->flags |= NK_WINDOW_HIDDEN; - } - } - if (popup->flags & NK_WINDOW_HIDDEN) - popup->seq = 0; - nk_popup_end(ctx); - return; -} - - - - - -/* =============================================================== - * - * MENU - * - * ===============================================================*/ -NK_API void -nk_menubar_begin(struct nk_context *ctx) -{ - struct nk_panel *layout; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - layout = ctx->current->layout; - NK_ASSERT(layout->at_y == layout->bounds.y); - /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin. - If you want a menubar the first nuklear function after `nk_begin` has to be a - `nk_menubar_begin` call. Inside the menubar you then have to allocate space for - widgets (also supports multiple rows). - Example: - if (nk_begin(...)) { - nk_menubar_begin(...); - nk_layout_xxxx(...); - nk_button(...); - nk_layout_xxxx(...); - nk_button(...); - nk_menubar_end(...); - } - nk_end(...); - */ - if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) - return; - - layout->menu.x = layout->at_x; - layout->menu.y = layout->at_y + layout->row.height; - layout->menu.w = layout->bounds.w; - layout->menu.offset.x = *layout->offset_x; - layout->menu.offset.y = *layout->offset_y; - *layout->offset_y = 0; -} -NK_API void -nk_menubar_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_command_buffer *out; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - out = &win->buffer; - layout = win->layout; - if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) - return; - - layout->menu.h = layout->at_y - layout->menu.y; - layout->menu.h += layout->row.height + ctx->style.window.spacing.y; - - layout->bounds.y += layout->menu.h; - layout->bounds.h -= layout->menu.h; - - *layout->offset_x = layout->menu.offset.x; - *layout->offset_y = layout->menu.offset.y; - layout->at_y = layout->bounds.y - layout->row.height; - - layout->clip.y = layout->bounds.y; - layout->clip.h = layout->bounds.h; - nk_push_scissor(out, layout->clip); -} -NK_INTERN int -nk_menu_begin(struct nk_context *ctx, struct nk_window *win, - const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size) -{ - int is_open = 0; - int is_active = 0; - struct nk_rect body; - struct nk_window *popup; - nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU); - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - body.x = header.x; - body.w = size.x; - body.y = header.y + header.h; - body.h = size.y; - - popup = win->popup.win; - is_open = popup ? nk_true : nk_false; - is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); - if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || - (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) - return 0; - - win->popup.type = NK_PANEL_MENU; - win->popup.name = hash; - return 1; -} -NK_API nk_bool -nk_menu_begin_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, struct nk_vec2 size) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect header; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header, - title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} -NK_API nk_bool nk_menu_begin_label(struct nk_context *ctx, - const char *text, nk_flags align, struct nk_vec2 size) -{ - return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size); -} -NK_API nk_bool -nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img, - struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header, - img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, id, is_clicked, header, size); -} -NK_API nk_bool -nk_menu_begin_symbol(struct nk_context *ctx, const char *id, - enum nk_symbol_type sym, struct nk_vec2 size) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect header; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header, - sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, id, is_clicked, header, size); -} -NK_API nk_bool -nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, - header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, - ctx->style.font, in)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} -NK_API nk_bool -nk_menu_begin_image_label(struct nk_context *ctx, - const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size) -{ - return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size); -} -NK_API nk_bool -nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, - header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, - ctx->style.font, in)) is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} -NK_API nk_bool -nk_menu_begin_symbol_label(struct nk_context *ctx, - const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size ) -{ - return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size); -} -NK_API nk_bool -nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align) -{ - return nk_contextual_item_text(ctx, title, len, align); -} -NK_API nk_bool -nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{ - return nk_contextual_item_label(ctx, label, align); -} -NK_API nk_bool -nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{ - return nk_contextual_item_image_label(ctx, img, label, align); -} -NK_API nk_bool -nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{ - return nk_contextual_item_image_text(ctx, img, text, len, align); -} -NK_API nk_bool nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *text, int len, nk_flags align) -{ - return nk_contextual_item_symbol_text(ctx, sym, text, len, align); -} -NK_API nk_bool nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *label, nk_flags align) -{ - return nk_contextual_item_symbol_label(ctx, sym, label, align); -} -NK_API void nk_menu_close(struct nk_context *ctx) -{ - nk_contextual_close(ctx); -} -NK_API void -nk_menu_end(struct nk_context *ctx) -{ - nk_contextual_end(ctx); -} - - - - - -/* =============================================================== - * - * LAYOUT - * - * ===============================================================*/ -NK_API void -nk_layout_set_min_row_height(struct nk_context *ctx, float height) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.min_height = height; -} -NK_API void -nk_layout_reset_min_row_height(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.min_height = ctx->style.font->height; - layout->row.min_height += ctx->style.text.padding.y*2; - layout->row.min_height += ctx->style.window.min_row_height_padding*2; -} -NK_LIB float -nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, - float total_space, int columns) -{ - float panel_spacing; - float panel_space; - - struct nk_vec2 spacing; - - spacing = style->window.spacing; - - /* calculate the usable panel space */ - panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x; - panel_space = total_space - panel_spacing; - return panel_space; -} -NK_LIB void -nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, - float height, int cols) -{ - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - - struct nk_vec2 item_spacing; - struct nk_color color; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* prefetch some configuration data */ - layout = win->layout; - style = &ctx->style; - out = &win->buffer; - color = style->window.background; - item_spacing = style->window.spacing; - - /* if one of these triggers you forgot to add an `if` condition around either - a window, group, popup, combobox or contextual menu `begin` and `end` block. - Example: - if (nk_begin(...) {...} nk_end(...); or - if (nk_group_begin(...) { nk_group_end(...);} */ - NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); - NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); - NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - - /* update the current row and set the current row layout */ - layout->row.index = 0; - layout->at_y += layout->row.height; - layout->row.columns = cols; - if (height == 0.0f) - layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y; - else layout->row.height = height + item_spacing.y; - - layout->row.item_offset = 0; - if (layout->flags & NK_WINDOW_DYNAMIC) { - /* draw background for dynamic panels */ - struct nk_rect background; - background.x = win->bounds.x; - background.w = win->bounds.w; - background.y = layout->at_y - 1.0f; - background.h = layout->row.height + 1.0f; - nk_fill_rect(out, background, 0, color); - } -} -NK_LIB void -nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int cols, int width) -{ - /* update the current row and set the current row layout */ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - nk_panel_layout(ctx, win, height, cols); - if (fmt == NK_DYNAMIC) - win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED; - else win->layout->row.type = NK_LAYOUT_STATIC_FIXED; - - win->layout->row.ratio = 0; - win->layout->row.filled = 0; - win->layout->row.item_offset = 0; - win->layout->row.item_width = (float)width; -} -NK_API float -nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(pixel_width); - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - win = ctx->current; - return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f); -} -NK_API void -nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols) -{ - nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0); -} -NK_API void -nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols) -{ - nk_row_layout(ctx, NK_STATIC, height, cols, item_width); -} -NK_API void -nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, - float row_height, int cols) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, row_height, cols); - if (fmt == NK_DYNAMIC) - layout->row.type = NK_LAYOUT_DYNAMIC_ROW; - else layout->row.type = NK_LAYOUT_STATIC_ROW; - - layout->row.ratio = 0; - layout->row.filled = 0; - layout->row.item_width = 0; - layout->row.item_offset = 0; - layout->row.columns = cols; -} -NK_API void -nk_layout_row_push(struct nk_context *ctx, float ratio_or_width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); - if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) - return; - - if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) { - float ratio = ratio_or_width; - if ((ratio + layout->row.filled) > 1.0f) return; - if (ratio > 0.0f) - layout->row.item_width = NK_SATURATE(ratio); - else layout->row.item_width = 1.0f - layout->row.filled; - } else layout->row.item_width = ratio_or_width; -} -NK_API void -nk_layout_row_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); - if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) - return; - layout->row.item_width = 0; - layout->row.item_offset = 0; -} -NK_API void -nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int cols, const float *ratio) -{ - int i; - int n_undef = 0; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, cols); - if (fmt == NK_DYNAMIC) { - /* calculate width of undefined widget ratios */ - float r = 0; - layout->row.ratio = ratio; - for (i = 0; i < cols; ++i) { - if (ratio[i] < 0.0f) - n_undef++; - else r += ratio[i]; - } - r = NK_SATURATE(1.0f - r); - layout->row.type = NK_LAYOUT_DYNAMIC; - layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0; - } else { - layout->row.ratio = ratio; - layout->row.type = NK_LAYOUT_STATIC; - layout->row.item_width = 0; - layout->row.item_offset = 0; - } - layout->row.item_offset = 0; - layout->row.filled = 0; -} -NK_API void -nk_layout_row_template_begin(struct nk_context *ctx, float height) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, 1); - layout->row.type = NK_LAYOUT_TEMPLATE; - layout->row.columns = 0; - layout->row.ratio = 0; - layout->row.item_width = 0; - layout->row.item_height = 0; - layout->row.item_offset = 0; - layout->row.filled = 0; - layout->row.item.x = 0; - layout->row.item.y = 0; - layout->row.item.w = 0; - layout->row.item.h = 0; -} -NK_API void -nk_layout_row_template_push_dynamic(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = -1.0f; -} -NK_API void -nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = -min_width; -} -NK_API void -nk_layout_row_template_push_static(struct nk_context *ctx, float width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = width; -} -NK_API void -nk_layout_row_template_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - int i = 0; - int variable_count = 0; - int min_variable_count = 0; - float min_fixed_width = 0.0f; - float total_fixed_width = 0.0f; - float max_variable_width = 0.0f; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - for (i = 0; i < layout->row.columns; ++i) { - float width = layout->row.templates[i]; - if (width >= 0.0f) { - total_fixed_width += width; - min_fixed_width += width; - } else if (width < -1.0f) { - width = -width; - total_fixed_width += width; - max_variable_width = NK_MAX(max_variable_width, width); - variable_count++; - } else { - min_variable_count++; - variable_count++; - } - } - if (variable_count) { - float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, - layout->bounds.w, layout->row.columns); - float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count; - int enough_space = var_width >= max_variable_width; - if (!enough_space) - var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count; - for (i = 0; i < layout->row.columns; ++i) { - float *width = &layout->row.templates[i]; - *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width; - } - } -} -NK_API void -nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int widget_count) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, widget_count); - if (fmt == NK_STATIC) - layout->row.type = NK_LAYOUT_STATIC_FREE; - else layout->row.type = NK_LAYOUT_DYNAMIC_FREE; - - layout->row.ratio = 0; - layout->row.filled = 0; - layout->row.item_width = 0; - layout->row.item_offset = 0; -} -NK_API void -nk_layout_space_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.item_width = 0; - layout->row.item_height = 0; - layout->row.item_offset = 0; - nk_zero(&layout->row.item, sizeof(layout->row.item)); -} -NK_API void -nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.item = rect; -} -NK_API struct nk_rect -nk_layout_space_bounds(struct nk_context *ctx) -{ - struct nk_rect ret; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x = layout->clip.x; - ret.y = layout->clip.y; - ret.w = layout->clip.w; - ret.h = layout->row.height; - return ret; -} -NK_API struct nk_rect -nk_layout_widget_bounds(struct nk_context *ctx) -{ - struct nk_rect ret; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x = layout->at_x; - ret.y = layout->at_y; - ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0); - ret.h = layout->row.height; - return ret; -} -NK_API struct nk_vec2 -nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += layout->at_x - (float)*layout->offset_x; - ret.y += layout->at_y - (float)*layout->offset_y; - return ret; -} -NK_API struct nk_vec2 -nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += -layout->at_x + (float)*layout->offset_x; - ret.y += -layout->at_y + (float)*layout->offset_y; - return ret; -} -NK_API struct nk_rect -nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += layout->at_x - (float)*layout->offset_x; - ret.y += layout->at_y - (float)*layout->offset_y; - return ret; -} -NK_API struct nk_rect -nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += -layout->at_x + (float)*layout->offset_x; - ret.y += -layout->at_y + (float)*layout->offset_y; - return ret; -} -NK_LIB void -nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win) -{ - struct nk_panel *layout = win->layout; - struct nk_vec2 spacing = ctx->style.window.spacing; - const float row_height = layout->row.height - spacing.y; - nk_panel_layout(ctx, win, row_height, layout->row.columns); -} -NK_LIB void -nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, - struct nk_window *win, int modify) -{ - struct nk_panel *layout; - const struct nk_style *style; - - struct nk_vec2 spacing; - - float item_offset = 0; - float item_width = 0; - float item_spacing = 0; - float panel_space = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - NK_ASSERT(bounds); - - spacing = style->window.spacing; - panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, - layout->bounds.w, layout->row.columns); - - #define NK_FRAC(x) (x - (int)x) /* will be used to remove fookin gaps */ - /* calculate the width of one item inside the current layout space */ - switch (layout->row.type) { - case NK_LAYOUT_DYNAMIC_FIXED: { - /* scaling fixed size widgets item width */ - float w = NK_MAX(1.0f,panel_space) / (float)layout->row.columns; - item_offset = (float)layout->row.index * w; - item_width = w + NK_FRAC(item_offset); - item_spacing = (float)layout->row.index * spacing.x; - } break; - case NK_LAYOUT_DYNAMIC_ROW: { - /* scaling single ratio widget width */ - float w = layout->row.item_width * panel_space; - item_offset = layout->row.item_offset; - item_width = w + NK_FRAC(item_offset); - item_spacing = 0; - - if (modify) { - layout->row.item_offset += w + spacing.x; - layout->row.filled += layout->row.item_width; - layout->row.index = 0; - } - } break; - case NK_LAYOUT_DYNAMIC_FREE: { - /* panel width depended free widget placing */ - bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x); - bounds->x -= (float)*layout->offset_x; - bounds->y = layout->at_y + (layout->row.height * layout->row.item.y); - bounds->y -= (float)*layout->offset_y; - bounds->w = layout->bounds.w * layout->row.item.w + NK_FRAC(bounds->x); - bounds->h = layout->row.height * layout->row.item.h + NK_FRAC(bounds->y); - return; - } - case NK_LAYOUT_DYNAMIC: { - /* scaling arrays of panel width ratios for every widget */ - float ratio, w; - NK_ASSERT(layout->row.ratio); - ratio = (layout->row.ratio[layout->row.index] < 0) ? - layout->row.item_width : layout->row.ratio[layout->row.index]; - - w = (ratio * panel_space); - item_spacing = (float)layout->row.index * spacing.x; - item_offset = layout->row.item_offset; - item_width = w + NK_FRAC(item_offset); - - if (modify) { - layout->row.item_offset += w; - layout->row.filled += ratio; - } - } break; - case NK_LAYOUT_STATIC_FIXED: { - /* non-scaling fixed widgets item width */ - item_width = layout->row.item_width; - item_offset = (float)layout->row.index * item_width; - item_spacing = (float)layout->row.index * spacing.x; - } break; - case NK_LAYOUT_STATIC_ROW: { - /* scaling single ratio widget width */ - item_width = layout->row.item_width; - item_offset = layout->row.item_offset; - item_spacing = (float)layout->row.index * spacing.x; - if (modify) layout->row.item_offset += item_width; - } break; - case NK_LAYOUT_STATIC_FREE: { - /* free widget placing */ - bounds->x = layout->at_x + layout->row.item.x; - bounds->w = layout->row.item.w; - if (((bounds->x + bounds->w) > layout->max_x) && modify) - layout->max_x = (bounds->x + bounds->w); - bounds->x -= (float)*layout->offset_x; - bounds->y = layout->at_y + layout->row.item.y; - bounds->y -= (float)*layout->offset_y; - bounds->h = layout->row.item.h; - return; - } - case NK_LAYOUT_STATIC: { - /* non-scaling array of panel pixel width for every widget */ - item_spacing = (float)layout->row.index * spacing.x; - item_width = layout->row.ratio[layout->row.index]; - item_offset = layout->row.item_offset; - if (modify) layout->row.item_offset += item_width; - } break; - case NK_LAYOUT_TEMPLATE: { - /* stretchy row layout with combined dynamic/static widget width*/ - float w; - NK_ASSERT(layout->row.index < layout->row.columns); - NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - w = layout->row.templates[layout->row.index]; - item_offset = layout->row.item_offset; - item_width = w + NK_FRAC(item_offset); - item_spacing = (float)layout->row.index * spacing.x; - if (modify) layout->row.item_offset += w; - } break; - #undef NK_FRAC - default: NK_ASSERT(0); break; - }; - - /* set the bounds of the newly allocated widget */ - bounds->w = item_width; - bounds->h = layout->row.height - spacing.y; - bounds->y = layout->at_y - (float)*layout->offset_y; - bounds->x = layout->at_x + item_offset + item_spacing; - if (((bounds->x + bounds->w) > layout->max_x) && modify) - layout->max_x = bounds->x + bounds->w; - bounds->x -= (float)*layout->offset_x; -} -NK_LIB void -nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* check if the end of the row has been hit and begin new row if so */ - win = ctx->current; - layout = win->layout; - if (layout->row.index >= layout->row.columns) - nk_panel_alloc_row(ctx, win); - - /* calculate widget position and size */ - nk_layout_widget_space(bounds, ctx, win, nk_true); - layout->row.index++; -} -NK_LIB void -nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx) -{ - float y; - int index; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - y = layout->at_y; - index = layout->row.index; - if (layout->row.index >= layout->row.columns) { - layout->at_y += layout->row.height; - layout->row.index = 0; - } - nk_layout_widget_space(bounds, ctx, win, nk_false); - if (!layout->row.index) { - bounds->x -= layout->row.item_offset; - } - layout->at_y = y; - layout->row.index = index; -} - - - - - -/* =============================================================== - * - * TREE - * - * ===============================================================*/ -NK_INTERN int -nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states *state) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - const struct nk_input *in; - const struct nk_style_button *button; - enum nk_symbol_type symbol; - float row_height; - - struct nk_vec2 item_spacing; - struct nk_rect header = {0,0,0,0}; - struct nk_rect sym = {0,0,0,0}; - struct nk_text text; - - nk_flags ws = 0; - enum nk_widget_layout_states widget_state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* cache some data */ - win = ctx->current; - layout = win->layout; - out = &win->buffer; - style = &ctx->style; - item_spacing = style->window.spacing; - - /* calculate header bounds and draw background */ - row_height = style->font->height + 2 * style->tab.padding.y; - nk_layout_set_min_row_height(ctx, row_height); - nk_layout_row_dynamic(ctx, row_height, 1); - nk_layout_reset_min_row_height(ctx); - - widget_state = nk_widget(&header, ctx); - if (type == NK_TREE_TAB) { - const struct nk_style_item *background = &style->tab.background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, header, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - text.background = background->data.color; - nk_fill_rect(out, header, 0, style->tab.border_color); - nk_fill_rect(out, nk_shrink_rect(header, style->tab.border), - style->tab.rounding, background->data.color); - } - } else text.background = style->window.background; - - /* update node state */ - in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0; - in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0; - if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT)) - *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED; - - /* select correct button style */ - if (*state == NK_MAXIMIZED) { - symbol = style->tab.sym_maximize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_maximize_button; - else button = &style->tab.node_maximize_button; - } else { - symbol = style->tab.sym_minimize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_minimize_button; - else button = &style->tab.node_minimize_button; - } - - {/* draw triangle button */ - sym.w = sym.h = style->font->height; - sym.y = header.y + style->tab.padding.y; - sym.x = header.x + style->tab.padding.x; - nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, - button, 0, style->font); - - if (img) { - /* draw optional image icon */ - sym.x = sym.x + sym.w + 4 * item_spacing.x; - nk_draw_image(&win->buffer, sym, img, nk_white); - sym.w = style->font->height + style->tab.spacing.x;} - } - - {/* draw label */ - struct nk_rect label; - header.w = NK_MAX(header.w, sym.w + item_spacing.x); - label.x = sym.x + sym.w + item_spacing.x; - label.y = sym.y; - label.w = header.w - (sym.w + item_spacing.y + style->tab.indent); - label.h = style->font->height; - text.text = style->tab.text; - text.padding = nk_vec2(0,0); - nk_widget_text(out, label, title, nk_strlen(title), &text, - NK_TEXT_LEFT, style->font);} - - /* increase x-axis cursor widget position pointer */ - if (*state == NK_MAXIMIZED) { - layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent; - layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent); - layout->bounds.w -= (style->tab.indent + style->window.padding.x); - layout->row.tree_depth++; - return nk_true; - } else return nk_false; -} -NK_INTERN int -nk_tree_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states initial_state, - const char *hash, int len, int line) -{ - struct nk_window *win = ctx->current; - int title_len = 0; - nk_hash tree_hash = 0; - nk_uint *state = 0; - - /* retrieve tree state from internal widget state tables */ - if (!hash) { - title_len = (int)nk_strlen(title); - tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line); - } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line); - state = nk_find_value(win, tree_hash); - if (!state) { - state = nk_add_value(ctx, win, tree_hash, 0); - *state = initial_state; - } - return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state); -} -NK_API nk_bool -nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states *state) -{ - return nk_tree_state_base(ctx, type, 0, title, state); -} -NK_API nk_bool -nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states *state) -{ - return nk_tree_state_base(ctx, type, &img, title, state); -} -NK_API void -nk_tree_state_pop(struct nk_context *ctx) -{ - struct nk_window *win = 0; - struct nk_panel *layout = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->at_x -= ctx->style.tab.indent + (float)*layout->offset_x; - layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x; - NK_ASSERT(layout->row.tree_depth); - layout->row.tree_depth--; -} -NK_API nk_bool -nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states initial_state, - const char *hash, int len, int line) -{ - return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line); -} -NK_API nk_bool -nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states initial_state, - const char *hash, int len,int seed) -{ - return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed); -} -NK_API void -nk_tree_pop(struct nk_context *ctx) -{ - nk_tree_state_pop(ctx); -} -NK_INTERN int -nk_tree_element_image_push_hashed_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, int title_len, - enum nk_collapse_states *state, nk_bool *selected) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - const struct nk_input *in; - const struct nk_style_button *button; - enum nk_symbol_type symbol; - float row_height; - struct nk_vec2 padding; - - int text_len; - float text_width; - - struct nk_vec2 item_spacing; - struct nk_rect header = {0,0,0,0}; - struct nk_rect sym = {0,0,0,0}; - - nk_flags ws = 0; - enum nk_widget_layout_states widget_state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* cache some data */ - win = ctx->current; - layout = win->layout; - out = &win->buffer; - style = &ctx->style; - item_spacing = style->window.spacing; - padding = style->selectable.padding; - - /* calculate header bounds and draw background */ - row_height = style->font->height + 2 * style->tab.padding.y; - nk_layout_set_min_row_height(ctx, row_height); - nk_layout_row_dynamic(ctx, row_height, 1); - nk_layout_reset_min_row_height(ctx); - - widget_state = nk_widget(&header, ctx); - if (type == NK_TREE_TAB) { - const struct nk_style_item *background = &style->tab.background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, header, &background->data.image, nk_white); - } else { - nk_fill_rect(out, header, 0, style->tab.border_color); - nk_fill_rect(out, nk_shrink_rect(header, style->tab.border), - style->tab.rounding, background->data.color); - } - } - - in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0; - in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0; - - /* select correct button style */ - if (*state == NK_MAXIMIZED) { - symbol = style->tab.sym_maximize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_maximize_button; - else button = &style->tab.node_maximize_button; - } else { - symbol = style->tab.sym_minimize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_minimize_button; - else button = &style->tab.node_minimize_button; - } - {/* draw triangle button */ - sym.w = sym.h = style->font->height; - sym.y = header.y + style->tab.padding.y; - sym.x = header.x + style->tab.padding.x; - if (nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, button, in, style->font)) - *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;} - - /* draw label */ - {nk_flags dummy = 0; - struct nk_rect label; - /* calculate size of the text and tooltip */ - text_len = nk_strlen(title); - text_width = style->font->width(style->font->userdata, style->font->height, title, text_len); - text_width += (4 * padding.x); - - header.w = NK_MAX(header.w, sym.w + item_spacing.x); - label.x = sym.x + sym.w + item_spacing.x; - label.y = sym.y; - label.w = NK_MIN(header.w - (sym.w + item_spacing.y + style->tab.indent), text_width); - label.h = style->font->height; - - if (img) { - nk_do_selectable_image(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT, - selected, img, &style->selectable, in, style->font); - } else nk_do_selectable(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT, - selected, &style->selectable, in, style->font); - } - /* increase x-axis cursor widget position pointer */ - if (*state == NK_MAXIMIZED) { - layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent; - layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent); - layout->bounds.w -= (style->tab.indent + style->window.padding.x); - layout->row.tree_depth++; - return nk_true; - } else return nk_false; -} -NK_INTERN int -nk_tree_element_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states initial_state, - nk_bool *selected, const char *hash, int len, int line) -{ - struct nk_window *win = ctx->current; - int title_len = 0; - nk_hash tree_hash = 0; - nk_uint *state = 0; - - /* retrieve tree state from internal widget state tables */ - if (!hash) { - title_len = (int)nk_strlen(title); - tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line); - } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line); - state = nk_find_value(win, tree_hash); - if (!state) { - state = nk_add_value(ctx, win, tree_hash, 0); - *state = initial_state; - } return nk_tree_element_image_push_hashed_base(ctx, type, img, title, - nk_strlen(title), (enum nk_collapse_states*)state, selected); -} -NK_API nk_bool -nk_tree_element_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states initial_state, - nk_bool *selected, const char *hash, int len, int seed) -{ - return nk_tree_element_base(ctx, type, 0, title, initial_state, selected, hash, len, seed); -} -NK_API nk_bool -nk_tree_element_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states initial_state, - nk_bool *selected, const char *hash, int len,int seed) -{ - return nk_tree_element_base(ctx, type, &img, title, initial_state, selected, hash, len, seed); -} -NK_API void -nk_tree_element_pop(struct nk_context *ctx) -{ - nk_tree_state_pop(ctx); -} - - - - - -/* =============================================================== - * - * GROUP - * - * ===============================================================*/ -NK_API nk_bool -nk_group_scrolled_offset_begin(struct nk_context *ctx, - nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags) -{ - struct nk_rect bounds; - struct nk_window panel; - struct nk_window *win; - - win = ctx->current; - nk_panel_alloc_space(&bounds, ctx); - {const struct nk_rect *c = &win->layout->clip; - if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) && - !(flags & NK_WINDOW_MOVABLE)) { - return 0; - }} - if (win->flags & NK_WINDOW_ROM) - flags |= NK_WINDOW_ROM; - - /* initialize a fake window to create the panel from */ - nk_zero(&panel, sizeof(panel)); - panel.bounds = bounds; - panel.flags = flags; - panel.scrollbar.x = *x_offset; - panel.scrollbar.y = *y_offset; - panel.buffer = win->buffer; - panel.layout = (struct nk_panel*)nk_create_panel(ctx); - ctx->current = &panel; - nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP); - - win->buffer = panel.buffer; - win->buffer.clip = panel.layout->clip; - panel.layout->offset_x = x_offset; - panel.layout->offset_y = y_offset; - panel.layout->parent = win->layout; - win->layout = panel.layout; - - ctx->current = win; - if ((panel.layout->flags & NK_WINDOW_CLOSED) || - (panel.layout->flags & NK_WINDOW_MINIMIZED)) - { - nk_flags f = panel.layout->flags; - nk_group_scrolled_end(ctx); - if (f & NK_WINDOW_CLOSED) - return NK_WINDOW_CLOSED; - if (f & NK_WINDOW_MINIMIZED) - return NK_WINDOW_MINIMIZED; - } - return 1; -} -NK_API void -nk_group_scrolled_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *parent; - struct nk_panel *g; - - struct nk_rect clip; - struct nk_window pan; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - - /* make sure nk_group_begin was called correctly */ - NK_ASSERT(ctx->current); - win = ctx->current; - NK_ASSERT(win->layout); - g = win->layout; - NK_ASSERT(g->parent); - parent = g->parent; - - /* dummy window */ - nk_zero_struct(pan); - panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP); - pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h); - pan.bounds.x = g->bounds.x - panel_padding.x; - pan.bounds.w = g->bounds.w + 2 * panel_padding.x; - pan.bounds.h = g->bounds.h + g->header_height + g->menu.h; - if (g->flags & NK_WINDOW_BORDER) { - pan.bounds.x -= g->border; - pan.bounds.y -= g->border; - pan.bounds.w += 2*g->border; - pan.bounds.h += 2*g->border; - } - if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) { - pan.bounds.w += ctx->style.window.scrollbar_size.x; - pan.bounds.h += ctx->style.window.scrollbar_size.y; - } - pan.scrollbar.x = *g->offset_x; - pan.scrollbar.y = *g->offset_y; - pan.flags = g->flags; - pan.buffer = win->buffer; - pan.layout = g; - pan.parent = win; - ctx->current = &pan; - - /* make sure group has correct clipping rectangle */ - nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y, - pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x); - nk_push_scissor(&pan.buffer, clip); - nk_end(ctx); - - win->buffer = pan.buffer; - nk_push_scissor(&win->buffer, parent->clip); - ctx->current = win; - win->layout = parent; - g->bounds = pan.bounds; - return; -} -NK_API nk_bool -nk_group_scrolled_begin(struct nk_context *ctx, - struct nk_scroll *scroll, const char *title, nk_flags flags) -{ - return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags); -} -NK_API nk_bool -nk_group_begin_titled(struct nk_context *ctx, const char *id, - const char *title, nk_flags flags) -{ - int id_len; - nk_hash id_hash; - struct nk_window *win; - nk_uint *x_offset; - nk_uint *y_offset; - - NK_ASSERT(ctx); - NK_ASSERT(id); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !id) - return 0; - - /* find persistent group scrollbar value */ - win = ctx->current; - id_len = (int)nk_strlen(id); - id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP); - x_offset = nk_find_value(win, id_hash); - if (!x_offset) { - x_offset = nk_add_value(ctx, win, id_hash, 0); - y_offset = nk_add_value(ctx, win, id_hash+1, 0); - - NK_ASSERT(x_offset); - NK_ASSERT(y_offset); - if (!x_offset || !y_offset) return 0; - *x_offset = *y_offset = 0; - } else y_offset = nk_find_value(win, id_hash+1); - return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); -} -NK_API nk_bool -nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags) -{ - return nk_group_begin_titled(ctx, title, title, flags); -} -NK_API void -nk_group_end(struct nk_context *ctx) -{ - nk_group_scrolled_end(ctx); -} -NK_API void -nk_group_get_scroll(struct nk_context *ctx, const char *id, nk_uint *x_offset, nk_uint *y_offset) -{ - int id_len; - nk_hash id_hash; - struct nk_window *win; - nk_uint *x_offset_ptr; - nk_uint *y_offset_ptr; - - NK_ASSERT(ctx); - NK_ASSERT(id); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !id) - return; - - /* find persistent group scrollbar value */ - win = ctx->current; - id_len = (int)nk_strlen(id); - id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP); - x_offset_ptr = nk_find_value(win, id_hash); - if (!x_offset_ptr) { - x_offset_ptr = nk_add_value(ctx, win, id_hash, 0); - y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0); - - NK_ASSERT(x_offset_ptr); - NK_ASSERT(y_offset_ptr); - if (!x_offset_ptr || !y_offset_ptr) return; - *x_offset_ptr = *y_offset_ptr = 0; - } else y_offset_ptr = nk_find_value(win, id_hash+1); - if (x_offset) - *x_offset = *x_offset_ptr; - if (y_offset) - *y_offset = *y_offset_ptr; -} -NK_API void -nk_group_set_scroll(struct nk_context *ctx, const char *id, nk_uint x_offset, nk_uint y_offset) -{ - int id_len; - nk_hash id_hash; - struct nk_window *win; - nk_uint *x_offset_ptr; - nk_uint *y_offset_ptr; - - NK_ASSERT(ctx); - NK_ASSERT(id); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !id) - return; - - /* find persistent group scrollbar value */ - win = ctx->current; - id_len = (int)nk_strlen(id); - id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP); - x_offset_ptr = nk_find_value(win, id_hash); - if (!x_offset_ptr) { - x_offset_ptr = nk_add_value(ctx, win, id_hash, 0); - y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0); - - NK_ASSERT(x_offset_ptr); - NK_ASSERT(y_offset_ptr); - if (!x_offset_ptr || !y_offset_ptr) return; - *x_offset_ptr = *y_offset_ptr = 0; - } else y_offset_ptr = nk_find_value(win, id_hash+1); - *x_offset_ptr = x_offset; - *y_offset_ptr = y_offset; -} - - - - -/* =============================================================== - * - * LIST VIEW - * - * ===============================================================*/ -NK_API nk_bool -nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view, - const char *title, nk_flags flags, int row_height, int row_count) -{ - int title_len; - nk_hash title_hash; - nk_uint *x_offset; - nk_uint *y_offset; - - int result; - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_vec2 item_spacing; - - NK_ASSERT(ctx); - NK_ASSERT(view); - NK_ASSERT(title); - if (!ctx || !view || !title) return 0; - - win = ctx->current; - style = &ctx->style; - item_spacing = style->window.spacing; - row_height += NK_MAX(0, (int)item_spacing.y); - - /* find persistent list view scrollbar offset */ - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP); - x_offset = nk_find_value(win, title_hash); - if (!x_offset) { - x_offset = nk_add_value(ctx, win, title_hash, 0); - y_offset = nk_add_value(ctx, win, title_hash+1, 0); - - NK_ASSERT(x_offset); - NK_ASSERT(y_offset); - if (!x_offset || !y_offset) return 0; - *x_offset = *y_offset = 0; - } else y_offset = nk_find_value(win, title_hash+1); - view->scroll_value = *y_offset; - view->scroll_pointer = y_offset; - - *y_offset = 0; - result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); - win = ctx->current; - layout = win->layout; - - view->total_height = row_height * NK_MAX(row_count,1); - view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f); - view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height),0); - view->count = NK_MIN(view->count, row_count - view->begin); - view->end = view->begin + view->count; - view->ctx = ctx; - return result; -} -NK_API void -nk_list_view_end(struct nk_list_view *view) -{ - struct nk_context *ctx; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(view); - NK_ASSERT(view->ctx); - NK_ASSERT(view->scroll_pointer); - if (!view || !view->ctx) return; - - ctx = view->ctx; - win = ctx->current; - layout = win->layout; - layout->at_y = layout->bounds.y + (float)view->total_height; - *view->scroll_pointer = *view->scroll_pointer + view->scroll_value; - nk_group_end(view->ctx); -} - - - - - -/* =============================================================== - * - * WIDGET - * - * ===============================================================*/ -NK_API struct nk_rect -nk_widget_bounds(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_rect(0,0,0,0); - nk_layout_peek(&bounds, ctx); - return bounds; -} -NK_API struct nk_vec2 -nk_widget_position(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_vec2(0,0); - - nk_layout_peek(&bounds, ctx); - return nk_vec2(bounds.x, bounds.y); -} -NK_API struct nk_vec2 -nk_widget_size(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_vec2(0,0); - - nk_layout_peek(&bounds, ctx); - return nk_vec2(bounds.w, bounds.h); -} -NK_API float -nk_widget_width(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return 0; - - nk_layout_peek(&bounds, ctx); - return bounds.w; -} -NK_API float -nk_widget_height(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return 0; - - nk_layout_peek(&bounds, ctx); - return bounds.h; -} -NK_API nk_bool -nk_widget_is_hovered(struct nk_context *ctx) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_is_mouse_hovering_rect(&ctx->input, bounds); -} -NK_API nk_bool -nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_mouse_clicked(&ctx->input, btn, bounds); -} -NK_API nk_bool -nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, nk_bool down) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down); -} -NK_API enum nk_widget_layout_states -nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) -{ - struct nk_rect c, v; - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return NK_WIDGET_INVALID; - - /* allocate space and check if the widget needs to be updated and drawn */ - nk_panel_alloc_space(bounds, ctx); - win = ctx->current; - layout = win->layout; - in = &ctx->input; - c = layout->clip; - - /* if one of these triggers you forgot to add an `if` condition around either - a window, group, popup, combobox or contextual menu `begin` and `end` block. - Example: - if (nk_begin(...) {...} nk_end(...); or - if (nk_group_begin(...) { nk_group_end(...);} */ - NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); - NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); - NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - - /* need to convert to int here to remove floating point errors */ - bounds->x = (float)((int)bounds->x); - bounds->y = (float)((int)bounds->y); - bounds->w = (float)((int)bounds->w); - bounds->h = (float)((int)bounds->h); - - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h)) - return NK_WIDGET_INVALID; - if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h)) - return NK_WIDGET_ROM; - return NK_WIDGET_VALID; -} -NK_API enum nk_widget_layout_states -nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx, - struct nk_vec2 item_padding) -{ - /* update the bounds to stand without padding */ - enum nk_widget_layout_states state; - NK_UNUSED(item_padding); - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return NK_WIDGET_INVALID; - - state = nk_widget(bounds, ctx); - return state; -} -NK_API void -nk_spacing(struct nk_context *ctx, int cols) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_rect none; - int i, index, rows; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* spacing over row boundaries */ - win = ctx->current; - layout = win->layout; - index = (layout->row.index + cols) % layout->row.columns; - rows = (layout->row.index + cols) / layout->row.columns; - if (rows) { - for (i = 0; i < rows; ++i) - nk_panel_alloc_row(ctx, win); - cols = index; - } - /* non table layout need to allocate space */ - if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED && - layout->row.type != NK_LAYOUT_STATIC_FIXED) { - for (i = 0; i < cols; ++i) - nk_panel_alloc_space(&none, ctx); - } layout->row.index = index; -} - - - - - -/* =============================================================== - * - * TEXT - * - * ===============================================================*/ -NK_LIB void -nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - nk_flags a, const struct nk_user_font *f) -{ - struct nk_rect label; - float text_width; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - b.h = NK_MAX(b.h, 2 * t->padding.y); - label.x = 0; label.w = 0; - label.y = b.y + t->padding.y; - label.h = NK_MIN(f->height, b.h - 2 * t->padding.y); - - text_width = f->width(f->userdata, f->height, (const char*)string, len); - text_width += (2.0f * t->padding.x); - - /* align in x-axis */ - if (a & NK_TEXT_ALIGN_LEFT) { - label.x = b.x + t->padding.x; - label.w = NK_MAX(0, b.w - 2 * t->padding.x); - } else if (a & NK_TEXT_ALIGN_CENTERED) { - label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width); - label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2); - label.x = NK_MAX(b.x + t->padding.x, label.x); - label.w = NK_MIN(b.x + b.w, label.x + label.w); - if (label.w >= label.x) label.w -= label.x; - } else if (a & NK_TEXT_ALIGN_RIGHT) { - label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width)); - label.w = (float)text_width + 2 * t->padding.x; - } else return; - - /* align in y-axis */ - if (a & NK_TEXT_ALIGN_MIDDLE) { - label.y = b.y + b.h/2.0f - (float)f->height/2.0f; - label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f)); - } else if (a & NK_TEXT_ALIGN_BOTTOM) { - label.y = b.y + b.h - f->height; - label.h = f->height; - } - nk_draw_text(o, label, (const char*)string, len, f, t->background, t->text); -} -NK_LIB void -nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - const struct nk_user_font *f) -{ - float width; - int glyphs = 0; - int fitting = 0; - int done = 0; - struct nk_rect line; - struct nk_text text; - NK_INTERN nk_rune seperator[] = {' '}; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - text.padding = nk_vec2(0,0); - text.background = t->background; - text.text = t->text; - - b.w = NK_MAX(b.w, 2 * t->padding.x); - b.h = NK_MAX(b.h, 2 * t->padding.y); - b.h = b.h - 2 * t->padding.y; - - line.x = b.x + t->padding.x; - line.y = b.y + t->padding.y; - line.w = b.w - 2 * t->padding.x; - line.h = 2 * t->padding.y + f->height; - - fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); - while (done < len) { - if (!fitting || line.y + line.h >= (b.y + b.h)) break; - nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f); - done += fitting; - line.y += f->height + 2 * t->padding.y; - fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); - } -} -NK_API void -nk_text_colored(struct nk_context *ctx, const char *str, int len, - nk_flags alignment, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font); -} -NK_API void -nk_text_wrap_colored(struct nk_context *ctx, const char *str, - int len, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font); -} -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void -nk_labelf_colored(struct nk_context *ctx, nk_flags flags, - struct nk_color color, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - nk_labelfv_colored(ctx, flags, color, fmt, args); - va_end(args); -} -NK_API void -nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color, - const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - nk_labelfv_colored_wrap(ctx, color, fmt, args); - va_end(args); -} -NK_API void -nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - nk_labelfv(ctx, flags, fmt, args); - va_end(args); -} -NK_API void -nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...) -{ - va_list args; - va_start(args, fmt); - nk_labelfv_wrap(ctx, fmt, args); - va_end(args); -} -NK_API void -nk_labelfv_colored(struct nk_context *ctx, nk_flags flags, - struct nk_color color, const char *fmt, va_list args) -{ - char buf[256]; - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_colored(ctx, buf, flags, color); -} - -NK_API void -nk_labelfv_colored_wrap(struct nk_context *ctx, struct nk_color color, - const char *fmt, va_list args) -{ - char buf[256]; - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_colored_wrap(ctx, buf, color); -} - -NK_API void -nk_labelfv(struct nk_context *ctx, nk_flags flags, const char *fmt, va_list args) -{ - char buf[256]; - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label(ctx, buf, flags); -} - -NK_API void -nk_labelfv_wrap(struct nk_context *ctx, const char *fmt, va_list args) -{ - char buf[256]; - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_wrap(ctx, buf); -} - -NK_API void -nk_value_bool(struct nk_context *ctx, const char *prefix, int value) -{ - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false")); -} -NK_API void -nk_value_int(struct nk_context *ctx, const char *prefix, int value) -{ - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value); -} -NK_API void -nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value) -{ - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value); -} -NK_API void -nk_value_float(struct nk_context *ctx, const char *prefix, float value) -{ - double double_value = (double)value; - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value); -} -NK_API void -nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c) -{ - nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a); -} -NK_API void -nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color) -{ - double c[4]; nk_color_dv(c, color); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)", - p, c[0], c[1], c[2], c[3]); -} -NK_API void -nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color) -{ - char hex[16]; - nk_color_hex_rgba(hex, color); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex); -} -#endif -NK_API void -nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_text_colored(ctx, str, len, alignment, ctx->style.text.color); -} -NK_API void -nk_text_wrap(struct nk_context *ctx, const char *str, int len) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_text_wrap_colored(ctx, str, len, ctx->style.text.color); -} -NK_API void -nk_label(struct nk_context *ctx, const char *str, nk_flags alignment) -{ - nk_text(ctx, str, nk_strlen(str), alignment); -} -NK_API void -nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align, - struct nk_color color) -{ - nk_text_colored(ctx, str, nk_strlen(str), align, color); -} -NK_API void -nk_label_wrap(struct nk_context *ctx, const char *str) -{ - nk_text_wrap(ctx, str, nk_strlen(str)); -} -NK_API void -nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color) -{ - nk_text_wrap_colored(ctx, str, nk_strlen(str), color); -} - - - - - -/* =============================================================== - * - * IMAGE - * - * ===============================================================*/ -NK_API nk_handle -nk_handle_ptr(void *ptr) -{ - nk_handle handle = {0}; - handle.ptr = ptr; - return handle; -} -NK_API nk_handle -nk_handle_id(int id) -{ - nk_handle handle; - nk_zero_struct(handle); - handle.id = id; - return handle; -} -NK_API struct nk_image -nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.ptr = ptr; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} -NK_API struct nk_image -nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.id = id; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} -NK_API struct nk_image -nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h, - struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle = handle; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} -NK_API struct nk_image -nk_image_handle(nk_handle handle) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle = handle; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} -NK_API struct nk_image -nk_image_ptr(void *ptr) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - NK_ASSERT(ptr); - s.handle.ptr = ptr; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} -NK_API struct nk_image -nk_image_id(int id) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.id = id; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} -NK_API nk_bool -nk_image_is_subimage(const struct nk_image* img) -{ - NK_ASSERT(img); - return !(img->w == 0 && img->h == 0); -} -NK_API void -nk_image(struct nk_context *ctx, struct nk_image img) -{ - struct nk_window *win; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - if (!nk_widget(&bounds, ctx)) return; - nk_draw_image(&win->buffer, bounds, &img, nk_white); -} -NK_API void -nk_image_color(struct nk_context *ctx, struct nk_image img, struct nk_color col) -{ - struct nk_window *win; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - if (!nk_widget(&bounds, ctx)) return; - nk_draw_image(&win->buffer, bounds, &img, col); -} - - - - - -/* ============================================================== - * - * BUTTON - * - * ===============================================================*/ -NK_LIB void -nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, - struct nk_rect content, struct nk_color background, struct nk_color foreground, - float border_width, const struct nk_user_font *font) -{ - switch (type) { - case NK_SYMBOL_X: - case NK_SYMBOL_UNDERSCORE: - case NK_SYMBOL_PLUS: - case NK_SYMBOL_MINUS: { - /* single character text symbol */ - const char *X = (type == NK_SYMBOL_X) ? "x": - (type == NK_SYMBOL_UNDERSCORE) ? "_": - (type == NK_SYMBOL_PLUS) ? "+": "-"; - struct nk_text text; - text.padding = nk_vec2(0,0); - text.background = background; - text.text = foreground; - nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font); - } break; - case NK_SYMBOL_CIRCLE_SOLID: - case NK_SYMBOL_CIRCLE_OUTLINE: - case NK_SYMBOL_RECT_SOLID: - case NK_SYMBOL_RECT_OUTLINE: { - /* simple empty/filled shapes */ - if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) { - nk_fill_rect(out, content, 0, foreground); - if (type == NK_SYMBOL_RECT_OUTLINE) - nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background); - } else { - nk_fill_circle(out, content, foreground); - if (type == NK_SYMBOL_CIRCLE_OUTLINE) - nk_fill_circle(out, nk_shrink_rect(content, 1), background); - } - } break; - case NK_SYMBOL_TRIANGLE_UP: - case NK_SYMBOL_TRIANGLE_DOWN: - case NK_SYMBOL_TRIANGLE_LEFT: - case NK_SYMBOL_TRIANGLE_RIGHT: { - enum nk_heading heading; - struct nk_vec2 points[3]; - heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT : - (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT: - (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN; - nk_triangle_from_direction(points, content, 0, 0, heading); - nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y, - points[2].x, points[2].y, foreground); - } break; - default: - case NK_SYMBOL_NONE: - case NK_SYMBOL_MAX: break; - } -} -NK_LIB nk_bool -nk_button_behavior(nk_flags *state, struct nk_rect r, - const struct nk_input *i, enum nk_button_behavior behavior) -{ - int ret = 0; - nk_widget_state_reset(state); - if (!i) return 0; - if (nk_input_is_mouse_hovering_rect(i, r)) { - *state = NK_WIDGET_STATE_HOVERED; - if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT)) - *state = NK_WIDGET_STATE_ACTIVE; - if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) { - ret = (behavior != NK_BUTTON_DEFAULT) ? - nk_input_is_mouse_down(i, NK_BUTTON_LEFT): -#ifdef NK_BUTTON_TRIGGER_ON_RELEASE - nk_input_is_mouse_released(i, NK_BUTTON_LEFT); -#else - nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT); -#endif - } - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(i, r)) - *state |= NK_WIDGET_STATE_LEFT; - return ret; -} -NK_LIB const struct nk_style_item* -nk_draw_button(struct nk_command_buffer *out, - const struct nk_rect *bounds, nk_flags state, - const struct nk_style_button *style) -{ - const struct nk_style_item *background; - if (state & NK_WIDGET_STATE_HOVER) - background = &style->hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - background = &style->active; - else background = &style->normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } - return background; -} -NK_LIB nk_bool -nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, - const struct nk_style_button *style, const struct nk_input *in, - enum nk_button_behavior behavior, struct nk_rect *content) -{ - struct nk_rect bounds; - NK_ASSERT(style); - NK_ASSERT(state); - NK_ASSERT(out); - if (!out || !style) - return nk_false; - - /* calculate button content space */ - content->x = r.x + style->padding.x + style->border + style->rounding; - content->y = r.y + style->padding.y + style->border + style->rounding; - content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2); - content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2); - - /* execute button behavior */ - bounds.x = r.x - style->touch_padding.x; - bounds.y = r.y - style->touch_padding.y; - bounds.w = r.w + 2 * style->touch_padding.x; - bounds.h = r.h + 2 * style->touch_padding.y; - return nk_button_behavior(state, bounds, in, behavior); -} -NK_LIB void -nk_draw_button_text(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, - const struct nk_style_button *style, const char *txt, int len, - nk_flags text_alignment, const struct nk_user_font *font) -{ - struct nk_text text; - const struct nk_style_item *background; - background = nk_draw_button(out, bounds, state, style); - - /* select correct colors/images */ - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - if (state & NK_WIDGET_STATE_HOVER) - text.text = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - text.text = style->text_active; - else text.text = style->text_normal; - - text.padding = nk_vec2(0,0); - nk_widget_text(out, *content, txt, len, &text, text_alignment, font); -} -NK_LIB nk_bool -nk_do_button_text(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - const char *string, int len, nk_flags align, enum nk_button_behavior behavior, - const struct nk_style_button *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect content; - int ret = nk_false; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(string); - NK_ASSERT(font); - if (!out || !style || !font || !string) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} -NK_LIB void -nk_draw_button_symbol(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, - nk_flags state, const struct nk_style_button *style, - enum nk_symbol_type type, const struct nk_user_font *font) -{ - struct nk_color sym, bg; - const struct nk_style_item *background; - - /* select correct colors/images */ - background = nk_draw_button(out, bounds, state, style); - if (background->type == NK_STYLE_ITEM_COLOR) - bg = background->data.color; - else bg = style->text_background; - - if (state & NK_WIDGET_STATE_HOVER) - sym = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - sym = style->text_active; - else sym = style->text_normal; - nk_draw_symbol(out, type, *content, bg, sym, 1, font); -} -NK_LIB nk_bool -nk_do_button_symbol(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - enum nk_symbol_type symbol, enum nk_button_behavior behavior, - const struct nk_style_button *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int ret; - struct nk_rect content; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(font); - NK_ASSERT(out); - if (!out || !style || !font || !state) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} -NK_LIB void -nk_draw_button_image(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, - nk_flags state, const struct nk_style_button *style, const struct nk_image *img) -{ - nk_draw_button(out, bounds, state, style); - nk_draw_image(out, *content, img, nk_white); -} -NK_LIB nk_bool -nk_do_button_image(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - struct nk_image img, enum nk_button_behavior b, - const struct nk_style_button *style, const struct nk_input *in) -{ - int ret; - struct nk_rect content; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style || !state) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, b, &content); - content.x += style->image_padding.x; - content.y += style->image_padding.y; - content.w -= 2 * style->image_padding.x; - content.h -= 2 * style->image_padding.y; - - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_image(out, &bounds, &content, *state, style, &img); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} -NK_LIB void -nk_draw_button_text_symbol(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *label, - const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, - const char *str, int len, enum nk_symbol_type type, - const struct nk_user_font *font) -{ - struct nk_color sym; - struct nk_text text; - const struct nk_style_item *background; - - /* select correct background colors/images */ - background = nk_draw_button(out, bounds, state, style); - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - - /* select correct text colors */ - if (state & NK_WIDGET_STATE_HOVER) { - sym = style->text_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - sym = style->text_active; - text.text = style->text_active; - } else { - sym = style->text_normal; - text.text = style->text_normal; - } - - text.padding = nk_vec2(0,0); - nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font); - nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); -} -NK_LIB nk_bool -nk_do_button_text_symbol(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - enum nk_symbol_type symbol, const char *str, int len, nk_flags align, - enum nk_button_behavior behavior, const struct nk_style_button *style, - const struct nk_user_font *font, const struct nk_input *in) -{ - int ret; - struct nk_rect tri = {0,0,0,0}; - struct nk_rect content; - - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(font); - if (!out || !style || !font) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - tri.y = content.y + (content.h/2) - font->height/2; - tri.w = font->height; tri.h = font->height; - if (align & NK_TEXT_ALIGN_LEFT) { - tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w); - tri.x = NK_MAX(tri.x, 0); - } else tri.x = content.x + 2 * style->padding.x; - - /* draw button */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text_symbol(out, &bounds, &content, &tri, - *state, style, str, len, symbol, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} -NK_LIB void -nk_draw_button_text_image(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *label, - const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, - const char *str, int len, const struct nk_user_font *font, - const struct nk_image *img) -{ - struct nk_text text; - const struct nk_style_item *background; - background = nk_draw_button(out, bounds, state, style); - - /* select correct colors */ - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - if (state & NK_WIDGET_STATE_HOVER) - text.text = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - text.text = style->text_active; - else text.text = style->text_normal; - - text.padding = nk_vec2(0,0); - nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); - nk_draw_image(out, *image, img, nk_white); -} -NK_LIB nk_bool -nk_do_button_text_image(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - struct nk_image img, const char* str, int len, nk_flags align, - enum nk_button_behavior behavior, const struct nk_style_button *style, - const struct nk_user_font *font, const struct nk_input *in) -{ - int ret; - struct nk_rect icon; - struct nk_rect content; - - NK_ASSERT(style); - NK_ASSERT(state); - NK_ASSERT(font); - NK_ASSERT(out); - if (!out || !font || !style || !str) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} -NK_API void -nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) -{ - NK_ASSERT(ctx); - if (!ctx) return; - ctx->button_behavior = behavior; -} -NK_API nk_bool -nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) -{ - struct nk_config_stack_button_behavior *button_stack; - struct nk_config_stack_button_behavior_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - button_stack = &ctx->stacks.button_behaviors; - NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements)); - if (button_stack->head >= (int)NK_LEN(button_stack->elements)) - return 0; - - element = &button_stack->elements[button_stack->head++]; - element->address = &ctx->button_behavior; - element->old_value = ctx->button_behavior; - ctx->button_behavior = behavior; - return 1; -} -NK_API nk_bool -nk_button_pop_behavior(struct nk_context *ctx) -{ - struct nk_config_stack_button_behavior *button_stack; - struct nk_config_stack_button_behavior_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - button_stack = &ctx->stacks.button_behaviors; - NK_ASSERT(button_stack->head > 0); - if (button_stack->head < 1) - return 0; - - element = &button_stack->elements[--button_stack->head]; - *element->address = element->old_value; - return 1; -} -NK_API nk_bool -nk_button_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, const char *title, int len) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(style); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0; - - win = ctx->current; - layout = win->layout; - state = nk_widget(&bounds, ctx); - - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, - title, len, style->text_alignment, ctx->button_behavior, - style, in, ctx->style.font); -} -NK_API nk_bool -nk_button_text(struct nk_context *ctx, const char *title, int len) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_text_styled(ctx, &ctx->style.button, title, len); -} -NK_API nk_bool nk_button_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, const char *title) -{ - return nk_button_text_styled(ctx, style, title, nk_strlen(title)); -} -NK_API nk_bool nk_button_label(struct nk_context *ctx, const char *title) -{ - return nk_button_text(ctx, title, nk_strlen(title)); -} -NK_API nk_bool -nk_button_color(struct nk_context *ctx, struct nk_color color) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - struct nk_style_button button; - - int ret = 0; - struct nk_rect bounds; - struct nk_rect content; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - button = ctx->style.button; - button.normal = nk_style_item_color(color); - button.hover = nk_style_item_color(color); - button.active = nk_style_item_color(color); - ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds, - &button, in, ctx->button_behavior, &content); - nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button); - return ret; -} -NK_API nk_bool -nk_button_symbol_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, ctx->button_behavior, style, in, ctx->style.font); -} -NK_API nk_bool -nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_symbol_styled(ctx, &ctx->style.button, symbol); -} -NK_API nk_bool -nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style, - struct nk_image img) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds, - img, ctx->button_behavior, style, in); -} -NK_API nk_bool -nk_button_image(struct nk_context *ctx, struct nk_image img) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_image_styled(ctx, &ctx->style.button, img); -} -NK_API nk_bool -nk_button_symbol_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, text, len, align, ctx->button_behavior, - style, ctx->style.font, in); -} -NK_API nk_bool -nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, - const char* text, int len, nk_flags align) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align); -} -NK_API nk_bool nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *label, nk_flags align) -{ - return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align); -} -NK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol, - const char *title, nk_flags align) -{ - return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align); -} -NK_API nk_bool -nk_button_image_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, struct nk_image img, const char *text, - int len, nk_flags align) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, - bounds, img, text, len, align, ctx->button_behavior, - style, ctx->style.font, in); -} -NK_API nk_bool -nk_button_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{ - return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align); -} -NK_API nk_bool nk_button_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{ - return nk_button_image_text(ctx, img, label, nk_strlen(label), align); -} -NK_API nk_bool nk_button_image_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, struct nk_image img, - const char *label, nk_flags text_alignment) -{ - return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment); -} - - - - - -/* =============================================================== - * - * TOGGLE - * - * ===============================================================*/ -NK_LIB nk_bool -nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, - nk_flags *state, nk_bool active) -{ - nk_widget_state_reset(state); - if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) { - *state = NK_WIDGET_STATE_ACTIVE; - active = !active; - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, select)) - *state |= NK_WIDGET_STATE_LEFT; - return active; -} -NK_LIB void -nk_draw_checkbox(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_toggle *style, nk_bool active, - const struct nk_rect *label, const struct nk_rect *selector, - const struct nk_rect *cursors, const char *string, int len, - const struct nk_user_font *font) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - struct nk_text text; - - /* select correct colors/images */ - if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_active; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - text.text = style->text_normal; - } - - /* draw background and cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *selector, 0, style->border_color); - nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color); - } else nk_draw_image(out, *selector, &background->data.image, nk_white); - if (active) { - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *cursors, &cursor->data.image, nk_white); - else nk_fill_rect(out, *cursors, 0, cursor->data.color); - } - - text.padding.x = 0; - text.padding.y = 0; - text.background = style->text_background; - nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); -} -NK_LIB void -nk_draw_option(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_toggle *style, nk_bool active, - const struct nk_rect *label, const struct nk_rect *selector, - const struct nk_rect *cursors, const char *string, int len, - const struct nk_user_font *font) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - struct nk_text text; - - /* select correct colors/images */ - if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_active; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - text.text = style->text_normal; - } - - /* draw background and cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_circle(out, *selector, style->border_color); - nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color); - } else nk_draw_image(out, *selector, &background->data.image, nk_white); - if (active) { - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *cursors, &cursor->data.image, nk_white); - else nk_fill_circle(out, *cursors, cursor->data.color); - } - - text.padding.x = 0; - text.padding.y = 0; - text.background = style->text_background; - nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); -} -NK_LIB nk_bool -nk_do_toggle(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect r, - nk_bool *active, const char *str, int len, enum nk_toggle_type type, - const struct nk_style_toggle *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int was_active; - struct nk_rect bounds; - struct nk_rect select; - struct nk_rect cursor; - struct nk_rect label; - - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(font); - if (!out || !style || !font || !active) - return 0; - - r.w = NK_MAX(r.w, font->height + 2 * style->padding.x); - r.h = NK_MAX(r.h, font->height + 2 * style->padding.y); - - /* add additional touch padding for touch screen devices */ - bounds.x = r.x - style->touch_padding.x; - bounds.y = r.y - style->touch_padding.y; - bounds.w = r.w + 2 * style->touch_padding.x; - bounds.h = r.h + 2 * style->touch_padding.y; - - /* calculate the selector space */ - select.w = font->height; - select.h = select.w; - select.y = r.y + r.h/2.0f - select.h/2.0f; - select.x = r.x; - - /* calculate the bounds of the cursor inside the selector */ - cursor.x = select.x + style->padding.x + style->border; - cursor.y = select.y + style->padding.y + style->border; - cursor.w = select.w - (2 * style->padding.x + 2 * style->border); - cursor.h = select.h - (2 * style->padding.y + 2 * style->border); - - /* label behind the selector */ - label.x = select.x + select.w + style->spacing; - label.y = select.y; - label.w = NK_MAX(r.x + r.w, label.x) - label.x; - label.h = select.w; - - /* update selector */ - was_active = *active; - *active = nk_toggle_behavior(in, bounds, state, *active); - - /* draw selector */ - if (style->draw_begin) - style->draw_begin(out, style->userdata); - if (type == NK_TOGGLE_CHECK) { - nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font); - } else { - nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font); - } - if (style->draw_end) - style->draw_end(out, style->userdata); - return (was_active != *active); -} -/*---------------------------------------------------------------- - * - * CHECKBOX - * - * --------------------------------------------------------------*/ -NK_API nk_bool -nk_check_text(struct nk_context *ctx, const char *text, int len, nk_bool active) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return active; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return active; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active, - text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font); - return active; -} -NK_API unsigned int -nk_check_flags_text(struct nk_context *ctx, const char *text, int len, - unsigned int flags, unsigned int value) -{ - int old_active; - NK_ASSERT(ctx); - NK_ASSERT(text); - if (!ctx || !text) return flags; - old_active = (int)((flags & value) & value); - if (nk_check_text(ctx, text, len, old_active)) - flags |= value; - else flags &= ~value; - return flags; -} -NK_API nk_bool -nk_checkbox_text(struct nk_context *ctx, const char *text, int len, nk_bool *active) -{ - int old_val; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(active); - if (!ctx || !text || !active) return 0; - old_val = *active; - *active = nk_check_text(ctx, text, len, *active); - return old_val != *active; -} -NK_API nk_bool -nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len, - unsigned int *flags, unsigned int value) -{ - nk_bool active; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(flags); - if (!ctx || !text || !flags) return 0; - - active = (int)((*flags & value) & value); - if (nk_checkbox_text(ctx, text, len, &active)) { - if (active) *flags |= value; - else *flags &= ~value; - return 1; - } - return 0; -} -NK_API nk_bool nk_check_label(struct nk_context *ctx, const char *label, nk_bool active) -{ - return nk_check_text(ctx, label, nk_strlen(label), active); -} -NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label, - unsigned int flags, unsigned int value) -{ - return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value); -} -NK_API nk_bool nk_checkbox_label(struct nk_context *ctx, const char *label, nk_bool *active) -{ - return nk_checkbox_text(ctx, label, nk_strlen(label), active); -} -NK_API nk_bool nk_checkbox_flags_label(struct nk_context *ctx, const char *label, - unsigned int *flags, unsigned int value) -{ - return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value); -} -/*---------------------------------------------------------------- - * - * OPTION - * - * --------------------------------------------------------------*/ -NK_API nk_bool -nk_option_text(struct nk_context *ctx, const char *text, int len, nk_bool is_active) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return is_active; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return (int)state; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active, - text, len, NK_TOGGLE_OPTION, &style->option, in, style->font); - return is_active; -} -NK_API nk_bool -nk_radio_text(struct nk_context *ctx, const char *text, int len, nk_bool *active) -{ - int old_value; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(active); - if (!ctx || !text || !active) return 0; - old_value = *active; - *active = nk_option_text(ctx, text, len, old_value); - return old_value != *active; -} -NK_API nk_bool -nk_option_label(struct nk_context *ctx, const char *label, nk_bool active) -{ - return nk_option_text(ctx, label, nk_strlen(label), active); -} -NK_API nk_bool -nk_radio_label(struct nk_context *ctx, const char *label, nk_bool *active) -{ - return nk_radio_text(ctx, label, nk_strlen(label), active); -} - - - - - -/* =============================================================== - * - * SELECTABLE - * - * ===============================================================*/ -NK_LIB void -nk_draw_selectable(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_selectable *style, nk_bool active, - const struct nk_rect *bounds, - const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym, - const char *string, int len, nk_flags align, const struct nk_user_font *font) -{ - const struct nk_style_item *background; - struct nk_text text; - text.padding = style->padding; - - /* select correct colors/images */ - if (!active) { - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->pressed; - text.text = style->text_pressed; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text.text = style->text_hover; - } else { - background = &style->normal; - text.text = style->text_normal; - } - } else { - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->pressed_active; - text.text = style->text_pressed_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover_active; - text.text = style->text_hover_active; - } else { - background = &style->normal_active; - text.text = style->text_normal_active; - } - } - /* draw selectable background and text */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - text.background = background->data.color; - } - if (icon) { - if (img) nk_draw_image(out, *icon, img, nk_white); - else nk_draw_symbol(out, sym, *icon, text.background, text.text, 1, font); - } - nk_widget_text(out, *bounds, string, len, &text, align, font); -} -NK_LIB nk_bool -nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, - const struct nk_style_selectable *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int old_value; - struct nk_rect touch; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* remove padding */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - - /* update button */ - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, 0,0,NK_SYMBOL_NONE, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} -NK_LIB nk_bool -nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, - const struct nk_image *img, const struct nk_style_selectable *style, - const struct nk_input *in, const struct nk_user_font *font) -{ - nk_bool old_value; - struct nk_rect touch; - struct nk_rect icon; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* toggle behavior */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, NK_SYMBOL_NONE, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} -NK_LIB nk_bool -nk_do_selectable_symbol(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, - enum nk_symbol_type sym, const struct nk_style_selectable *style, - const struct nk_input *in, const struct nk_user_font *font) -{ - int old_value; - struct nk_rect touch; - struct nk_rect icon; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* toggle behavior */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, &icon, 0, sym, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} - -NK_API nk_bool -nk_selectable_text(struct nk_context *ctx, const char *str, int len, - nk_flags align, nk_bool *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, &style->selectable, in, style->font); -} -NK_API nk_bool -nk_selectable_image_text(struct nk_context *ctx, struct nk_image img, - const char *str, int len, nk_flags align, nk_bool *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, &img, &style->selectable, in, style->font); -} -NK_API nk_bool -nk_selectable_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *str, int len, nk_flags align, nk_bool *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable_symbol(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, sym, &style->selectable, in, style->font); -} -NK_API nk_bool -nk_selectable_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *title, nk_flags align, nk_bool *value) -{ - return nk_selectable_symbol_text(ctx, sym, title, nk_strlen(title), align, value); -} -NK_API nk_bool nk_select_text(struct nk_context *ctx, const char *str, int len, - nk_flags align, nk_bool value) -{ - nk_selectable_text(ctx, str, len, align, &value);return value; -} -NK_API nk_bool nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool *value) -{ - return nk_selectable_text(ctx, str, nk_strlen(str), align, value); -} -NK_API nk_bool nk_selectable_image_label(struct nk_context *ctx,struct nk_image img, - const char *str, nk_flags align, nk_bool *value) -{ - return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value); -} -NK_API nk_bool nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool value) -{ - nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value; -} -NK_API nk_bool nk_select_image_label(struct nk_context *ctx, struct nk_image img, - const char *str, nk_flags align, nk_bool value) -{ - nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value; -} -NK_API nk_bool nk_select_image_text(struct nk_context *ctx, struct nk_image img, - const char *str, int len, nk_flags align, nk_bool value) -{ - nk_selectable_image_text(ctx, img, str, len, align, &value);return value; -} -NK_API nk_bool -nk_select_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *title, int title_len, nk_flags align, nk_bool value) -{ - nk_selectable_symbol_text(ctx, sym, title, title_len, align, &value);return value; -} -NK_API nk_bool -nk_select_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *title, nk_flags align, nk_bool value) -{ - return nk_select_symbol_text(ctx, sym, title, nk_strlen(title), align, value); -} - - - - - -/* =============================================================== - * - * SLIDER - * - * ===============================================================*/ -NK_LIB float -nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, - struct nk_rect *visual_cursor, struct nk_input *in, - struct nk_rect bounds, float slider_min, float slider_max, float slider_value, - float slider_step, float slider_steps) -{ - int left_mouse_down; - int left_mouse_click_in_cursor; - - /* check if visual cursor is being dragged */ - nk_widget_state_reset(state); - left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, *visual_cursor, nk_true); - - if (left_mouse_down && left_mouse_click_in_cursor) { - float ratio = 0; - const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f); - const float pxstep = bounds.w / slider_steps; - - /* only update value if the next slider step is reached */ - *state = NK_WIDGET_STATE_ACTIVE; - if (NK_ABS(d) >= pxstep) { - const float steps = (float)((int)(NK_ABS(d) / pxstep)); - slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps); - slider_value = NK_CLAMP(slider_min, slider_value, slider_max); - ratio = (slider_value - slider_min)/slider_step; - logical_cursor->x = bounds.x + (logical_cursor->w * ratio); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x; - } - } - - /* slider widget state */ - if (nk_input_is_mouse_hovering_rect(in, bounds)) - *state = NK_WIDGET_STATE_HOVERED; - if (*state & NK_WIDGET_STATE_HOVER && - !nk_input_is_mouse_prev_hovering_rect(in, bounds)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, bounds)) - *state |= NK_WIDGET_STATE_LEFT; - return slider_value; -} -NK_LIB void -nk_draw_slider(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_slider *style, const struct nk_rect *bounds, - const struct nk_rect *visual_cursor, float min, float value, float max) -{ - struct nk_rect fill; - struct nk_rect bar; - const struct nk_style_item *background; - - /* select correct slider images/colors */ - struct nk_color bar_color; - const struct nk_style_item *cursor; - - NK_UNUSED(min); - NK_UNUSED(max); - NK_UNUSED(value); - - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - bar_color = style->bar_active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - bar_color = style->bar_hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - bar_color = style->bar_normal; - cursor = &style->cursor_normal; - } - /* calculate slider background bar */ - bar.x = bounds->x; - bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12; - bar.w = bounds->w; - bar.h = bounds->h/6; - - /* filled background bar style */ - fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x; - fill.x = bar.x; - fill.y = bar.y; - fill.h = bar.h; - - /* draw background */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } - - /* draw slider bar */ - nk_fill_rect(out, bar, style->rounding, bar_color); - nk_fill_rect(out, fill, style->rounding, style->bar_filled); - - /* draw cursor */ - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white); - else nk_fill_circle(out, *visual_cursor, cursor->data.color); -} -NK_LIB float -nk_do_slider(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - float min, float val, float max, float step, - const struct nk_style_slider *style, struct nk_input *in, - const struct nk_user_font *font) -{ - float slider_range; - float slider_min; - float slider_max; - float slider_value; - float slider_steps; - float cursor_offset; - - struct nk_rect visual_cursor; - struct nk_rect logical_cursor; - - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style) - return 0; - - /* remove padding from slider bounds */ - bounds.x = bounds.x + style->padding.x; - bounds.y = bounds.y + style->padding.y; - bounds.h = NK_MAX(bounds.h, 2*style->padding.y); - bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x); - bounds.w -= 2 * style->padding.x; - bounds.h -= 2 * style->padding.y; - - /* optional buttons */ - if (style->show_buttons) { - nk_flags ws; - struct nk_rect button; - button.y = bounds.y; - button.w = bounds.h; - button.h = bounds.h; - - /* decrement button */ - button.x = bounds.x; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT, - &style->dec_button, in, font)) - val -= step; - - /* increment button */ - button.x = (bounds.x + bounds.w) - button.w; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT, - &style->inc_button, in, font)) - val += step; - - bounds.x = bounds.x + button.w + style->spacing.x; - bounds.w = bounds.w - (2*button.w + 2*style->spacing.x); - } - - /* remove one cursor size to support visual cursor */ - bounds.x += style->cursor_size.x*0.5f; - bounds.w -= style->cursor_size.x; - - /* make sure the provided values are correct */ - slider_max = NK_MAX(min, max); - slider_min = NK_MIN(min, max); - slider_value = NK_CLAMP(slider_min, val, slider_max); - slider_range = slider_max - slider_min; - slider_steps = slider_range / step; - cursor_offset = (slider_value - slider_min) / step; - - /* calculate cursor - Basically you have two cursors. One for visual representation and interaction - and one for updating the actual cursor value. */ - logical_cursor.h = bounds.h; - logical_cursor.w = bounds.w / slider_steps; - logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset); - logical_cursor.y = bounds.y; - - visual_cursor.h = style->cursor_size.y; - visual_cursor.w = style->cursor_size.x; - visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f; - visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; - - slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor, - in, bounds, slider_min, slider_max, slider_value, step, slider_steps); - visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; - - /* draw slider */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max); - if (style->draw_end) style->draw_end(out, style->userdata); - return slider_value; -} -NK_API nk_bool -nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value, - float value_step) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_input *in; - const struct nk_style *style; - - int ret = 0; - float old_value; - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(value); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return ret; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return ret; - in = (/*state == NK_WIDGET_ROM || */ layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - old_value = *value; - *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value, - old_value, max_value, value_step, &style->slider, in, style->font); - return (old_value > *value || old_value < *value); -} -NK_API float -nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step) -{ - nk_slider_float(ctx, min, &val, max, step); return val; -} -NK_API int -nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step) -{ - float value = (float)val; - nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); - return (int)value; -} -NK_API nk_bool -nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step) -{ - int ret; - float value = (float)*val; - ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); - *val = (int)value; - return ret; -} - - - - - -/* =============================================================== - * - * PROGRESS - * - * ===============================================================*/ -NK_LIB nk_size -nk_progress_behavior(nk_flags *state, struct nk_input *in, - struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable) -{ - int left_mouse_down = 0; - int left_mouse_click_in_cursor = 0; - - nk_widget_state_reset(state); - if (!in || !modifiable) return value; - left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, cursor, nk_true); - if (nk_input_is_mouse_hovering_rect(in, r)) - *state = NK_WIDGET_STATE_HOVERED; - - if (in && left_mouse_down && left_mouse_click_in_cursor) { - if (left_mouse_down && left_mouse_click_in_cursor) { - float ratio = NK_MAX(0, (float)(in->mouse.pos.x - cursor.x)) / (float)cursor.w; - value = (nk_size)NK_CLAMP(0, (float)max * ratio, (float)max); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor.x + cursor.w/2.0f; - *state |= NK_WIDGET_STATE_ACTIVE; - } - } - /* set progressbar widget state */ - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, r)) - *state |= NK_WIDGET_STATE_LEFT; - return value; -} -NK_LIB void -nk_draw_progress(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_progress *style, const struct nk_rect *bounds, - const struct nk_rect *scursor, nk_size value, nk_size max) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - - NK_UNUSED(max); - NK_UNUSED(value); - - /* select correct colors/images to draw */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER){ - background = &style->hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, *bounds, &background->data.image, nk_white); - - /* draw cursor */ - if (cursor->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *scursor, style->rounding, cursor->data.color); - nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white); -} -NK_LIB nk_size -nk_do_progress(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - nk_size value, nk_size max, nk_bool modifiable, - const struct nk_style_progress *style, struct nk_input *in) -{ - float prog_scale; - nk_size prog_value; - struct nk_rect cursor; - - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style) return 0; - - /* calculate progressbar cursor */ - cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border); - cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border); - cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border)); - prog_scale = (float)value / (float)max; - - /* update progressbar */ - prog_value = NK_MIN(value, max); - prog_value = nk_progress_behavior(state, in, bounds, cursor,max, prog_value, modifiable); - cursor.w = cursor.w * prog_scale; - - /* draw progressbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_progress(out, *state, style, &bounds, &cursor, value, max); - if (style->draw_end) style->draw_end(out, style->userdata); - return prog_value; -} -NK_API nk_bool -nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, nk_bool is_modifyable) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - nk_size old_value; - - NK_ASSERT(ctx); - NK_ASSERT(cur); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !cur) - return 0; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - old_value = *cur; - *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds, - *cur, max, is_modifyable, &style->progress, in); - return (*cur != old_value); -} -NK_API nk_size -nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, nk_bool modifyable) -{ - nk_progress(ctx, &cur, max, modifyable); - return cur; -} - - - - - -/* =============================================================== - * - * SCROLLBAR - * - * ===============================================================*/ -NK_LIB float -nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, - int has_scrolling, const struct nk_rect *scroll, - const struct nk_rect *cursor, const struct nk_rect *empty0, - const struct nk_rect *empty1, float scroll_offset, - float target, float scroll_step, enum nk_orientation o) -{ - nk_flags ws = 0; - int left_mouse_down; - int left_mouse_clicked; - int left_mouse_click_in_cursor; - float scroll_delta; - - nk_widget_state_reset(state); - if (!in) return scroll_offset; - - left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked; - left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, *cursor, nk_true); - if (nk_input_is_mouse_hovering_rect(in, *scroll)) - *state = NK_WIDGET_STATE_HOVERED; - - scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x; - if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) { - /* update cursor by mouse dragging */ - float pixel, delta; - *state = NK_WIDGET_STATE_ACTIVE; - if (o == NK_VERTICAL) { - float cursor_y; - pixel = in->mouse.delta.y; - delta = (pixel / scroll->h) * target; - scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h); - cursor_y = scroll->y + ((scroll_offset/target) * scroll->h); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f; - } else { - float cursor_x; - pixel = in->mouse.delta.x; - delta = (pixel / scroll->w) * target; - scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w); - cursor_x = scroll->x + ((scroll_offset/target) * scroll->w); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f; - } - } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)|| - nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) { - /* scroll page up by click on empty space or shortcut */ - if (o == NK_VERTICAL) - scroll_offset = NK_MAX(0, scroll_offset - scroll->h); - else scroll_offset = NK_MAX(0, scroll_offset - scroll->w); - } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) || - nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) { - /* scroll page down by click on empty space or shortcut */ - if (o == NK_VERTICAL) - scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h); - else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w); - } else if (has_scrolling) { - if ((scroll_delta < 0 || (scroll_delta > 0))) { - /* update cursor by mouse scrolling */ - scroll_offset = scroll_offset + scroll_step * (-scroll_delta); - if (o == NK_VERTICAL) - scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h); - else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w); - } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) { - /* update cursor to the beginning */ - if (o == NK_VERTICAL) scroll_offset = 0; - } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) { - /* update cursor to the end */ - if (o == NK_VERTICAL) scroll_offset = target - scroll->h; - } - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll)) - *state |= NK_WIDGET_STATE_LEFT; - return scroll_offset; -} -NK_LIB void -nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_scrollbar *style, const struct nk_rect *bounds, - const struct nk_rect *scroll) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - - /* select correct colors/images to draw */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } else { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } - - /* draw cursor */ - if (cursor->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color); - nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color); - } else nk_draw_image(out, *scroll, &cursor->data.image, nk_white); -} -NK_LIB float -nk_do_scrollbarv(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, - float offset, float target, float step, float button_pixel_inc, - const struct nk_style_scrollbar *style, struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect empty_north; - struct nk_rect empty_south; - struct nk_rect cursor; - - float scroll_step; - float scroll_offset; - float scroll_off; - float scroll_ratio; - - NK_ASSERT(out); - NK_ASSERT(style); - NK_ASSERT(state); - if (!out || !style) return 0; - - scroll.w = NK_MAX(scroll.w, 1); - scroll.h = NK_MAX(scroll.h, 0); - if (target <= scroll.h) return 0; - - /* optional scrollbar buttons */ - if (style->show_buttons) { - nk_flags ws; - float scroll_h; - struct nk_rect button; - - button.x = scroll.x; - button.w = scroll.w; - button.h = scroll.w; - - scroll_h = NK_MAX(scroll.h - 2 * button.h,0); - scroll_step = NK_MIN(step, button_pixel_inc); - - /* decrement button */ - button.y = scroll.y; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, - NK_BUTTON_REPEATER, &style->dec_button, in, font)) - offset = offset - scroll_step; - - /* increment button */ - button.y = scroll.y + scroll.h - button.h; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, - NK_BUTTON_REPEATER, &style->inc_button, in, font)) - offset = offset + scroll_step; - - scroll.y = scroll.y + button.h; - scroll.h = scroll_h; - } - - /* calculate scrollbar constants */ - scroll_step = NK_MIN(step, scroll.h); - scroll_offset = NK_CLAMP(0, offset, target - scroll.h); - scroll_ratio = scroll.h / target; - scroll_off = scroll_offset / target; - - /* calculate scrollbar cursor bounds */ - cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0); - cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y; - cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x); - cursor.x = scroll.x + style->border + style->padding.x; - - /* calculate empty space around cursor */ - empty_north.x = scroll.x; - empty_north.y = scroll.y; - empty_north.w = scroll.w; - empty_north.h = NK_MAX(cursor.y - scroll.y, 0); - - empty_south.x = scroll.x; - empty_south.y = cursor.y + cursor.h; - empty_south.w = scroll.w; - empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0); - - /* update scrollbar */ - scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, - &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL); - scroll_off = scroll_offset / target; - cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y; - - /* draw scrollbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_scrollbar(out, *state, style, &scroll, &cursor); - if (style->draw_end) style->draw_end(out, style->userdata); - return scroll_offset; -} -NK_LIB float -nk_do_scrollbarh(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, - float offset, float target, float step, float button_pixel_inc, - const struct nk_style_scrollbar *style, struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect cursor; - struct nk_rect empty_west; - struct nk_rect empty_east; - - float scroll_step; - float scroll_offset; - float scroll_off; - float scroll_ratio; - - NK_ASSERT(out); - NK_ASSERT(style); - if (!out || !style) return 0; - - /* scrollbar background */ - scroll.h = NK_MAX(scroll.h, 1); - scroll.w = NK_MAX(scroll.w, 2 * scroll.h); - if (target <= scroll.w) return 0; - - /* optional scrollbar buttons */ - if (style->show_buttons) { - nk_flags ws; - float scroll_w; - struct nk_rect button; - button.y = scroll.y; - button.w = scroll.h; - button.h = scroll.h; - - scroll_w = scroll.w - 2 * button.w; - scroll_step = NK_MIN(step, button_pixel_inc); - - /* decrement button */ - button.x = scroll.x; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, - NK_BUTTON_REPEATER, &style->dec_button, in, font)) - offset = offset - scroll_step; - - /* increment button */ - button.x = scroll.x + scroll.w - button.w; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, - NK_BUTTON_REPEATER, &style->inc_button, in, font)) - offset = offset + scroll_step; - - scroll.x = scroll.x + button.w; - scroll.w = scroll_w; - } - - /* calculate scrollbar constants */ - scroll_step = NK_MIN(step, scroll.w); - scroll_offset = NK_CLAMP(0, offset, target - scroll.w); - scroll_ratio = scroll.w / target; - scroll_off = scroll_offset / target; - - /* calculate cursor bounds */ - cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x); - cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x; - cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y); - cursor.y = scroll.y + style->border + style->padding.y; - - /* calculate empty space around cursor */ - empty_west.x = scroll.x; - empty_west.y = scroll.y; - empty_west.w = cursor.x - scroll.x; - empty_west.h = scroll.h; - - empty_east.x = cursor.x + cursor.w; - empty_east.y = scroll.y; - empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w); - empty_east.h = scroll.h; - - /* update scrollbar */ - scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, - &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL); - scroll_off = scroll_offset / target; - cursor.x = scroll.x + (scroll_off * scroll.w); - - /* draw scrollbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_scrollbar(out, *state, style, &scroll, &cursor); - if (style->draw_end) style->draw_end(out, style->userdata); - return scroll_offset; -} - - - - - -/* =============================================================== - * - * TEXT EDITOR - * - * ===============================================================*/ -/* stb_textedit.h - v1.8 - public domain - Sean Barrett */ -struct nk_text_find { - float x,y; /* position of n'th character */ - float height; /* height of line */ - int first_char, length; /* first char of row, and length */ - int prev_first; /*_ first char of previous row */ -}; - -struct nk_text_edit_row { - float x0,x1; - /* starting x location, end x location (allows for align=right, etc) */ - float baseline_y_delta; - /* position of baseline relative to previous row's baseline*/ - float ymin,ymax; - /* height of row above and below baseline */ - int num_chars; -}; - -/* forward declarations */ -NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int); -NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int); -NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int); -#define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) - -NK_INTERN float -nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id, - const struct nk_user_font *font) -{ - int len = 0; - nk_rune unicode = 0; - const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len); - return font->width(font->userdata, font->height, str, len); -} -NK_INTERN void -nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit, - int line_start_id, float row_height, const struct nk_user_font *font) -{ - int l; - int glyphs = 0; - nk_rune unicode; - const char *remaining; - int len = nk_str_len_char(&edit->string); - const char *end = nk_str_get_const(&edit->string) + len; - const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l); - const struct nk_vec2 size = nk_text_calculate_text_bounds(font, - text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE); - - r->x0 = 0.0f; - r->x1 = size.x; - r->baseline_y_delta = size.y; - r->ymin = 0.0f; - r->ymax = size.y; - r->num_chars = glyphs; -} -NK_INTERN int -nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y, - const struct nk_user_font *font, float row_height) -{ - struct nk_text_edit_row r; - int n = edit->string.len; - float base_y = 0, prev_x; - int i=0, k; - - r.x0 = r.x1 = 0; - r.ymin = r.ymax = 0; - r.num_chars = 0; - - /* search rows to find one that straddles 'y' */ - while (i < n) { - nk_textedit_layout_row(&r, edit, i, row_height, font); - if (r.num_chars <= 0) - return n; - - if (i==0 && y < base_y + r.ymin) - return 0; - - if (y < base_y + r.ymax) - break; - - i += r.num_chars; - base_y += r.baseline_y_delta; - } - - /* below all text, return 'after' last character */ - if (i >= n) - return n; - - /* check if it's before the beginning of the line */ - if (x < r.x0) - return i; - - /* check if it's before the end of the line */ - if (x < r.x1) { - /* search characters in row for one that straddles 'x' */ - k = i; - prev_x = r.x0; - for (i=0; i < r.num_chars; ++i) { - float w = nk_textedit_get_width(edit, k, i, font); - if (x < prev_x+w) { - if (x < prev_x+w/2) - return k+i; - else return k+i+1; - } - prev_x += w; - } - /* shouldn't happen, but if it does, fall through to end-of-line case */ - } - - /* if the last character is a newline, return that. - * otherwise return 'after' the last character */ - if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n') - return i+r.num_chars-1; - else return i+r.num_chars; -} -NK_LIB void -nk_textedit_click(struct nk_text_edit *state, float x, float y, - const struct nk_user_font *font, float row_height) -{ - /* API click: on mouse down, move the cursor to the clicked location, - * and reset the selection */ - state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height); - state->select_start = state->cursor; - state->select_end = state->cursor; - state->has_preferred_x = 0; -} -NK_LIB void -nk_textedit_drag(struct nk_text_edit *state, float x, float y, - const struct nk_user_font *font, float row_height) -{ - /* API drag: on mouse drag, move the cursor and selection endpoint - * to the clicked location */ - int p = nk_textedit_locate_coord(state, x, y, font, row_height); - if (state->select_start == state->select_end) - state->select_start = state->cursor; - state->cursor = state->select_end = p; -} -NK_INTERN void -nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state, - int n, int single_line, const struct nk_user_font *font, float row_height) -{ - /* find the x/y location of a character, and remember info about the previous - * row in case we get a move-up event (for page up, we'll have to rescan) */ - struct nk_text_edit_row r; - int prev_start = 0; - int z = state->string.len; - int i=0, first; - - nk_zero_struct(r); - if (n == z) { - /* if it's at the end, then find the last line -- simpler than trying to - explicitly handle this case in the regular code */ - nk_textedit_layout_row(&r, state, 0, row_height, font); - if (single_line) { - find->first_char = 0; - find->length = z; - } else { - while (i < z) { - prev_start = i; - i += r.num_chars; - nk_textedit_layout_row(&r, state, i, row_height, font); - } - - find->first_char = i; - find->length = r.num_chars; - } - find->x = r.x1; - find->y = r.ymin; - find->height = r.ymax - r.ymin; - find->prev_first = prev_start; - return; - } - - /* search rows to find the one that straddles character n */ - find->y = 0; - - for(;;) { - nk_textedit_layout_row(&r, state, i, row_height, font); - if (n < i + r.num_chars) break; - prev_start = i; - i += r.num_chars; - find->y += r.baseline_y_delta; - } - - find->first_char = first = i; - find->length = r.num_chars; - find->height = r.ymax - r.ymin; - find->prev_first = prev_start; - - /* now scan to find xpos */ - find->x = r.x0; - for (i=0; first+i < n; ++i) - find->x += nk_textedit_get_width(state, first, i, font); -} -NK_INTERN void -nk_textedit_clamp(struct nk_text_edit *state) -{ - /* make the selection/cursor state valid if client altered the string */ - int n = state->string.len; - if (NK_TEXT_HAS_SELECTION(state)) { - if (state->select_start > n) state->select_start = n; - if (state->select_end > n) state->select_end = n; - /* if clamping forced them to be equal, move the cursor to match */ - if (state->select_start == state->select_end) - state->cursor = state->select_start; - } - if (state->cursor > n) state->cursor = n; -} -NK_API void -nk_textedit_delete(struct nk_text_edit *state, int where, int len) -{ - /* delete characters while updating undo */ - nk_textedit_makeundo_delete(state, where, len); - nk_str_delete_runes(&state->string, where, len); - state->has_preferred_x = 0; -} -NK_API void -nk_textedit_delete_selection(struct nk_text_edit *state) -{ - /* delete the section */ - nk_textedit_clamp(state); - if (NK_TEXT_HAS_SELECTION(state)) { - if (state->select_start < state->select_end) { - nk_textedit_delete(state, state->select_start, - state->select_end - state->select_start); - state->select_end = state->cursor = state->select_start; - } else { - nk_textedit_delete(state, state->select_end, - state->select_start - state->select_end); - state->select_start = state->cursor = state->select_end; - } - state->has_preferred_x = 0; - } -} -NK_INTERN void -nk_textedit_sortselection(struct nk_text_edit *state) -{ - /* canonicalize the selection so start <= end */ - if (state->select_end < state->select_start) { - int temp = state->select_end; - state->select_end = state->select_start; - state->select_start = temp; - } -} -NK_INTERN void -nk_textedit_move_to_first(struct nk_text_edit *state) -{ - /* move cursor to first character of selection */ - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_sortselection(state); - state->cursor = state->select_start; - state->select_end = state->select_start; - state->has_preferred_x = 0; - } -} -NK_INTERN void -nk_textedit_move_to_last(struct nk_text_edit *state) -{ - /* move cursor to last character of selection */ - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_sortselection(state); - nk_textedit_clamp(state); - state->cursor = state->select_end; - state->select_start = state->select_end; - state->has_preferred_x = 0; - } -} -NK_INTERN int -nk_is_word_boundary( struct nk_text_edit *state, int idx) -{ - int len; - nk_rune c; - if (idx <= 0) return 1; - if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1; - return (c == ' ' || c == '\t' ||c == 0x3000 || c == ',' || c == ';' || - c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || - c == '|'); -} -NK_INTERN int -nk_textedit_move_to_word_previous(struct nk_text_edit *state) -{ - int c = state->cursor - 1; - while( c >= 0 && !nk_is_word_boundary(state, c)) - --c; - - if( c < 0 ) - c = 0; - - return c; -} -NK_INTERN int -nk_textedit_move_to_word_next(struct nk_text_edit *state) -{ - const int len = state->string.len; - int c = state->cursor+1; - while( c < len && !nk_is_word_boundary(state, c)) - ++c; - - if( c > len ) - c = len; - - return c; -} -NK_INTERN void -nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state) -{ - /* update selection and cursor to match each other */ - if (!NK_TEXT_HAS_SELECTION(state)) - state->select_start = state->select_end = state->cursor; - else state->cursor = state->select_end; -} -NK_API nk_bool -nk_textedit_cut(struct nk_text_edit *state) -{ - /* API cut: delete selection */ - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - return 0; - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_delete_selection(state); /* implicitly clamps */ - state->has_preferred_x = 0; - return 1; - } - return 0; -} -NK_API nk_bool -nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len) -{ - /* API paste: replace existing selection with passed-in text */ - int glyphs; - const char *text = (const char *) ctext; - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0; - - /* if there's a selection, the paste should delete it */ - nk_textedit_clamp(state); - nk_textedit_delete_selection(state); - - /* try to insert the characters */ - glyphs = nk_utf_len(ctext, len); - if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) { - nk_textedit_makeundo_insert(state, state->cursor, glyphs); - state->cursor += len; - state->has_preferred_x = 0; - return 1; - } - /* remove the undo since we didn't actually insert the characters */ - if (state->undo.undo_point) - --state->undo.undo_point; - return 0; -} -NK_API void -nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len) -{ - nk_rune unicode; - int glyph_len; - int text_len = 0; - - NK_ASSERT(state); - NK_ASSERT(text); - if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return; - - glyph_len = nk_utf_decode(text, &unicode, total_len); - while ((text_len < total_len) && glyph_len) - { - /* don't insert a backward delete, just process the event */ - if (unicode == 127) goto next; - /* can't add newline in single-line mode */ - if (unicode == '\n' && state->single_line) goto next; - /* filter incoming text */ - if (state->filter && !state->filter(state, unicode)) goto next; - - if (!NK_TEXT_HAS_SELECTION(state) && - state->cursor < state->string.len) - { - if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) { - nk_textedit_makeundo_replace(state, state->cursor, 1, 1); - nk_str_delete_runes(&state->string, state->cursor, 1); - } - if (nk_str_insert_text_utf8(&state->string, state->cursor, - text+text_len, 1)) - { - ++state->cursor; - state->has_preferred_x = 0; - } - } else { - nk_textedit_delete_selection(state); /* implicitly clamps */ - if (nk_str_insert_text_utf8(&state->string, state->cursor, - text+text_len, 1)) - { - nk_textedit_makeundo_insert(state, state->cursor, 1); - ++state->cursor; - state->has_preferred_x = 0; - } - } - next: - text_len += glyph_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); - } -} -NK_LIB void -nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, - const struct nk_user_font *font, float row_height) -{ -retry: - switch (key) - { - case NK_KEY_NONE: - case NK_KEY_CTRL: - case NK_KEY_ENTER: - case NK_KEY_SHIFT: - case NK_KEY_TAB: - case NK_KEY_COPY: - case NK_KEY_CUT: - case NK_KEY_PASTE: - case NK_KEY_MAX: - default: break; - case NK_KEY_TEXT_UNDO: - nk_textedit_undo(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_REDO: - nk_textedit_redo(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_SELECT_ALL: - nk_textedit_select_all(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_INSERT_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - state->mode = NK_TEXT_EDIT_MODE_INSERT; - break; - case NK_KEY_TEXT_REPLACE_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - state->mode = NK_TEXT_EDIT_MODE_REPLACE; - break; - case NK_KEY_TEXT_RESET_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_INSERT || - state->mode == NK_TEXT_EDIT_MODE_REPLACE) - state->mode = NK_TEXT_EDIT_MODE_VIEW; - break; - - case NK_KEY_LEFT: - if (shift_mod) { - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - /* move selection left */ - if (state->select_end > 0) - --state->select_end; - state->cursor = state->select_end; - state->has_preferred_x = 0; - } else { - /* if currently there's a selection, - * move cursor to start of selection */ - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - else if (state->cursor > 0) - --state->cursor; - state->has_preferred_x = 0; - } break; - - case NK_KEY_RIGHT: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - /* move selection right */ - ++state->select_end; - nk_textedit_clamp(state); - state->cursor = state->select_end; - state->has_preferred_x = 0; - } else { - /* if currently there's a selection, - * move cursor to end of selection */ - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - else ++state->cursor; - nk_textedit_clamp(state); - state->has_preferred_x = 0; - } break; - - case NK_KEY_TEXT_WORD_LEFT: - if (shift_mod) { - if( !NK_TEXT_HAS_SELECTION( state ) ) - nk_textedit_prep_selection_at_cursor(state); - state->cursor = nk_textedit_move_to_word_previous(state); - state->select_end = state->cursor; - nk_textedit_clamp(state ); - } else { - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - else { - state->cursor = nk_textedit_move_to_word_previous(state); - nk_textedit_clamp(state ); - } - } break; - - case NK_KEY_TEXT_WORD_RIGHT: - if (shift_mod) { - if( !NK_TEXT_HAS_SELECTION( state ) ) - nk_textedit_prep_selection_at_cursor(state); - state->cursor = nk_textedit_move_to_word_next(state); - state->select_end = state->cursor; - nk_textedit_clamp(state); - } else { - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - else { - state->cursor = nk_textedit_move_to_word_next(state); - nk_textedit_clamp(state ); - } - } break; - - case NK_KEY_DOWN: { - struct nk_text_find find; - struct nk_text_edit_row row; - int i, sel = shift_mod; - - if (state->single_line) { - /* on windows, up&down in single-line behave like left&right */ - key = NK_KEY_RIGHT; - goto retry; - } - - if (sel) - nk_textedit_prep_selection_at_cursor(state); - else if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - - /* compute current position of cursor point */ - nk_textedit_clamp(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - /* now find character position down a row */ - if (find.length) - { - float x; - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - int start = find.first_char + find.length; - - state->cursor = start; - nk_textedit_layout_row(&row, state, state->cursor, row_height, font); - x = row.x0; - - for (i=0; i < row.num_chars && x < row.x1; ++i) { - float dx = nk_textedit_get_width(state, start, i, font); - x += dx; - if (x > goal_x) - break; - ++state->cursor; - } - nk_textedit_clamp(state); - - state->has_preferred_x = 1; - state->preferred_x = goal_x; - if (sel) - state->select_end = state->cursor; - } - } break; - - case NK_KEY_UP: { - struct nk_text_find find; - struct nk_text_edit_row row; - int i, sel = shift_mod; - - if (state->single_line) { - /* on windows, up&down become left&right */ - key = NK_KEY_LEFT; - goto retry; - } - - if (sel) - nk_textedit_prep_selection_at_cursor(state); - else if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - - /* compute current position of cursor point */ - nk_textedit_clamp(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - /* can only go up if there's a previous row */ - if (find.prev_first != find.first_char) { - /* now find character position up a row */ - float x; - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - - state->cursor = find.prev_first; - nk_textedit_layout_row(&row, state, state->cursor, row_height, font); - x = row.x0; - - for (i=0; i < row.num_chars && x < row.x1; ++i) { - float dx = nk_textedit_get_width(state, find.prev_first, i, font); - x += dx; - if (x > goal_x) - break; - ++state->cursor; - } - nk_textedit_clamp(state); - - state->has_preferred_x = 1; - state->preferred_x = goal_x; - if (sel) state->select_end = state->cursor; - } - } break; - - case NK_KEY_DEL: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - break; - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_delete_selection(state); - else { - int n = state->string.len; - if (state->cursor < n) - nk_textedit_delete(state, state->cursor, 1); - } - state->has_preferred_x = 0; - break; - - case NK_KEY_BACKSPACE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - break; - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_delete_selection(state); - else { - nk_textedit_clamp(state); - if (state->cursor > 0) { - nk_textedit_delete(state, state->cursor-1, 1); - --state->cursor; - } - } - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_START: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - state->cursor = state->select_end = 0; - state->has_preferred_x = 0; - } else { - state->cursor = state->select_start = state->select_end = 0; - state->has_preferred_x = 0; - } - break; - - case NK_KEY_TEXT_END: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - state->cursor = state->select_end = state->string.len; - state->has_preferred_x = 0; - } else { - state->cursor = state->string.len; - state->select_start = state->select_end = 0; - state->has_preferred_x = 0; - } - break; - - case NK_KEY_TEXT_LINE_START: { - if (shift_mod) { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - if (state->string.len && state->cursor == state->string.len) - --state->cursor; - nk_textedit_find_charpos(&find, state,state->cursor, state->single_line, - font, row_height); - state->cursor = state->select_end = find.first_char; - state->has_preferred_x = 0; - } else { - struct nk_text_find find; - if (state->string.len && state->cursor == state->string.len) - --state->cursor; - nk_textedit_clamp(state); - nk_textedit_move_to_first(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - state->cursor = find.first_char; - state->has_preferred_x = 0; - } - } break; - - case NK_KEY_TEXT_LINE_END: { - if (shift_mod) { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') - --state->cursor; - state->select_end = state->cursor; - } else { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_move_to_first(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') - --state->cursor; - }} break; - } -} -NK_INTERN void -nk_textedit_flush_redo(struct nk_text_undo_state *state) -{ - state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; - state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; -} -NK_INTERN void -nk_textedit_discard_undo(struct nk_text_undo_state *state) -{ - /* discard the oldest entry in the undo list */ - if (state->undo_point > 0) { - /* if the 0th undo state has characters, clean those up */ - if (state->undo_rec[0].char_storage >= 0) { - int n = state->undo_rec[0].insert_length, i; - /* delete n characters from all other records */ - state->undo_char_point = (short)(state->undo_char_point - n); - NK_MEMCPY(state->undo_char, state->undo_char + n, - (nk_size)state->undo_char_point*sizeof(nk_rune)); - for (i=0; i < state->undo_point; ++i) { - if (state->undo_rec[i].char_storage >= 0) - state->undo_rec[i].char_storage = (short) - (state->undo_rec[i].char_storage - n); - } - } - --state->undo_point; - NK_MEMCPY(state->undo_rec, state->undo_rec+1, - (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0]))); - } -} -NK_INTERN void -nk_textedit_discard_redo(struct nk_text_undo_state *state) -{ -/* discard the oldest entry in the redo list--it's bad if this - ever happens, but because undo & redo have to store the actual - characters in different cases, the redo character buffer can - fill up even though the undo buffer didn't */ - nk_size num; - int k = NK_TEXTEDIT_UNDOSTATECOUNT-1; - if (state->redo_point <= k) { - /* if the k'th undo state has characters, clean those up */ - if (state->undo_rec[k].char_storage >= 0) { - int n = state->undo_rec[k].insert_length, i; - /* delete n characters from all other records */ - state->redo_char_point = (short)(state->redo_char_point + n); - num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point); - NK_MEMCPY(state->undo_char + state->redo_char_point, - state->undo_char + state->redo_char_point-n, num * sizeof(char)); - for (i = state->redo_point; i < k; ++i) { - if (state->undo_rec[i].char_storage >= 0) { - state->undo_rec[i].char_storage = (short) - (state->undo_rec[i].char_storage + n); - } - } - } - ++state->redo_point; - num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point); - if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1, - state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0])); - } -} -NK_INTERN struct nk_text_undo_record* -nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars) -{ - /* any time we create a new undo record, we discard redo*/ - nk_textedit_flush_redo(state); - - /* if we have no free records, we have to make room, - * by sliding the existing records down */ - if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - nk_textedit_discard_undo(state); - - /* if the characters to store won't possibly fit in the buffer, - * we can't undo */ - if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) { - state->undo_point = 0; - state->undo_char_point = 0; - return 0; - } - - /* if we don't have enough free characters in the buffer, - * we have to make room */ - while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT) - nk_textedit_discard_undo(state); - return &state->undo_rec[state->undo_point++]; -} -NK_INTERN nk_rune* -nk_textedit_createundo(struct nk_text_undo_state *state, int pos, - int insert_len, int delete_len) -{ - struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len); - if (r == 0) - return 0; - - r->where = pos; - r->insert_length = (short) insert_len; - r->delete_length = (short) delete_len; - - if (insert_len == 0) { - r->char_storage = -1; - return 0; - } else { - r->char_storage = state->undo_char_point; - state->undo_char_point = (short)(state->undo_char_point + insert_len); - return &state->undo_char[r->char_storage]; - } -} -NK_API void -nk_textedit_undo(struct nk_text_edit *state) -{ - struct nk_text_undo_state *s = &state->undo; - struct nk_text_undo_record u, *r; - if (s->undo_point == 0) - return; - - /* we need to do two things: apply the undo record, and create a redo record */ - u = s->undo_rec[s->undo_point-1]; - r = &s->undo_rec[s->redo_point-1]; - r->char_storage = -1; - - r->insert_length = u.delete_length; - r->delete_length = u.insert_length; - r->where = u.where; - - if (u.delete_length) - { - /* if the undo record says to delete characters, then the redo record will - need to re-insert the characters that get deleted, so we need to store - them. - there are three cases: - - there's enough room to store the characters - - characters stored for *redoing* don't leave room for redo - - characters stored for *undoing* don't leave room for redo - if the last is true, we have to bail */ - if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) { - /* the undo records take up too much character space; there's no space - * to store the redo characters */ - r->insert_length = 0; - } else { - int i; - /* there's definitely room to store the characters eventually */ - while (s->undo_char_point + u.delete_length > s->redo_char_point) { - /* there's currently not enough room, so discard a redo record */ - nk_textedit_discard_redo(s); - /* should never happen: */ - if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - return; - } - - r = &s->undo_rec[s->redo_point-1]; - r->char_storage = (short)(s->redo_char_point - u.delete_length); - s->redo_char_point = (short)(s->redo_char_point - u.delete_length); - - /* now save the characters */ - for (i=0; i < u.delete_length; ++i) - s->undo_char[r->char_storage + i] = - nk_str_rune_at(&state->string, u.where + i); - } - /* now we can carry out the deletion */ - nk_str_delete_runes(&state->string, u.where, u.delete_length); - } - - /* check type of recorded action: */ - if (u.insert_length) { - /* easy case: was a deletion, so we need to insert n characters */ - nk_str_insert_text_runes(&state->string, u.where, - &s->undo_char[u.char_storage], u.insert_length); - s->undo_char_point = (short)(s->undo_char_point - u.insert_length); - } - state->cursor = (short)(u.where + u.insert_length); - - s->undo_point--; - s->redo_point--; -} -NK_API void -nk_textedit_redo(struct nk_text_edit *state) -{ - struct nk_text_undo_state *s = &state->undo; - struct nk_text_undo_record *u, r; - if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - return; - - /* we need to do two things: apply the redo record, and create an undo record */ - u = &s->undo_rec[s->undo_point]; - r = s->undo_rec[s->redo_point]; - - /* we KNOW there must be room for the undo record, because the redo record - was derived from an undo record */ - u->delete_length = r.insert_length; - u->insert_length = r.delete_length; - u->where = r.where; - u->char_storage = -1; - - if (r.delete_length) { - /* the redo record requires us to delete characters, so the undo record - needs to store the characters */ - if (s->undo_char_point + u->insert_length > s->redo_char_point) { - u->insert_length = 0; - u->delete_length = 0; - } else { - int i; - u->char_storage = s->undo_char_point; - s->undo_char_point = (short)(s->undo_char_point + u->insert_length); - - /* now save the characters */ - for (i=0; i < u->insert_length; ++i) { - s->undo_char[u->char_storage + i] = - nk_str_rune_at(&state->string, u->where + i); - } - } - nk_str_delete_runes(&state->string, r.where, r.delete_length); - } - - if (r.insert_length) { - /* easy case: need to insert n characters */ - nk_str_insert_text_runes(&state->string, r.where, - &s->undo_char[r.char_storage], r.insert_length); - } - state->cursor = r.where + r.insert_length; - - s->undo_point++; - s->redo_point++; -} -NK_INTERN void -nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length) -{ - nk_textedit_createundo(&state->undo, where, 0, length); -} -NK_INTERN void -nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length) -{ - int i; - nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0); - if (p) { - for (i=0; i < length; ++i) - p[i] = nk_str_rune_at(&state->string, where+i); - } -} -NK_INTERN void -nk_textedit_makeundo_replace(struct nk_text_edit *state, int where, - int old_length, int new_length) -{ - int i; - nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length); - if (p) { - for (i=0; i < old_length; ++i) - p[i] = nk_str_rune_at(&state->string, where+i); - } -} -NK_LIB void -nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, - nk_plugin_filter filter) -{ - /* reset the state to default */ - state->undo.undo_point = 0; - state->undo.undo_char_point = 0; - state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; - state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; - state->select_end = state->select_start = 0; - state->cursor = 0; - state->has_preferred_x = 0; - state->preferred_x = 0; - state->cursor_at_end_of_line = 0; - state->initialized = 1; - state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE); - state->mode = NK_TEXT_EDIT_MODE_VIEW; - state->filter = filter; - state->scrollbar = nk_vec2(0,0); -} -NK_API void -nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size) -{ - NK_ASSERT(state); - NK_ASSERT(memory); - if (!state || !memory || !size) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init_fixed(&state->string, memory, size); -} -NK_API void -nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size size) -{ - NK_ASSERT(state); - NK_ASSERT(alloc); - if (!state || !alloc) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init(&state->string, alloc, size); -} -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_textedit_init_default(struct nk_text_edit *state) -{ - NK_ASSERT(state); - if (!state) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init_default(&state->string); -} -#endif -NK_API void -nk_textedit_select_all(struct nk_text_edit *state) -{ - NK_ASSERT(state); - state->select_start = 0; - state->select_end = state->string.len; -} -NK_API void -nk_textedit_free(struct nk_text_edit *state) -{ - NK_ASSERT(state); - if (!state) return; - nk_str_free(&state->string); -} - - - - - -/* =============================================================== - * - * FILTER - * - * ===============================================================*/ -NK_API nk_bool -nk_filter_default(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(unicode); - NK_UNUSED(box); - return nk_true; -} -NK_API nk_bool -nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode > 128) return nk_false; - else return nk_true; -} -NK_API nk_bool -nk_filter_float(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-') - return nk_false; - else return nk_true; -} -NK_API nk_bool -nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && unicode != '-') - return nk_false; - else return nk_true; -} -NK_API nk_bool -nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && - (unicode < 'a' || unicode > 'f') && - (unicode < 'A' || unicode > 'F')) - return nk_false; - else return nk_true; -} -NK_API nk_bool -nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode < '0' || unicode > '7') - return nk_false; - else return nk_true; -} -NK_API nk_bool -nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode != '0' && unicode != '1') - return nk_false; - else return nk_true; -} - -/* =============================================================== - * - * EDIT - * - * ===============================================================*/ -NK_LIB void -nk_edit_draw_text(struct nk_command_buffer *out, - const struct nk_style_edit *style, float pos_x, float pos_y, - float x_offset, const char *text, int byte_len, float row_height, - const struct nk_user_font *font, struct nk_color background, - struct nk_color foreground, nk_bool is_selected) -{ - NK_ASSERT(out); - NK_ASSERT(font); - NK_ASSERT(style); - if (!text || !byte_len || !out || !style) return; - - {int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - float line_width = 0; - float glyph_width; - const char *line = text; - float line_offset = 0; - int line_count = 0; - - struct nk_text txt; - txt.padding = nk_vec2(0,0); - txt.background = background; - txt.text = foreground; - - glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len); - if (!glyph_len) return; - while ((text_len < byte_len) && glyph_len) - { - if (unicode == '\n') { - /* new line separator so draw previous line */ - struct nk_rect label; - label.y = pos_y + line_offset; - label.h = row_height; - label.w = line_width; - label.x = pos_x; - if (!line_count) - label.x += x_offset; - - if (is_selected) /* selection needs to draw different background color */ - nk_fill_rect(out, label, 0, background); - nk_widget_text(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_CENTERED, font); - - text_len++; - line_count++; - line_width = 0; - line = text + text_len; - line_offset += row_height; - glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len)); - continue; - } - if (unicode == '\r') { - text_len++; - glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); - continue; - } - glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); - line_width += (float)glyph_width; - text_len += glyph_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); - continue; - } - if (line_width > 0) { - /* draw last line */ - struct nk_rect label; - label.y = pos_y + line_offset; - label.h = row_height; - label.w = line_width; - label.x = pos_x; - if (!line_count) - label.x += x_offset; - - if (is_selected) - nk_fill_rect(out, label, 0, background); - nk_widget_text(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_LEFT, font); - }} -} -NK_LIB nk_flags -nk_do_edit(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, - struct nk_text_edit *edit, const struct nk_style_edit *style, - struct nk_input *in, const struct nk_user_font *font) -{ - struct nk_rect area; - nk_flags ret = 0; - float row_height; - char prev_state = 0; - char is_hovered = 0; - char select_all = 0; - char cursor_follow = 0; - struct nk_rect old_clip; - struct nk_rect clip; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(style); - if (!state || !out || !style) - return ret; - - /* visible text area calculation */ - area.x = bounds.x + style->padding.x + style->border; - area.y = bounds.y + style->padding.y + style->border; - area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border); - area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border); - if (flags & NK_EDIT_MULTILINE) - area.w = NK_MAX(0, area.w - style->scrollbar_size.x); - row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h; - - /* calculate clipping rectangle */ - old_clip = out->clip; - nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h); - - /* update edit state */ - prev_state = (char)edit->active; - is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds); - if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) { - edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, - bounds.x, bounds.y, bounds.w, bounds.h); - } - - /* (de)activate text editor */ - if (!prev_state && edit->active) { - const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ? - NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE; - /* keep scroll position when re-activating edit widget */ - struct nk_vec2 oldscrollbar = edit->scrollbar; - nk_textedit_clear_state(edit, type, filter); - edit->scrollbar = oldscrollbar; - if (flags & NK_EDIT_AUTO_SELECT) - select_all = nk_true; - if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) { - edit->cursor = edit->string.len; - in = 0; - } - } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW; - if (flags & NK_EDIT_READ_ONLY) - edit->mode = NK_TEXT_EDIT_MODE_VIEW; - else if (flags & NK_EDIT_ALWAYS_INSERT_MODE) - edit->mode = NK_TEXT_EDIT_MODE_INSERT; - - ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE; - if (prev_state != edit->active) - ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED; - - /* handle user input */ - if (edit->active && in) - { - int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down; - const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x; - const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y; - - /* mouse click handler */ - is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area); - if (select_all) { - nk_textedit_select_all(edit); - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && - in->mouse.buttons[NK_BUTTON_LEFT].clicked) { - nk_textedit_click(edit, mouse_x, mouse_y, font, row_height); - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && - (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) { - nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height); - cursor_follow = nk_true; - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked && - in->mouse.buttons[NK_BUTTON_RIGHT].down) { - nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height); - nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height); - cursor_follow = nk_true; - } - - {int i; /* keyboard input */ - int old_mode = edit->mode; - for (i = 0; i < NK_KEY_MAX; ++i) { - if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */ - if (nk_input_is_key_pressed(in, (enum nk_keys)i)) { - nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height); - cursor_follow = nk_true; - } - } - if (old_mode != edit->mode) { - in->keyboard.text_len = 0; - }} - - /* text input */ - edit->filter = filter; - if (in->keyboard.text_len) { - nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len); - cursor_follow = nk_true; - in->keyboard.text_len = 0; - } - - /* enter key handler */ - if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) { - cursor_follow = nk_true; - if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod) - nk_textedit_text(edit, "\n", 1); - else if (flags & NK_EDIT_SIG_ENTER) - ret |= NK_EDIT_COMMITED; - else nk_textedit_text(edit, "\n", 1); - } - - /* cut & copy handler */ - {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY); - int cut = nk_input_is_key_pressed(in, NK_KEY_CUT); - if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD)) - { - int glyph_len; - nk_rune unicode; - const char *text; - int b = edit->select_start; - int e = edit->select_end; - - int begin = NK_MIN(b, e); - int end = NK_MAX(b, e); - text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); - if (edit->clip.copy) - edit->clip.copy(edit->clip.userdata, text, end - begin); - if (cut && !(flags & NK_EDIT_READ_ONLY)){ - nk_textedit_cut(edit); - cursor_follow = nk_true; - } - }} - - /* paste handler */ - {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE); - if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) { - edit->clip.paste(edit->clip.userdata, edit); - cursor_follow = nk_true; - }} - - /* tab handler */ - {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB); - if (tab && (flags & NK_EDIT_ALLOW_TAB)) { - nk_textedit_text(edit, " ", 4); - cursor_follow = nk_true; - }} - } - - /* set widget state */ - if (edit->active) - *state = NK_WIDGET_STATE_ACTIVE; - else nk_widget_state_reset(state); - - if (is_hovered) - *state |= NK_WIDGET_STATE_HOVERED; - - /* DRAW EDIT */ - {const char *text = nk_str_get_const(&edit->string); - int len = nk_str_len_char(&edit->string); - - {/* select background colors/images */ - const struct nk_style_item *background; - if (*state & NK_WIDGET_STATE_ACTIVED) - background = &style->active; - else if (*state & NK_WIDGET_STATE_HOVER) - background = &style->hover; - else background = &style->normal; - - /* draw background frame */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, bounds, style->rounding, background->data.color); - nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, bounds, &background->data.image, nk_white);} - - area.w = NK_MAX(0, area.w - style->cursor_size); - if (edit->active) - { - int total_lines = 1; - struct nk_vec2 text_size = nk_vec2(0,0); - - /* text pointer positions */ - const char *cursor_ptr = 0; - const char *select_begin_ptr = 0; - const char *select_end_ptr = 0; - - /* 2D pixel positions */ - struct nk_vec2 cursor_pos = nk_vec2(0,0); - struct nk_vec2 selection_offset_start = nk_vec2(0,0); - struct nk_vec2 selection_offset_end = nk_vec2(0,0); - - int selection_begin = NK_MIN(edit->select_start, edit->select_end); - int selection_end = NK_MAX(edit->select_start, edit->select_end); - - /* calculate total line count + total space + cursor/selection position */ - float line_width = 0.0f; - if (text && len) - { - /* utf8 encoding */ - float glyph_width; - int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - int glyphs = 0; - int row_begin = 0; - - glyph_len = nk_utf_decode(text, &unicode, len); - glyph_width = font->width(font->userdata, font->height, text, glyph_len); - line_width = 0; - - /* iterate all lines */ - while ((text_len < len) && glyph_len) - { - /* set cursor 2D position and line */ - if (!cursor_ptr && glyphs == edit->cursor) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - cursor_pos.y = (float)(total_lines-1) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - cursor_pos.x = row_size.x; - cursor_ptr = text + text_len; - } - - /* set start selection 2D position and line */ - if (!select_begin_ptr && edit->select_start != edit->select_end && - glyphs == selection_begin) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - selection_offset_start.x = row_size.x; - select_begin_ptr = text + text_len; - } - - /* set end selection 2D position and line */ - if (!select_end_ptr && edit->select_start != edit->select_end && - glyphs == selection_end) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - selection_offset_end.y = (float)(total_lines-1) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - selection_offset_end.x = row_size.x; - select_end_ptr = text + text_len; - } - if (unicode == '\n') { - text_size.x = NK_MAX(text_size.x, line_width); - total_lines++; - line_width = 0; - text_len++; - glyphs++; - row_begin = text_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); - glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); - continue; - } - - glyphs++; - text_len += glyph_len; - line_width += (float)glyph_width; - - glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); - glyph_width = font->width(font->userdata, font->height, - text+text_len, glyph_len); - continue; - } - text_size.y = (float)total_lines * row_height; - - /* handle case when cursor is at end of text buffer */ - if (!cursor_ptr && edit->cursor == edit->string.len) { - cursor_pos.x = line_width; - cursor_pos.y = text_size.y - row_height; - } - } - { - /* scrollbar */ - if (cursor_follow) - { - /* update scrollbar to follow cursor */ - if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) { - /* horizontal scroll */ - const float scroll_increment = area.w * 0.25f; - if (cursor_pos.x < edit->scrollbar.x) - edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment); - if (cursor_pos.x >= edit->scrollbar.x + area.w) - edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - area.w + scroll_increment); - } else edit->scrollbar.x = 0; - - if (flags & NK_EDIT_MULTILINE) { - /* vertical scroll */ - if (cursor_pos.y < edit->scrollbar.y) - edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height); - if (cursor_pos.y >= edit->scrollbar.y + area.h) - edit->scrollbar.y = edit->scrollbar.y + row_height; - } else edit->scrollbar.y = 0; - } - - /* scrollbar widget */ - if (flags & NK_EDIT_MULTILINE) - { - nk_flags ws; - struct nk_rect scroll; - float scroll_target; - float scroll_offset; - float scroll_step; - float scroll_inc; - - scroll = area; - scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x; - scroll.w = style->scrollbar_size.x; - - scroll_offset = edit->scrollbar.y; - scroll_step = scroll.h * 0.10f; - scroll_inc = scroll.h * 0.01f; - scroll_target = text_size.y; - edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, 0, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &style->scrollbar, in, font); - } - } - - /* draw text */ - {struct nk_color background_color; - struct nk_color text_color; - struct nk_color sel_background_color; - struct nk_color sel_text_color; - struct nk_color cursor_color; - struct nk_color cursor_text_color; - const struct nk_style_item *background; - nk_push_scissor(out, clip); - - /* select correct colors to draw */ - if (*state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text_color = style->text_active; - sel_text_color = style->selected_text_hover; - sel_background_color = style->selected_hover; - cursor_color = style->cursor_hover; - cursor_text_color = style->cursor_text_hover; - } else if (*state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text_color = style->text_hover; - sel_text_color = style->selected_text_hover; - sel_background_color = style->selected_hover; - cursor_text_color = style->cursor_text_hover; - cursor_color = style->cursor_hover; - } else { - background = &style->normal; - text_color = style->text_normal; - sel_text_color = style->selected_text_normal; - sel_background_color = style->selected_normal; - cursor_color = style->cursor_normal; - cursor_text_color = style->cursor_text_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) - background_color = nk_rgba(0,0,0,0); - else background_color = background->data.color; - - - if (edit->select_start == edit->select_end) { - /* no selection so just draw the complete text */ - const char *begin = nk_str_get_const(&edit->string); - int l = nk_str_len_char(&edit->string); - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, - background_color, text_color, nk_false); - } else { - /* edit has selection so draw 1-3 text chunks */ - if (edit->select_start != edit->select_end && selection_begin > 0){ - /* draw unselected text before selection */ - const char *begin = nk_str_get_const(&edit->string); - NK_ASSERT(select_begin_ptr); - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin), - row_height, font, background_color, text_color, nk_false); - } - if (edit->select_start != edit->select_end) { - /* draw selected text */ - NK_ASSERT(select_begin_ptr); - if (!select_end_ptr) { - const char *begin = nk_str_get_const(&edit->string); - select_end_ptr = begin + nk_str_len_char(&edit->string); - } - nk_edit_draw_text(out, style, - area.x - edit->scrollbar.x, - area.y + selection_offset_start.y - edit->scrollbar.y, - selection_offset_start.x, - select_begin_ptr, (int)(select_end_ptr - select_begin_ptr), - row_height, font, sel_background_color, sel_text_color, nk_true); - } - if ((edit->select_start != edit->select_end && - selection_end < edit->string.len)) - { - /* draw unselected text after selected text */ - const char *begin = select_end_ptr; - const char *end = nk_str_get_const(&edit->string) + - nk_str_len_char(&edit->string); - NK_ASSERT(select_end_ptr); - nk_edit_draw_text(out, style, - area.x - edit->scrollbar.x, - area.y + selection_offset_end.y - edit->scrollbar.y, - selection_offset_end.x, - begin, (int)(end - begin), row_height, font, - background_color, text_color, nk_true); - } - } - - /* cursor */ - if (edit->select_start == edit->select_end) - { - if (edit->cursor >= nk_str_len(&edit->string) || - (cursor_ptr && *cursor_ptr == '\n')) { - /* draw cursor at end of line */ - struct nk_rect cursor; - cursor.w = style->cursor_size; - cursor.h = font->height; - cursor.x = area.x + cursor_pos.x - edit->scrollbar.x; - cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f; - cursor.y -= edit->scrollbar.y; - nk_fill_rect(out, cursor, 0, cursor_color); - } else { - /* draw cursor inside text */ - int glyph_len; - struct nk_rect label; - struct nk_text txt; - - nk_rune unicode; - NK_ASSERT(cursor_ptr); - glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4); - - label.x = area.x + cursor_pos.x - edit->scrollbar.x; - label.y = area.y + cursor_pos.y - edit->scrollbar.y; - label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len); - label.h = row_height; - - txt.padding = nk_vec2(0,0); - txt.background = cursor_color;; - txt.text = cursor_text_color; - nk_fill_rect(out, label, 0, cursor_color); - nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font); - } - }} - } else { - /* not active so just draw text */ - int l = nk_str_len_char(&edit->string); - const char *begin = nk_str_get_const(&edit->string); - - const struct nk_style_item *background; - struct nk_color background_color; - struct nk_color text_color; - nk_push_scissor(out, clip); - if (*state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text_color = style->text_active; - } else if (*state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text_color = style->text_hover; - } else { - background = &style->normal; - text_color = style->text_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) - background_color = nk_rgba(0,0,0,0); - else background_color = background->data.color; - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, - background_color, text_color, nk_false); - } - nk_push_scissor(out, old_clip);} - return ret; -} -NK_API void -nk_edit_focus(struct nk_context *ctx, nk_flags flags) -{ - nk_hash hash; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - win = ctx->current; - hash = win->edit.seq; - win->edit.active = nk_true; - win->edit.name = hash; - if (flags & NK_EDIT_ALWAYS_INSERT_MODE) - win->edit.mode = NK_TEXT_EDIT_MODE_INSERT; -} -NK_API void -nk_edit_unfocus(struct nk_context *ctx) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - win = ctx->current; - win->edit.active = nk_false; - win->edit.name = 0; -} -NK_API nk_flags -nk_edit_string(struct nk_context *ctx, nk_flags flags, - char *memory, int *len, int max, nk_plugin_filter filter) -{ - nk_hash hash; - nk_flags state; - struct nk_text_edit *edit; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(memory); - NK_ASSERT(len); - if (!ctx || !memory || !len) - return 0; - - filter = (!filter) ? nk_filter_default: filter; - win = ctx->current; - hash = win->edit.seq; - edit = &ctx->text_edit; - nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)? - NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter); - - if (win->edit.active && hash == win->edit.name) { - if (flags & NK_EDIT_NO_CURSOR) - edit->cursor = nk_utf_len(memory, *len); - else edit->cursor = win->edit.cursor; - if (!(flags & NK_EDIT_SELECTABLE)) { - edit->select_start = win->edit.cursor; - edit->select_end = win->edit.cursor; - } else { - edit->select_start = win->edit.sel_start; - edit->select_end = win->edit.sel_end; - } - edit->mode = win->edit.mode; - edit->scrollbar.x = (float)win->edit.scrollbar.x; - edit->scrollbar.y = (float)win->edit.scrollbar.y; - edit->active = nk_true; - } else edit->active = nk_false; - - max = NK_MAX(1, max); - *len = NK_MIN(*len, max-1); - nk_str_init_fixed(&edit->string, memory, (nk_size)max); - edit->string.buffer.allocated = (nk_size)*len; - edit->string.len = nk_utf_len(memory, *len); - state = nk_edit_buffer(ctx, flags, edit, filter); - *len = (int)edit->string.buffer.allocated; - - if (edit->active) { - win->edit.cursor = edit->cursor; - win->edit.sel_start = edit->select_start; - win->edit.sel_end = edit->select_end; - win->edit.mode = edit->mode; - win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x; - win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y; - } return state; -} -NK_API nk_flags -nk_edit_buffer(struct nk_context *ctx, nk_flags flags, - struct nk_text_edit *edit, nk_plugin_filter filter) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - nk_flags ret_flags = 0; - unsigned char prev_state; - nk_hash hash; - - /* make sure correct values */ - NK_ASSERT(ctx); - NK_ASSERT(edit); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget(&bounds, ctx); - if (!state) return state; - in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - /* check if edit is currently hot item */ - hash = win->edit.seq++; - if (win->edit.active && hash == win->edit.name) { - if (flags & NK_EDIT_NO_CURSOR) - edit->cursor = edit->string.len; - if (!(flags & NK_EDIT_SELECTABLE)) { - edit->select_start = edit->cursor; - edit->select_end = edit->cursor; - } - if (flags & NK_EDIT_CLIPBOARD) - edit->clip = ctx->clip; - edit->active = (unsigned char)win->edit.active; - } else edit->active = nk_false; - edit->mode = win->edit.mode; - - filter = (!filter) ? nk_filter_default: filter; - prev_state = (unsigned char)edit->active; - in = (flags & NK_EDIT_READ_ONLY) ? 0: in; - ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags, - filter, edit, &style->edit, in, style->font); - - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT]; - if (edit->active && prev_state != edit->active) { - /* current edit is now hot */ - win->edit.active = nk_true; - win->edit.name = hash; - } else if (prev_state && !edit->active) { - /* current edit is now cold */ - win->edit.active = nk_false; - } return ret_flags; -} -NK_API nk_flags -nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags, - char *buffer, int max, nk_plugin_filter filter) -{ - nk_flags result; - int len = nk_strlen(buffer); - result = nk_edit_string(ctx, flags, buffer, &len, max, filter); - buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0'; - return result; -} - - - - - -/* =============================================================== - * - * PROPERTY - * - * ===============================================================*/ -NK_LIB void -nk_drag_behavior(nk_flags *state, const struct nk_input *in, - struct nk_rect drag, struct nk_property_variant *variant, - float inc_per_pixel) -{ - int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_cursor = in && - nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true); - - nk_widget_state_reset(state); - if (nk_input_is_mouse_hovering_rect(in, drag)) - *state = NK_WIDGET_STATE_HOVERED; - - if (left_mouse_down && left_mouse_click_in_cursor) { - float delta, pixels; - pixels = in->mouse.delta.x; - delta = pixels * inc_per_pixel; - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = variant->value.i + (int)delta; - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); - break; - case NK_PROPERTY_FLOAT: - variant->value.f = variant->value.f + (float)delta; - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); - break; - case NK_PROPERTY_DOUBLE: - variant->value.d = variant->value.d + (double)delta; - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); - break; - } - *state = NK_WIDGET_STATE_ACTIVE; - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, drag)) - *state |= NK_WIDGET_STATE_LEFT; -} -NK_LIB void -nk_property_behavior(nk_flags *ws, const struct nk_input *in, - struct nk_rect property, struct nk_rect label, struct nk_rect edit, - struct nk_rect empty, int *state, struct nk_property_variant *variant, - float inc_per_pixel) -{ - if (in && *state == NK_PROPERTY_DEFAULT) { - if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT)) - *state = NK_PROPERTY_EDIT; - else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true)) - *state = NK_PROPERTY_DRAG; - else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true)) - *state = NK_PROPERTY_DRAG; - } - if (*state == NK_PROPERTY_DRAG) { - nk_drag_behavior(ws, in, property, variant, inc_per_pixel); - if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT; - } -} -NK_LIB void -nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, - const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, - const char *name, int len, const struct nk_user_font *font) -{ - struct nk_text text; - const struct nk_style_item *background; - - /* select correct background and text color */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text.text = style->label_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text.text = style->label_hover; - } else { - background = &style->normal; - text.text = style->label_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - text.background = background->data.color; - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color); - } - - /* draw label */ - text.padding = nk_vec2(0,0); - nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font); -} -NK_LIB void -nk_do_property(nk_flags *ws, - struct nk_command_buffer *out, struct nk_rect property, - const char *name, struct nk_property_variant *variant, - float inc_per_pixel, char *buffer, int *len, - int *state, int *cursor, int *select_begin, int *select_end, - const struct nk_style_property *style, - enum nk_property_filter filter, struct nk_input *in, - const struct nk_user_font *font, struct nk_text_edit *text_edit, - enum nk_button_behavior behavior) -{ - const nk_plugin_filter filters[] = { - nk_filter_decimal, - nk_filter_float - }; - nk_bool active, old; - int num_len, name_len; - char string[NK_MAX_NUMBER_BUFFER]; - float size; - - char *dst = 0; - int *length; - - struct nk_rect left; - struct nk_rect right; - struct nk_rect label; - struct nk_rect edit; - struct nk_rect empty; - - /* left decrement button */ - left.h = font->height/2; - left.w = left.h; - left.x = property.x + style->border + style->padding.x; - left.y = property.y + style->border + property.h/2.0f - left.h/2; - - /* text label */ - name_len = nk_strlen(name); - size = font->width(font->userdata, font->height, name, name_len); - label.x = left.x + left.w + style->padding.x; - label.w = (float)size + 2 * style->padding.x; - label.y = property.y + style->border + style->padding.y; - label.h = property.h - (2 * style->border + 2 * style->padding.y); - - /* right increment button */ - right.y = left.y; - right.w = left.w; - right.h = left.h; - right.x = property.x + property.w - (right.w + style->padding.x); - - /* edit */ - if (*state == NK_PROPERTY_EDIT) { - size = font->width(font->userdata, font->height, buffer, *len); - size += style->edit.cursor_size; - length = len; - dst = buffer; - } else { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - nk_itoa(string, variant->value.i); - num_len = nk_strlen(string); - break; - case NK_PROPERTY_FLOAT: - NK_DTOA(string, (double)variant->value.f); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); - break; - case NK_PROPERTY_DOUBLE: - NK_DTOA(string, variant->value.d); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); - break; - } - size = font->width(font->userdata, font->height, string, num_len); - dst = string; - length = &num_len; - } - - edit.w = (float)size + 2 * style->padding.x; - edit.w = NK_MIN(edit.w, right.x - (label.x + label.w)); - edit.x = right.x - (edit.w + style->padding.x); - edit.y = property.y + style->border; - edit.h = property.h - (2 * style->border); - - /* empty left space activator */ - empty.w = edit.x - (label.x + label.w); - empty.x = label.x + label.w; - empty.y = property.y; - empty.h = property.h; - - /* update property */ - old = (*state == NK_PROPERTY_EDIT); - nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel); - - /* draw property */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_property(out, style, &property, &label, *ws, name, name_len, font); - if (style->draw_end) style->draw_end(out, style->userdata); - - /* execute right button */ - if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break; - case NK_PROPERTY_FLOAT: - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break; - case NK_PROPERTY_DOUBLE: - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break; - } - } - /* execute left button */ - if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break; - case NK_PROPERTY_FLOAT: - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break; - case NK_PROPERTY_DOUBLE: - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break; - } - } - if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) { - /* property has been activated so setup buffer */ - NK_MEMCPY(buffer, dst, (nk_size)*length); - *cursor = nk_utf_len(buffer, *length); - *len = *length; - length = len; - dst = buffer; - active = 0; - } else active = (*state == NK_PROPERTY_EDIT); - - /* execute and run text edit field */ - nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]); - text_edit->active = (unsigned char)active; - text_edit->string.len = *length; - text_edit->cursor = NK_CLAMP(0, *cursor, *length); - text_edit->select_start = NK_CLAMP(0,*select_begin, *length); - text_edit->select_end = NK_CLAMP(0,*select_end, *length); - text_edit->string.buffer.allocated = (nk_size)*length; - text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER; - text_edit->string.buffer.memory.ptr = dst; - text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER; - text_edit->mode = NK_TEXT_EDIT_MODE_INSERT; - nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT, - filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font); - - *length = text_edit->string.len; - *cursor = text_edit->cursor; - *select_begin = text_edit->select_start; - *select_end = text_edit->select_end; - if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER)) - text_edit->active = nk_false; - - if (active && !text_edit->active) { - /* property is now not active so convert edit text to value*/ - *state = NK_PROPERTY_DEFAULT; - buffer[*len] = '\0'; - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = nk_strtoi(buffer, 0); - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); - break; - case NK_PROPERTY_FLOAT: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.f = nk_strtof(buffer, 0); - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); - break; - case NK_PROPERTY_DOUBLE: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.d = nk_strtod(buffer, 0); - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); - break; - } - } -} -NK_LIB struct nk_property_variant -nk_property_variant_int(int value, int min_value, int max_value, int step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_INT; - result.value.i = value; - result.min_value.i = min_value; - result.max_value.i = max_value; - result.step.i = step; - return result; -} -NK_LIB struct nk_property_variant -nk_property_variant_float(float value, float min_value, float max_value, float step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_FLOAT; - result.value.f = value; - result.min_value.f = min_value; - result.max_value.f = max_value; - result.step.f = step; - return result; -} -NK_LIB struct nk_property_variant -nk_property_variant_double(double value, double min_value, double max_value, - double step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_DOUBLE; - result.value.d = value; - result.min_value.d = min_value; - result.max_value.d = max_value; - result.step.d = step; - return result; -} -NK_LIB void -nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, - float inc_per_pixel, const enum nk_property_filter filter) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states s; - - int *state = 0; - nk_hash hash = 0; - char *buffer = 0; - int *len = 0; - int *cursor = 0; - int *select_begin = 0; - int *select_end = 0; - int old_state; - - char dummy_buffer[NK_MAX_NUMBER_BUFFER]; - int dummy_state = NK_PROPERTY_DEFAULT; - int dummy_length = 0; - int dummy_cursor = 0; - int dummy_select_begin = 0; - int dummy_select_end = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - s = nk_widget(&bounds, ctx); - if (!s) return; - - /* calculate hash from name */ - if (name[0] == '#') { - hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++); - name++; /* special number hash */ - } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42); - - /* check if property is currently hot item */ - if (win->property.active && hash == win->property.name) { - buffer = win->property.buffer; - len = &win->property.length; - cursor = &win->property.cursor; - state = &win->property.state; - select_begin = &win->property.select_start; - select_end = &win->property.select_end; - } else { - buffer = dummy_buffer; - len = &dummy_length; - cursor = &dummy_cursor; - state = &dummy_state; - select_begin = &dummy_select_begin; - select_end = &dummy_select_end; - } - - /* execute property widget */ - old_state = *state; - ctx->text_edit.clip = ctx->clip; - in = ((s == NK_WIDGET_ROM && !win->property.active) || - layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name, - variant, inc_per_pixel, buffer, len, state, cursor, select_begin, - select_end, &style->property, filter, in, style->font, &ctx->text_edit, - ctx->button_behavior); - - if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) { - /* current property is now hot */ - win->property.active = 1; - NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len); - win->property.length = *len; - win->property.cursor = *cursor; - win->property.state = *state; - win->property.name = hash; - win->property.select_start = *select_begin; - win->property.select_end = *select_end; - if (*state == NK_PROPERTY_DRAG) { - ctx->input.mouse.grab = nk_true; - ctx->input.mouse.grabbed = nk_true; - } - } - /* check if previously active property is now inactive */ - if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) { - if (old_state == NK_PROPERTY_DRAG) { - ctx->input.mouse.grab = nk_false; - ctx->input.mouse.grabbed = nk_false; - ctx->input.mouse.ungrab = nk_true; - } - win->property.select_start = 0; - win->property.select_end = 0; - win->property.active = 0; - } -} -NK_API void -nk_property_int(struct nk_context *ctx, const char *name, - int min, int *val, int max, int step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_int(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); - *val = variant.value.i; -} -NK_API void -nk_property_float(struct nk_context *ctx, const char *name, - float min, float *val, float max, float step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_float(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - *val = variant.value.f; -} -NK_API void -nk_property_double(struct nk_context *ctx, const char *name, - double min, double *val, double max, double step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_double(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - *val = variant.value.d; -} -NK_API nk_bool -nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, - int max, int step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_int(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); - val = variant.value.i; - return val; -} -NK_API float -nk_propertyf(struct nk_context *ctx, const char *name, float min, - float val, float max, float step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_float(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - val = variant.value.f; - return val; -} -NK_API double -nk_propertyd(struct nk_context *ctx, const char *name, double min, - double val, double max, double step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_double(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - val = variant.value.d; - return val; -} - - - - - -/* ============================================================== - * - * CHART - * - * ===============================================================*/ -NK_API nk_bool -nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type, - struct nk_color color, struct nk_color highlight, - int count, float min_value, float max_value) -{ - struct nk_window *win; - struct nk_chart *chart; - const struct nk_style *config; - const struct nk_style_chart *style; - - const struct nk_style_item *background; - struct nk_rect bounds = {0, 0, 0, 0}; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - if (!nk_widget(&bounds, ctx)) { - chart = &ctx->current->layout->chart; - nk_zero(chart, sizeof(*chart)); - return 0; - } - - win = ctx->current; - config = &ctx->style; - chart = &win->layout->chart; - style = &config->chart; - - /* setup basic generic chart */ - nk_zero(chart, sizeof(*chart)); - chart->x = bounds.x + style->padding.x; - chart->y = bounds.y + style->padding.y; - chart->w = bounds.w - 2 * style->padding.x; - chart->h = bounds.h - 2 * style->padding.y; - chart->w = NK_MAX(chart->w, 2 * style->padding.x); - chart->h = NK_MAX(chart->h, 2 * style->padding.y); - - /* add first slot into chart */ - {struct nk_chart_slot *slot = &chart->slots[chart->slot++]; - slot->type = type; - slot->count = count; - slot->color = color; - slot->highlight = highlight; - slot->min = NK_MIN(min_value, max_value); - slot->max = NK_MAX(min_value, max_value); - slot->range = slot->max - slot->min;} - - /* draw chart background */ - background = &style->background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color); - nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border), - style->rounding, style->background.data.color); - } - return 1; -} -NK_API nk_bool -nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type, - int count, float min_value, float max_value) -{ - return nk_chart_begin_colored(ctx, type, ctx->style.chart.color, - ctx->style.chart.selected_color, count, min_value, max_value); -} -NK_API void -nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type, - struct nk_color color, struct nk_color highlight, - int count, float min_value, float max_value) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT); - if (!ctx || !ctx->current || !ctx->current->layout) return; - if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return; - - /* add another slot into the graph */ - {struct nk_chart *chart = &ctx->current->layout->chart; - struct nk_chart_slot *slot = &chart->slots[chart->slot++]; - slot->type = type; - slot->count = count; - slot->color = color; - slot->highlight = highlight; - slot->min = NK_MIN(min_value, max_value); - slot->max = NK_MAX(min_value, max_value); - slot->range = slot->max - slot->min;} -} -NK_API void -nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type, - int count, float min_value, float max_value) -{ - nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color, - ctx->style.chart.selected_color, count, min_value, max_value); -} -NK_INTERN nk_flags -nk_chart_push_line(struct nk_context *ctx, struct nk_window *win, - struct nk_chart *g, float value, int slot) -{ - struct nk_panel *layout = win->layout; - const struct nk_input *i = &ctx->input; - struct nk_command_buffer *out = &win->buffer; - - nk_flags ret = 0; - struct nk_vec2 cur; - struct nk_rect bounds; - struct nk_color color; - float step; - float range; - float ratio; - - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - step = g->w / (float)g->slots[slot].count; - range = g->slots[slot].max - g->slots[slot].min; - ratio = (value - g->slots[slot].min) / range; - - if (g->slots[slot].index == 0) { - /* first data point does not have a connection */ - g->slots[slot].last.x = g->x; - g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h; - - bounds.x = g->slots[slot].last.x - 2; - bounds.y = g->slots[slot].last.y - 2; - bounds.w = bounds.h = 4; - - color = g->slots[slot].color; - if (!(layout->flags & NK_WINDOW_ROM) && - NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){ - ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0; - ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down && - i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = g->slots[slot].highlight; - } - nk_fill_rect(out, bounds, 0, color); - g->slots[slot].index += 1; - return ret; - } - - /* draw a line between the last data point and the new one */ - color = g->slots[slot].color; - cur.x = g->x + (float)(step * (float)g->slots[slot].index); - cur.y = (g->y + g->h) - (ratio * (float)g->h); - nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color); - - bounds.x = cur.x - 3; - bounds.y = cur.y - 3; - bounds.w = bounds.h = 6; - - /* user selection of current data point */ - if (!(layout->flags & NK_WINDOW_ROM)) { - if (nk_input_is_mouse_hovering_rect(i, bounds)) { - ret = NK_CHART_HOVERING; - ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down && - i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = g->slots[slot].highlight; - } - } - nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); - - /* save current data point position */ - g->slots[slot].last.x = cur.x; - g->slots[slot].last.y = cur.y; - g->slots[slot].index += 1; - return ret; -} -NK_INTERN nk_flags -nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win, - struct nk_chart *chart, float value, int slot) -{ - struct nk_command_buffer *out = &win->buffer; - const struct nk_input *in = &ctx->input; - struct nk_panel *layout = win->layout; - - float ratio; - nk_flags ret = 0; - struct nk_color color; - struct nk_rect item = {0,0,0,0}; - - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - if (chart->slots[slot].index >= chart->slots[slot].count) - return nk_false; - if (chart->slots[slot].count) { - float padding = (float)(chart->slots[slot].count-1); - item.w = (chart->w - padding) / (float)(chart->slots[slot].count); - } - - /* calculate bounds of current bar chart entry */ - color = chart->slots[slot].color;; - item.h = chart->h * NK_ABS((value/chart->slots[slot].range)); - if (value >= 0) { - ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range); - item.y = (chart->y + chart->h) - chart->h * ratio; - } else { - ratio = (value - chart->slots[slot].max) / chart->slots[slot].range; - item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h; - } - item.x = chart->x + ((float)chart->slots[slot].index * item.w); - item.x = item.x + ((float)chart->slots[slot].index); - - /* user chart bar selection */ - if (!(layout->flags & NK_WINDOW_ROM) && - NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) { - ret = NK_CHART_HOVERING; - ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down && - in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = chart->slots[slot].highlight; - } - nk_fill_rect(out, item, 0, color); - chart->slots[slot].index += 1; - return ret; -} -NK_API nk_flags -nk_chart_push_slot(struct nk_context *ctx, float value, int slot) -{ - nk_flags flags; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - NK_ASSERT(slot < ctx->current->layout->chart.slot); - if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false; - if (slot >= ctx->current->layout->chart.slot) return nk_false; - - win = ctx->current; - if (win->layout->chart.slot < slot) return nk_false; - switch (win->layout->chart.slots[slot].type) { - case NK_CHART_LINES: - flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break; - case NK_CHART_COLUMN: - flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break; - default: - case NK_CHART_MAX: - flags = 0; - } - return flags; -} -NK_API nk_flags -nk_chart_push(struct nk_context *ctx, float value) -{ - return nk_chart_push_slot(ctx, value, 0); -} -NK_API void -nk_chart_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_chart *chart; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - - win = ctx->current; - chart = &win->layout->chart; - NK_MEMSET(chart, 0, sizeof(*chart)); - return; -} -NK_API void -nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values, - int count, int offset) -{ - int i = 0; - float min_value; - float max_value; - - NK_ASSERT(ctx); - NK_ASSERT(values); - if (!ctx || !values || !count) return; - - min_value = values[offset]; - max_value = values[offset]; - for (i = 0; i < count; ++i) { - min_value = NK_MIN(values[i + offset], min_value); - max_value = NK_MAX(values[i + offset], max_value); - } - - if (nk_chart_begin(ctx, type, count, min_value, max_value)) { - for (i = 0; i < count; ++i) - nk_chart_push(ctx, values[i + offset]); - nk_chart_end(ctx); - } -} -NK_API void -nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata, - float(*value_getter)(void* user, int index), int count, int offset) -{ - int i = 0; - float min_value; - float max_value; - - NK_ASSERT(ctx); - NK_ASSERT(value_getter); - if (!ctx || !value_getter || !count) return; - - max_value = min_value = value_getter(userdata, offset); - for (i = 0; i < count; ++i) { - float value = value_getter(userdata, i + offset); - min_value = NK_MIN(value, min_value); - max_value = NK_MAX(value, max_value); - } - - if (nk_chart_begin(ctx, type, count, min_value, max_value)) { - for (i = 0; i < count; ++i) - nk_chart_push(ctx, value_getter(userdata, i + offset)); - nk_chart_end(ctx); - } -} - - - - - -/* ============================================================== - * - * COLOR PICKER - * - * ===============================================================*/ -NK_LIB nk_bool -nk_color_picker_behavior(nk_flags *state, - const struct nk_rect *bounds, const struct nk_rect *matrix, - const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, - struct nk_colorf *color, const struct nk_input *in) -{ - float hsva[4]; - nk_bool value_changed = 0; - nk_bool hsv_changed = 0; - - NK_ASSERT(state); - NK_ASSERT(matrix); - NK_ASSERT(hue_bar); - NK_ASSERT(color); - - /* color matrix */ - nk_colorf_hsva_fv(hsva, *color); - if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) { - hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1)); - hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1)); - value_changed = hsv_changed = 1; - } - /* hue bar */ - if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) { - hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1)); - value_changed = hsv_changed = 1; - } - /* alpha bar */ - if (alpha_bar) { - if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) { - hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1)); - value_changed = 1; - } - } - nk_widget_state_reset(state); - if (hsv_changed) { - *color = nk_hsva_colorfv(hsva); - *state = NK_WIDGET_STATE_ACTIVE; - } - if (value_changed) { - color->a = hsva[3]; - *state = NK_WIDGET_STATE_ACTIVE; - } - /* set color picker widget state */ - if (nk_input_is_mouse_hovering_rect(in, *bounds)) - *state = NK_WIDGET_STATE_HOVERED; - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds)) - *state |= NK_WIDGET_STATE_LEFT; - return value_changed; -} -NK_LIB void -nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, - const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, - struct nk_colorf col) -{ - NK_STORAGE const struct nk_color black = {0,0,0,255}; - NK_STORAGE const struct nk_color white = {255, 255, 255, 255}; - NK_STORAGE const struct nk_color black_trans = {0,0,0,0}; - - const float crosshair_size = 7.0f; - struct nk_color temp; - float hsva[4]; - float line_y; - int i; - - NK_ASSERT(o); - NK_ASSERT(matrix); - NK_ASSERT(hue_bar); - - /* draw hue bar */ - nk_colorf_hsva_fv(hsva, col); - for (i = 0; i < 6; ++i) { - NK_GLOBAL const struct nk_color hue_colors[] = { - {255, 0, 0, 255}, {255,255,0,255}, {0,255,0,255}, {0, 255,255,255}, - {0,0,255,255}, {255, 0, 255, 255}, {255, 0, 0, 255} - }; - nk_fill_rect_multi_color(o, - nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f, - hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i], - hue_colors[i+1], hue_colors[i+1]); - } - line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f); - nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2, - line_y, 1, nk_rgb(255,255,255)); - - /* draw alpha bar */ - if (alpha_bar) { - float alpha = NK_SATURATE(col.a); - line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f); - - nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black); - nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2, - line_y, 1, nk_rgb(255,255,255)); - } - - /* draw color matrix */ - temp = nk_hsv_f(hsva[0], 1.0f, 1.0f); - nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white); - nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black); - - /* draw cross-hair */ - {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2]; - p.x = (float)(int)(matrix->x + S * matrix->w); - p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h); - nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white); - nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white); - nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white); - nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);} -} -NK_LIB nk_bool -nk_do_color_picker(nk_flags *state, - struct nk_command_buffer *out, struct nk_colorf *col, - enum nk_color_format fmt, struct nk_rect bounds, - struct nk_vec2 padding, const struct nk_input *in, - const struct nk_user_font *font) -{ - int ret = 0; - struct nk_rect matrix; - struct nk_rect hue_bar; - struct nk_rect alpha_bar; - float bar_w; - - NK_ASSERT(out); - NK_ASSERT(col); - NK_ASSERT(state); - NK_ASSERT(font); - if (!out || !col || !state || !font) - return ret; - - bar_w = font->height; - bounds.x += padding.x; - bounds.y += padding.x; - bounds.w -= 2 * padding.x; - bounds.h -= 2 * padding.y; - - matrix.x = bounds.x; - matrix.y = bounds.y; - matrix.h = bounds.h; - matrix.w = bounds.w - (3 * padding.x + 2 * bar_w); - - hue_bar.w = bar_w; - hue_bar.y = bounds.y; - hue_bar.h = matrix.h; - hue_bar.x = matrix.x + matrix.w + padding.x; - - alpha_bar.x = hue_bar.x + hue_bar.w + padding.x; - alpha_bar.y = bounds.y; - alpha_bar.w = bar_w; - alpha_bar.h = matrix.h; - - ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar, - (fmt == NK_RGBA) ? &alpha_bar:0, col, in); - nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *col); - return ret; -} -NK_API nk_bool -nk_color_pick(struct nk_context * ctx, struct nk_colorf *color, - enum nk_color_format fmt) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *config; - const struct nk_input *in; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(color); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !color) - return 0; - - win = ctx->current; - config = &ctx->style; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds, - nk_vec2(0,0), in, config->font); -} -NK_API struct nk_colorf -nk_color_picker(struct nk_context *ctx, struct nk_colorf color, - enum nk_color_format fmt) -{ - nk_color_pick(ctx, &color, fmt); - return color; -} - - - - - -/* ============================================================== - * - * COMBO - * - * ===============================================================*/ -NK_INTERN nk_bool -nk_combo_begin(struct nk_context *ctx, struct nk_window *win, - struct nk_vec2 size, nk_bool is_clicked, struct nk_rect header) -{ - struct nk_window *popup; - int is_open = 0; - int is_active = 0; - struct nk_rect body; - nk_hash hash; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - popup = win->popup.win; - body.x = header.x; - body.w = size.x; - body.y = header.y + header.h-ctx->style.window.combo_border; - body.h = size.y; - - hash = win->popup.combo_count++; - is_open = (popup) ? nk_true:nk_false; - is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO); - if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || - (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, 0, body, - (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0; - - win->popup.type = NK_PANEL_COMBO; - win->popup.name = hash; - return 1; -} -NK_API nk_bool -nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len, - struct nk_vec2 size) -{ - const struct nk_input *in; - struct nk_window *win; - struct nk_style *style; - - enum nk_widget_layout_states s; - int is_clicked = nk_false; - struct nk_rect header; - const struct nk_style_item *background; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(selected); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !selected) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - /* print currently selected text item */ - struct nk_rect label; - struct nk_rect button; - struct nk_rect content; - int draw_button_symbol; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else - sym = style->combo.sym_normal; - - /* represents whether or not the combo's button symbol should be drawn */ - draw_button_symbol = sym != NK_SYMBOL_NONE; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw selected label */ - text.padding = nk_vec2(0,0); - label.x = header.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.h = header.h - 2 * style->combo.content_padding.y; - if (draw_button_symbol) - label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x; - else - label.w = header.w - 2 * style->combo.content_padding.x; - nk_widget_text(&win->buffer, label, selected, len, &text, - NK_TEXT_LEFT, ctx->style.font); - - /* draw open/close button */ - if (draw_button_symbol) - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} -NK_API nk_bool -nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size) -{ - return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size); -} -NK_API nk_bool -nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) - background = &style->combo.active; - else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - background = &style->combo.hover; - else background = &style->combo.normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, header, &background->data.image,nk_white); - } else { - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect bounds; - int draw_button_symbol; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* represents whether or not the combo's button symbol should be drawn */ - draw_button_symbol = sym != NK_SYMBOL_NONE; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw color */ - bounds.h = header.h - 4 * style->combo.content_padding.y; - bounds.y = header.y + 2 * style->combo.content_padding.y; - bounds.x = header.x + 2 * style->combo.content_padding.x; - if (draw_button_symbol) - bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x; - else - bounds.w = header.w - 4 * style->combo.content_padding.x; - nk_fill_rect(&win->buffer, bounds, 0, color); - - /* draw open/close button */ - if (draw_button_symbol) - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} -NK_API nk_bool -nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_color sym_background; - struct nk_color symbol_color; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - symbol_color = style->combo.symbol_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - symbol_color = style->combo.symbol_hover; - } else { - background = &style->combo.normal; - symbol_color = style->combo.symbol_hover; - } - - if (background->type == NK_STYLE_ITEM_IMAGE) { - sym_background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - sym_background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect bounds = {0,0,0,0}; - struct nk_rect content; - struct nk_rect button; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw symbol */ - bounds.h = header.h - 2 * style->combo.content_padding.y; - bounds.y = header.y + style->combo.content_padding.y; - bounds.x = header.x + style->combo.content_padding.x; - bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; - nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color, - 1.0f, style->font); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} -NK_API nk_bool -nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len, - enum nk_symbol_type symbol, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_color symbol_color; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (!s) return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - symbol_color = style->combo.symbol_active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - symbol_color = style->combo.symbol_hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - symbol_color = style->combo.symbol_normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect label; - struct nk_rect image; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - - /* draw symbol */ - image.x = header.x + style->combo.content_padding.x; - image.y = header.y + style->combo.content_padding.y; - image.h = header.h - 2 * style->combo.content_padding.y; - image.w = image.h; - nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color, - 1.0f, style->font); - - /* draw label */ - text.padding = nk_vec2(0,0); - label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = (button.x - style->combo.content_padding.x) - label.x; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} -NK_API nk_bool -nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) - background = &style->combo.active; - else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - background = &style->combo.hover; - else background = &style->combo.normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect bounds = {0,0,0,0}; - struct nk_rect content; - struct nk_rect button; - int draw_button_symbol; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* represents whether or not the combo's button symbol should be drawn */ - draw_button_symbol = sym != NK_SYMBOL_NONE; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw image */ - bounds.h = header.h - 2 * style->combo.content_padding.y; - bounds.y = header.y + style->combo.content_padding.y; - bounds.x = header.x + style->combo.content_padding.x; - if (draw_button_symbol) - bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; - else - bounds.w = header.w - 2 * style->combo.content_padding.x; - nk_draw_image(&win->buffer, bounds, &img, nk_white); - - /* draw open/close button */ - if (draw_button_symbol) - nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} -NK_API nk_bool -nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len, - struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (!s) return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect label; - struct nk_rect image; - int draw_button_symbol; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* represents whether or not the combo's button symbol should be drawn */ - draw_button_symbol = sym != NK_SYMBOL_NONE; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - if (draw_button_symbol) - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - - /* draw image */ - image.x = header.x + style->combo.content_padding.x; - image.y = header.y + style->combo.content_padding.y; - image.h = header.h - 2 * style->combo.content_padding.y; - image.w = image.h; - nk_draw_image(&win->buffer, image, &img, nk_white); - - /* draw label */ - text.padding = nk_vec2(0,0); - label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.h = header.h - 2 * style->combo.content_padding.y; - if (draw_button_symbol) - label.w = (button.x - style->combo.content_padding.x) - label.x; - else - label.w = (header.x + header.w - style->combo.content_padding.x) - label.x; - nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} -NK_API nk_bool -nk_combo_begin_symbol_label(struct nk_context *ctx, - const char *selected, enum nk_symbol_type type, struct nk_vec2 size) -{ - return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size); -} -NK_API nk_bool -nk_combo_begin_image_label(struct nk_context *ctx, - const char *selected, struct nk_image img, struct nk_vec2 size) -{ - return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size); -} -NK_API nk_bool -nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align) -{ - return nk_contextual_item_text(ctx, text, len, align); -} -NK_API nk_bool -nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{ - return nk_contextual_item_label(ctx, label, align); -} -NK_API nk_bool -nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text, - int len, nk_flags alignment) -{ - return nk_contextual_item_image_text(ctx, img, text, len, alignment); -} -NK_API nk_bool -nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *text, nk_flags alignment) -{ - return nk_contextual_item_image_label(ctx, img, text, alignment); -} -NK_API nk_bool -nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *text, int len, nk_flags alignment) -{ - return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment); -} -NK_API nk_bool -nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *label, nk_flags alignment) -{ - return nk_contextual_item_symbol_label(ctx, sym, label, alignment); -} -NK_API void nk_combo_end(struct nk_context *ctx) -{ - nk_contextual_end(ctx); -} -NK_API void nk_combo_close(struct nk_context *ctx) -{ - nk_contextual_close(ctx); -} -NK_API int -nk_combo(struct nk_context *ctx, const char **items, int count, - int selected, int item_height, struct nk_vec2 size) -{ - int i = 0; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - - NK_ASSERT(ctx); - NK_ASSERT(items); - NK_ASSERT(ctx->current); - if (!ctx || !items ||!count) - return selected; - - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - if (nk_combo_begin_label(ctx, items[selected], size)) { - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT)) - selected = i; - } - nk_combo_end(ctx); - } - return selected; -} -NK_API int -nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator, - int separator, int selected, int count, int item_height, struct nk_vec2 size) -{ - int i; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - const char *current_item; - const char *iter; - int length = 0; - - NK_ASSERT(ctx); - NK_ASSERT(items_separated_by_separator); - if (!ctx || !items_separated_by_separator) - return selected; - - /* calculate popup window */ - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - - /* find selected item */ - current_item = items_separated_by_separator; - for (i = 0; i < count; ++i) { - iter = current_item; - while (*iter && *iter != separator) iter++; - length = (int)(iter - current_item); - if (i == selected) break; - current_item = iter + 1; - } - - if (nk_combo_begin_text(ctx, current_item, length, size)) { - current_item = items_separated_by_separator; - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - iter = current_item; - while (*iter && *iter != separator) iter++; - length = (int)(iter - current_item); - if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT)) - selected = i; - current_item = current_item + length + 1; - } - nk_combo_end(ctx); - } - return selected; -} -NK_API int -nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros, - int selected, int count, int item_height, struct nk_vec2 size) -{ - return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size); -} -NK_API int -nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**), - void *userdata, int selected, int count, int item_height, struct nk_vec2 size) -{ - int i; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - const char *item; - - NK_ASSERT(ctx); - NK_ASSERT(item_getter); - if (!ctx || !item_getter) - return selected; - - /* calculate popup window */ - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - - item_getter(userdata, selected, &item); - if (nk_combo_begin_label(ctx, item, size)) { - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - item_getter(userdata, i, &item); - if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT)) - selected = i; - } - nk_combo_end(ctx); - } return selected; -} -NK_API void -nk_combobox(struct nk_context *ctx, const char **items, int count, - int *selected, int item_height, struct nk_vec2 size) -{ - *selected = nk_combo(ctx, items, count, *selected, item_height, size); -} -NK_API void -nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros, - int *selected, int count, int item_height, struct nk_vec2 size) -{ - *selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size); -} -NK_API void -nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator, - int separator, int *selected, int count, int item_height, struct nk_vec2 size) -{ - *selected = nk_combo_separator(ctx, items_separated_by_separator, separator, - *selected, count, item_height, size); -} -NK_API void -nk_combobox_callback(struct nk_context *ctx, - void(*item_getter)(void* data, int id, const char **out_text), - void *userdata, int *selected, int count, int item_height, struct nk_vec2 size) -{ - *selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size); -} - - - - - -/* =============================================================== - * - * TOOLTIP - * - * ===============================================================*/ -NK_API nk_bool -nk_tooltip_begin(struct nk_context *ctx, float width) -{ - int x,y,w,h; - struct nk_window *win; - const struct nk_input *in; - struct nk_rect bounds; - int ret; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* make sure that no nonblocking popup is currently active */ - win = ctx->current; - in = &ctx->input; - if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK)) - return 0; - - w = nk_iceilf(width); - h = nk_iceilf(nk_null_rect.h); - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - - bounds.x = (float)x; - bounds.y = (float)y; - bounds.w = (float)w; - bounds.h = (float)h; - - ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, - "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); - if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM; - win->popup.type = NK_PANEL_TOOLTIP; - ctx->current->layout->type = NK_PANEL_TOOLTIP; - return ret; -} - -NK_API void -nk_tooltip_end(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->seq--; - nk_popup_close(ctx); - nk_popup_end(ctx); -} -NK_API void -nk_tooltip(struct nk_context *ctx, const char *text) -{ - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } -} -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void -nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - nk_tooltipfv(ctx, fmt, args); - va_end(args); -} -NK_API void -nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) -{ - char buf[256]; - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_tooltip(ctx, buf); -} -#endif - - - -#endif /* NK_IMPLEMENTATION */ - -/* -/// ## License -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none -/// ------------------------------------------------------------------------------ -/// This software is available under 2 licenses -- choose whichever you prefer. -/// ------------------------------------------------------------------------------ -/// ALTERNATIVE A - MIT License -/// Copyright (c) 2016-2018 Micha Mettke -/// Permission is hereby granted, free of charge, to any person obtaining a copy of -/// this software and associated documentation files (the "Software"), to deal in -/// the Software without restriction, including without limitation the rights to -/// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -/// of the Software, and to permit persons to whom the Software is furnished to do -/// so, subject to the following conditions: -/// The above copyright notice and this permission notice shall be included in all -/// copies or substantial portions of the Software. -/// 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 OR COPYRIGHT HOLDERS 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. -/// ------------------------------------------------------------------------------ -/// ALTERNATIVE B - Public Domain (www.unlicense.org) -/// 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. -/// ------------------------------------------------------------------------------ -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -/// ## Changelog -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none -/// [date][x.yy.zz]-[description] -/// -[date]: date on which the change has been pushed -/// -[x.yy.zz]: Numerical version string representation. Each version number on the right -/// resets back to zero if version on the left is incremented. -/// - [x]: Major version with API and library breaking changes -/// - [yy]: Minor version with non-breaking API and library changes -/// - [zz]: Bug fix version with no direct changes to API -/// -/// - 2020/10/11 (4.06.1) - Fix C++ style comments which are not allowed in ISO C90. -/// - 2020/10/07 (4.06.0) - Fix nk_combo return type wrongly changed to nk_bool -/// - 2020/09/05 (4.05.0) - Use the nk_font_atlas allocator for stb_truetype memory management. -/// - 2020/09/04 (4.04.1) - Replace every boolean int by nk_bool -/// - 2020/09/04 (4.04.0) - Add nk_bool with NK_INCLUDE_STANDARD_BOOL -/// - 2020/06/13 (4.03.1) - Fix nk_pool allocation sizes. -/// - 2020/06/04 (4.03.0) - Made nk_combo header symbols optional. -/// - 2020/05/27 (4.02.5) - Fix nk_do_edit: Keep scroll position when re-activating edit widget. -/// - 2020/05/09 (4.02.4) - Fix nk_menubar height calculation bug -/// - 2020/05/08 (4.02.3) - Fix missing stdarg.h with NK_INCLUDE_STANDARD_VARARGS -/// - 2020/04/30 (4.02.2) - Fix nk_edit border drawing bug -/// - 2020/04/09 (4.02.1) - Removed unused nk_sqrt function to fix compiler warnings -/// - Fixed compiler warnings if you bring your own methods for -/// nk_cos/nk_sin/nk_strtod/nk_memset/nk_memcopy/nk_dtoa -/// - 2020/04/06 (4.01.10) - Fix bug: Do not use pool before checking for NULL -/// - 2020/03/22 (4.01.9) - Fix bug where layout state wasn't restored correctly after -/// popping a tree. -/// - 2020/03/11 (4.01.8) - Fix bug where padding is subtracted from widget -/// - 2020/03/06 (4.01.7) - Fix bug where width padding was applied twice -/// - 2020/02/06 (4.01.6) - Update stb_truetype.h and stb_rect_pack.h and separate them -/// - 2019/12/10 (4.01.5) - Fix off-by-one error in NK_INTERSECT -/// - 2019/10/09 (4.01.4) - Fix bug for autoscrolling in nk_do_edit -/// - 2019/09/20 (4.01.3) - Fixed a bug wherein combobox cannot be closed by clicking the header -/// when NK_BUTTON_TRIGGER_ON_RELEASE is defined. -/// - 2019/09/10 (4.01.2) - Fixed the nk_cos function, which deviated significantly. -/// - 2019/09/08 (4.01.1) - Fixed a bug wherein re-baking of fonts caused a segmentation -/// fault due to dst_font->glyph_count not being zeroed on subsequent -/// bakes of the same set of fonts. -/// - 2019/06/23 (4.01.0) - Added nk_***_get_scroll and nk_***_set_scroll for groups, windows, and popups. -/// - 2019/06/12 (4.00.3) - Fix panel background drawing bug. -/// - 2018/10/31 (4.00.2) - Added NK_KEYSTATE_BASED_INPUT to "fix" state based backends -/// like GLFW without breaking key repeat behavior on event based. -/// - 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame. -/// - 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to -/// clear provided buffers. So make sure to either free -/// or clear each passed buffer after calling nk_convert. -/// - 2018/02/23 (3.00.6) - Fixed slider dragging behavior. -/// - 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process. -/// - 2018/01/31 (3.00.4) - Removed name collision with stb_truetype. -/// - 2018/01/28 (3.00.3) - Fixed panel window border drawing bug. -/// - 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separed group identifier and title. -/// - 2018/01/07 (3.00.1) - Started to change documentation style. -/// - 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken -/// because of conversions between float and byte color representation. -/// Color pickers now use floating point values to represent -/// HSV values. To get back the old behavior I added some additional -/// color conversion functions to cast between nk_color and -/// nk_colorf. -/// - 2017/12/23 (2.00.7) - Fixed small warning. -/// - 2017/12/23 (2.00.7) - Fixed `nk_edit_buffer` behavior if activated to allow input. -/// - 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior. -/// - 2017/12/04 (2.00.6) - Added formated string tooltip widget. -/// - 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag `NK_WINDOW_NO_INPUT`. -/// - 2017/11/15 (2.00.4) - Fixed font merging. -/// - 2017/11/07 (2.00.3) - Fixed window size and position modifier functions. -/// - 2017/09/14 (2.00.2) - Fixed `nk_edit_buffer` and `nk_edit_focus` behavior. -/// - 2017/09/14 (2.00.1) - Fixed window closing behavior. -/// - 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifing window position and size funtions now -/// require the name of the window and must happen outside the window -/// building process (between function call nk_begin and nk_end). -/// - 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last. -/// - 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows. -/// - 2017/08/27 (1.40.7) - Fixed window background flag. -/// - 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked -/// query for widgets. -/// - 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked -/// and filled rectangles. -/// - 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in -/// process of being destroyed. -/// - 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in -/// window instead of directly in table. -/// - 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro. -/// - 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero. -/// - 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only -/// comes in effect if you pass in zero was row height argument. -/// - 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change -/// how layouting works. From now there will be an internal minimum -/// row height derived from font height. If you need a row smaller than -/// that you can directly set it by `nk_layout_set_min_row_height` and -/// reset the value back by calling `nk_layout_reset_min_row_height. -/// - 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix. -/// - 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a `nk_layout_xxx` function. -/// - 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer. -/// - 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped. -/// - 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundries. -/// - 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space. -/// - 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size. -/// - 2017/05/06 (1.38.0) - Added platform double-click support. -/// - 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends. -/// - 2017/04/20 (1.37.0) - Extended properties with selection and clipboard support. -/// - 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing. -/// - 2017/04/09 (1.36.1) - Fixed #403 with another widget float error. -/// - 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags. -/// - 2017/04/09 (1.35.3) - Fixed buffer heap corruption. -/// - 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows. -/// - 2017/03/25 (1.35.1) - Fixed windows closing behavior. -/// - 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377. -/// - 2017/03/18 (1.34.3) - Fixed long window header titles. -/// - 2017/03/04 (1.34.2) - Fixed text edit filtering. -/// - 2017/03/04 (1.34.1) - Fixed group closable flag. -/// - 2017/02/25 (1.34.0) - Added custom draw command for better language binding support. -/// - 2017/01/24 (1.33.0) - Added programatic way of remove edit focus. -/// - 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows. -/// - 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows. -/// - 2017/01/21 (1.32.1) - Fixed slider behavior and drawing. -/// - 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner. -/// - 2017/01/13 (1.31.0) - Added additional row layouting method to combine both -/// dynamic and static widgets. -/// - 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit. -/// - 2016/12/31 (1.29.2) - Fixed closing window bug of minimized windows. -/// - 2016/12/03 (1.29.1) - Fixed wrapped text with no seperator and C89 error. -/// - 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters. -/// - 2016/11/22 (1.28.6) - Fixed window minimized closing bug. -/// - 2016/11/19 (1.28.5) - Fixed abstract combo box closing behavior. -/// - 2016/11/19 (1.28.4) - Fixed tooltip flickering. -/// - 2016/11/19 (1.28.3) - Fixed memory leak caused by popup repeated closing. -/// - 2016/11/18 (1.28.2) - Fixed memory leak caused by popup panel allocation. -/// - 2016/11/10 (1.28.1) - Fixed some warnings and C++ error. -/// - 2016/11/10 (1.28.0) - Added additional `nk_button` versions which allows to directly -/// pass in a style struct to change buttons visual. -/// - 2016/11/10 (1.27.0) - Added additional `nk_tree` versions to support external state -/// storage. Just like last the `nk_group` commit the main -/// advantage is that you optionally can minimize nuklears runtime -/// memory consumption or handle hash collisions. -/// - 2016/11/09 (1.26.0) - Added additional `nk_group` version to support external scrollbar -/// offset storage. Main advantage is that you can externalize -/// the memory management for the offset. It could also be helpful -/// if you have a hash collision in `nk_group_begin` but really -/// want the name. In addition I added `nk_list_view` which allows -/// to draw big lists inside a group without actually having to -/// commit the whole list to nuklear (issue #269). -/// - 2016/10/30 (1.25.1) - Fixed clipping rectangle bug inside `nk_draw_list`. -/// - 2016/10/29 (1.25.0) - Pulled `nk_panel` memory management into nuklear and out of -/// the hands of the user. From now on users don't have to care -/// about panels unless they care about some information. If you -/// still need the panel just call `nk_window_get_panel`. -/// - 2016/10/21 (1.24.0) - Changed widget border drawing to stroked rectangle from filled -/// rectangle for less overdraw and widget background transparency. -/// - 2016/10/18 (1.23.0) - Added `nk_edit_focus` for manually edit widget focus control. -/// - 2016/09/29 (1.22.7) - Fixed deduction of basic type in non `` compilation. -/// - 2016/09/29 (1.22.6) - Fixed edit widget UTF-8 text cursor drawing bug. -/// - 2016/09/28 (1.22.5) - Fixed edit widget UTF-8 text appending/inserting/removing. -/// - 2016/09/28 (1.22.4) - Fixed drawing bug inside edit widgets which offset all text -/// text in every edit widget if one of them is scrolled. -/// - 2016/09/28 (1.22.3) - Fixed small bug in edit widgets if not active. The wrong -/// text length is passed. It should have been in bytes but -/// was passed as glyphes. -/// - 2016/09/20 (1.22.2) - Fixed color button size calculation. -/// - 2016/09/20 (1.22.1) - Fixed some `nk_vsnprintf` behavior bugs and removed `` -/// again from `NK_INCLUDE_STANDARD_VARARGS`. -/// - 2016/09/18 (1.22.0) - C89 does not support vsnprintf only C99 and newer as well -/// as C++11 and newer. In addition to use vsnprintf you have -/// to include . So just defining `NK_INCLUDE_STD_VAR_ARGS` -/// is not enough. That behavior is now fixed. By default if -/// both varargs as well as stdio is selected I try to use -/// vsnprintf if not possible I will revert to vsprintf. If -/// varargs but not stdio was defined I will use my own function. -/// - 2016/09/15 (1.21.2) - Fixed panel `close` behavior for deeper panel levels. -/// - 2016/09/15 (1.21.1) - Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`. -/// - 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo, -/// and contextual which prevented closing in y-direction if -/// popup did not reach max height. -/// In addition the height parameter was changed into vec2 -/// for width and height to have more control over the popup size. -/// - 2016/09/13 (1.20.3) - Cleaned up and extended type selection. -/// - 2016/09/13 (1.20.2) - Fixed slider behavior hopefully for the last time. This time -/// all calculation are correct so no more hackery. -/// - 2016/09/13 (1.20.1) - Internal change to divide window/panel flags into panel flags and types. -/// Suprisinly spend years in C and still happened to confuse types -/// with flags. Probably something to take note. -/// - 2016/09/08 (1.20.0) - Added additional helper function to make it easier to just -/// take the produced buffers from `nk_convert` and unplug the -/// iteration process from `nk_context`. So now you can -/// just use the vertex,element and command buffer + two pointer -/// inside the command buffer retrieved by calls `nk__draw_begin` -/// and `nk__draw_end` and macro `nk_draw_foreach_bounded`. -/// - 2016/09/08 (1.19.0) - Added additional asserts to make sure every `nk_xxx_begin` call -/// for windows, popups, combobox, menu and contextual is guarded by -/// `if` condition and does not produce false drawing output. -/// - 2016/09/08 (1.18.0) - Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT` -/// to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and -/// `NK_SYMBOL_RECT_OUTLINE`. -/// - 2016/09/08 (1.17.0) - Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE` -/// to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and -/// `NK_SYMBOL_CIRCLE_OUTLINE`. -/// - 2016/09/08 (1.16.0) - Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES` -/// is not defined by supporting the biggest compiler GCC, clang and MSVC. -/// - 2016/09/07 (1.15.3) - Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error. -/// - 2016/09/04 (1.15.2) - Fixed wrong combobox height calculation. -/// - 2016/09/03 (1.15.1) - Fixed gaps inside combo boxes in OpenGL. -/// - 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and -/// instead made it user provided. The range of types to convert -/// to is quite limited at the moment, but I would be more than -/// happy to accept PRs to add additional. -/// - 2016/08/30 (1.14.2) - Removed unused variables. -/// - 2016/08/30 (1.14.1) - Fixed C++ build errors. -/// - 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly. -/// - 2016/08/30 (1.13.4) - Tweaked some default styling variables. -/// - 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would -/// refrain from using slider with a big number of steps. -/// - 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the -/// window was in Read Only Mode. -/// - 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just -/// a hack for combo box and menu. -/// - 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since -/// it is bugged and causes issues in window selection. -/// - 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now -/// determined by the scrollbar size. -/// - 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11.0. -/// - 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection. -/// - 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code -/// handling panel padding and panel border. -/// - 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx`. -/// - 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups. -/// - 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes. -/// - 2016/08/26 (1.10.0) - Added window name string prepresentation to account for -/// hash collisions. Currently limited to `NK_WINDOW_MAX_NAME` -/// which in term can be redefined if not big enough. -/// - 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code. -/// - 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released' -/// to account for key press and release happening in one frame. -/// - 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate. -/// - 2016/08/17 (1.09.6) - Removed invalid check for value zero in `nk_propertyx`. -/// - 2016/08/16 (1.09.5) - Fixed ROM mode for deeper levels of popup windows parents. -/// - 2016/08/15 (1.09.4) - Editbox are now still active if enter was pressed with flag -/// `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep -/// typing after commiting. -/// - 2016/08/15 (1.09.4) - Removed redundant code. -/// - 2016/08/15 (1.09.4) - Fixed negative numbers in `nk_strtoi` and remove unused variable. -/// - 2016/08/15 (1.09.3) - Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background -/// window only as selected by hovering and not by clicking. -/// - 2016/08/14 (1.09.2) - Fixed a bug in font atlas which caused wrong loading -/// of glyphes for font with multiple ranges. -/// - 2016/08/12 (1.09.1) - Added additional function to check if window is currently -/// hidden and therefore not visible. -/// - 2016/08/12 (1.09.1) - nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED` -/// instead of the old flag `NK_WINDOW_HIDDEN`. -/// - 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed -/// the underlying implementation to not cast to float and instead -/// work directly on the given values. -/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal -/// floating pointer number to string conversion for additional -/// precision. -/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal -/// string to floating point number conversion for additional -/// precision. -/// - 2016/08/08 (1.07.2) - Fixed compiling error without define `NK_INCLUDE_FIXED_TYPE`. -/// - 2016/08/08 (1.07.1) - Fixed possible floating point error inside `nk_widget` leading -/// to wrong wiget width calculation which results in widgets falsly -/// becomming tagged as not inside window and cannot be accessed. -/// - 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and -/// closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown -/// by using `nk_window_show` and closed by either clicking the close -/// icon in a window or by calling `nk_window_close`. Only closed -/// windows get removed at the end of the frame while hidden windows -/// remain. -/// - 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to -/// `nk_edit_string` which takes, edits and outputs a '\0' terminated string. -/// - 2016/08/08 (1.05.4) - Fixed scrollbar auto hiding behavior. -/// - 2016/08/08 (1.05.3) - Fixed wrong panel padding selection in `nk_layout_widget_space`. -/// - 2016/08/07 (1.05.2) - Fixed old bug in dynamic immediate mode layout API, calculating -/// wrong item spacing and panel width. -/// - 2016/08/07 (1.05.1) - Hopefully finally fixed combobox popup drawing bug. -/// - 2016/08/07 (1.05.0) - Split varargs away from `NK_INCLUDE_STANDARD_IO` into own -/// define `NK_INCLUDE_STANDARD_VARARGS` to allow more fine -/// grained controlled over library includes. -/// - 2016/08/06 (1.04.5) - Changed memset calls to `NK_MEMSET`. -/// - 2016/08/04 (1.04.4) - Fixed fast window scaling behavior. -/// - 2016/08/04 (1.04.3) - Fixed window scaling, movement bug which appears if you -/// move/scale a window and another window is behind it. -/// If you are fast enough then the window behind gets activated -/// and the operation is blocked. I now require activating -/// by hovering only if mouse is not pressed. -/// - 2016/08/04 (1.04.2) - Fixed changing fonts. -/// - 2016/08/03 (1.04.1) - Fixed `NK_WINDOW_BACKGROUND` behavior. -/// - 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image`. -/// - 2016/08/03 (1.04.0) - Added additional window padding style attributes for -/// sub windows (combo, menu, ...). -/// - 2016/08/03 (1.04.0) - Added functions to show/hide software cursor. -/// - 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window -/// to be always in the background of the screen. -/// - 2016/08/03 (1.03.2) - Removed invalid assert macro for NK_RGB color picker. -/// - 2016/08/01 (1.03.1) - Added helper macros into header include guard. -/// - 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to -/// simplify memory management by removing the need to -/// allocate the pool. -/// - 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled -/// will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT -/// seconds without window interaction. To make it work -/// you have to also set a delta time inside the `nk_context`. -/// - 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs. -/// - 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context`. -/// - 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument. -/// - 2016/07/15 (1.01.0) - Removed internal font baking API and simplified -/// font atlas memory management by converting pointer -/// arrays for fonts and font configurations to lists. -/// - 2016/07/15 (1.00.0) - Changed button API to use context dependend button -/// behavior instead of passing it for every function call. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// ## Gallery -/// ![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png) -/// ![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png) -/// ![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png) -/// ![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png) -/// ![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png) -/// ![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png) -/// ![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif) -/// ![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png) -/// ![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png) -/// -/// ## Credits -/// Developed by Micha Mettke and every direct or indirect github contributor.

-/// -/// Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain)
-/// Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation

-/// Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
-/// -/// Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and -/// giving me the inspiration for this library, Casey Muratori for handmade hero -/// and his original immediate mode graphical user interface idea and Sean -/// Barret for his amazing single header libraries which restored my faith -/// in libraries and brought me to create some of my own. Finally Apoorva Joshi -/// for his single header file packer. -*/ - diff --git a/source/engine/thirdparty/sokol/tests/ext/stb_truetype.h b/source/engine/thirdparty/sokol/tests/ext/stb_truetype.h deleted file mode 100644 index 98a12c9..0000000 --- a/source/engine/thirdparty/sokol/tests/ext/stb_truetype.h +++ /dev/null @@ -1,4548 +0,0 @@ -// stb_truetype.h - v1.16 - public domain -// authored from 2009-2016 by Sean Barrett / RAD Game Tools -// -// This library processes TrueType files: -// parse files -// extract glyph metrics -// extract glyph shapes -// render glyphs to one-channel bitmaps with antialiasing (box filter) -// render glyphs to one-channel SDF bitmaps (signed-distance field/function) -// -// Todo: -// non-MS cmaps -// crashproof on bad data -// hinting? (no longer patented) -// cleartype-style AA? -// optimize: use simple memory allocator for intermediates -// optimize: build edge-list directly from curves -// optimize: rasterize directly from curves? -// -// ADDITIONAL CONTRIBUTORS -// -// Mikko Mononen: compound shape support, more cmap formats -// Tor Andersson: kerning, subpixel rendering -// Dougall Johnson: OpenType / Type 2 font handling -// -// Misc other: -// Ryan Gordon -// Simon Glass -// github:IntellectualKitty -// -// Bug/warning reports/fixes: -// "Zer" on mollyrocket -// Cass Everitt -// stoiko (Haemimont Games) -// Brian Hook -// Walter van Niftrik -// David Gow -// David Given -// Ivan-Assen Ivanov -// Anthony Pesch -// Johan Duparc -// Hou Qiming -// Fabian "ryg" Giesen -// Martins Mozeiko -// Cap Petschulat -// Omar Cornut -// github:aloucks -// Peter LaValle -// Sergey Popov -// Giumo X. Clanjor -// Higor Euripedes -// Thomas Fields -// Derek Vinyard -// Cort Stratton -// -// VERSION HISTORY -// -// 1.16 (2017-07-12) SDF support -// 1.15 (2017-03-03) make more arguments const -// 1.14 (2017-01-16) num-fonts-in-TTC function -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual -// 1.11 (2016-04-02) fix unused-variable warning -// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; -// variant PackFontRanges to pack and render in separate phases; -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); -// fixed an assert() bug in the new rasterizer -// replace assert() with STBTT_assert() in new rasterizer -// -// Full history can be found at the end of this file. -// -// LICENSE -// -// See end of file for license information. -// -// USAGE -// -// Include this file in whatever places neeed to refer to it. In ONE C/C++ -// file, write: -// #define STB_TRUETYPE_IMPLEMENTATION -// before the #include of this file. This expands out the actual -// implementation into that C/C++ file. -// -// To make the implementation private to the file that generates the implementation, -// #define STBTT_STATIC -// -// Simple 3D API (don't ship this, but it's fine for tools and quick start) -// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture -// stbtt_GetBakedQuad() -- compute quad to draw for a given char -// -// Improved 3D API (more shippable): -// #include "stb_rect_pack.h" -- optional, but you really want it -// stbtt_PackBegin() -// stbtt_PackSetOversample() -- for improved quality on small fonts -// stbtt_PackFontRanges() -- pack and renders -// stbtt_PackEnd() -// stbtt_GetPackedQuad() -// -// "Load" a font file from a memory buffer (you have to keep the buffer loaded) -// stbtt_InitFont() -// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections -// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections -// -// Render a unicode codepoint to a bitmap -// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap -// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide -// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be -// -// Character advance/positioning -// stbtt_GetCodepointHMetrics() -// stbtt_GetFontVMetrics() -// stbtt_GetCodepointKernAdvance() -// -// Starting with version 1.06, the rasterizer was replaced with a new, -// faster and generally-more-precise rasterizer. The new rasterizer more -// accurately measures pixel coverage for anti-aliasing, except in the case -// where multiple shapes overlap, in which case it overestimates the AA pixel -// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If -// this turns out to be a problem, you can re-enable the old rasterizer with -// #define STBTT_RASTERIZER_VERSION 1 -// which will incur about a 15% speed hit. -// -// ADDITIONAL DOCUMENTATION -// -// Immediately after this block comment are a series of sample programs. -// -// After the sample programs is the "header file" section. This section -// includes documentation for each API function. -// -// Some important concepts to understand to use this library: -// -// Codepoint -// Characters are defined by unicode codepoints, e.g. 65 is -// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is -// the hiragana for "ma". -// -// Glyph -// A visual character shape (every codepoint is rendered as -// some glyph) -// -// Glyph index -// A font-specific integer ID representing a glyph -// -// Baseline -// Glyph shapes are defined relative to a baseline, which is the -// bottom of uppercase characters. Characters extend both above -// and below the baseline. -// -// Current Point -// As you draw text to the screen, you keep track of a "current point" -// which is the origin of each character. The current point's vertical -// position is the baseline. Even "baked fonts" use this model. -// -// Vertical Font Metrics -// The vertical qualities of the font, used to vertically position -// and space the characters. See docs for stbtt_GetFontVMetrics. -// -// Font Size in Pixels or Points -// The preferred interface for specifying font sizes in stb_truetype -// is to specify how tall the font's vertical extent should be in pixels. -// If that sounds good enough, skip the next paragraph. -// -// Most font APIs instead use "points", which are a common typographic -// measurement for describing font size, defined as 72 points per inch. -// stb_truetype provides a point API for compatibility. However, true -// "per inch" conventions don't make much sense on computer displays -// since they different monitors have different number of pixels per -// inch. For example, Windows traditionally uses a convention that -// there are 96 pixels per inch, thus making 'inch' measurements have -// nothing to do with inches, and thus effectively defining a point to -// be 1.333 pixels. Additionally, the TrueType font data provides -// an explicit scale factor to scale a given font's glyphs to points, -// but the author has observed that this scale factor is often wrong -// for non-commercial fonts, thus making fonts scaled in points -// according to the TrueType spec incoherently sized in practice. -// -// ADVANCED USAGE -// -// Quality: -// -// - Use the functions with Subpixel at the end to allow your characters -// to have subpixel positioning. Since the font is anti-aliased, not -// hinted, this is very import for quality. (This is not possible with -// baked fonts.) -// -// - Kerning is now supported, and if you're supporting subpixel rendering -// then kerning is worth using to give your text a polished look. -// -// Performance: -// -// - Convert Unicode codepoints to glyph indexes and operate on the glyphs; -// if you don't do this, stb_truetype is forced to do the conversion on -// every call. -// -// - There are a lot of memory allocations. We should modify it to take -// a temp buffer and allocate from the temp buffer (without freeing), -// should help performance a lot. -// -// NOTES -// -// The system uses the raw data found in the .ttf file without changing it -// and without building auxiliary data structures. This is a bit inefficient -// on little-endian systems (the data is big-endian), but assuming you're -// caching the bitmaps or glyph shapes this shouldn't be a big deal. -// -// It appears to be very hard to programmatically determine what font a -// given file is in a general way. I provide an API for this, but I don't -// recommend it. -// -// -// SOURCE STATISTICS (based on v0.6c, 2050 LOC) -// -// Documentation & header file 520 LOC \___ 660 LOC documentation -// Sample code 140 LOC / -// Truetype parsing 620 LOC ---- 620 LOC TrueType -// Software rasterization 240 LOC \ . -// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation -// Bitmap management 100 LOC / -// Baked bitmap interface 70 LOC / -// Font name matching & access 150 LOC ---- 150 -// C runtime library abstraction 60 LOC ---- 60 -// -// -// PERFORMANCE MEASUREMENTS FOR 1.06: -// -// 32-bit 64-bit -// Previous release: 8.83 s 7.68 s -// Pool allocations: 7.72 s 6.34 s -// Inline sort : 6.54 s 5.65 s -// New rasterizer : 5.63 s 5.00 s - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// SAMPLE PROGRAMS -//// -// -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless -// -#if 0 -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -unsigned char ttf_buffer[1<<20]; -unsigned char temp_bitmap[512*512]; - -stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs -GLuint ftex; - -void my_stbtt_initfont(void) -{ - fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); - stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! - // can free ttf_buffer at this point - glGenTextures(1, &ftex); - glBindTexture(GL_TEXTURE_2D, ftex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); - // can free temp_bitmap at this point - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -void my_stbtt_print(float x, float y, char *text) -{ - // assume orthographic projection with units = screen pixels, origin at top left - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, ftex); - glBegin(GL_QUADS); - while (*text) { - if (*text >= 32 && *text < 128) { - stbtt_aligned_quad q; - stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); - } - ++text; - } - glEnd(); -} -#endif -// -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program (this compiles): get a single bitmap, print as ASCII art -// -#if 0 -#include -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -char ttf_buffer[1<<25]; - -int main(int argc, char **argv) -{ - stbtt_fontinfo font; - unsigned char *bitmap; - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); - - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); - - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); - putchar('\n'); - } - return 0; -} -#endif -// -// Output: -// -// .ii. -// @@@@@@. -// V@Mio@@o -// :i. V@V -// :oM@@M -// :@@@MM@M -// @@o o@M -// :@@. M@M -// @@@o@@@@ -// :M@@V:@@. -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program: print "Hello World!" banner, with bugs -// -#if 0 -char buffer[24<<20]; -unsigned char screen[20][79]; - -int main(int arg, char **argv) -{ - stbtt_fontinfo font; - int i,j,ascent,baseline,ch=0; - float scale, xpos=2; // leave a little padding in case the character extends left - char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness - - fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); - stbtt_InitFont(&font, buffer, 0); - - scale = stbtt_ScaleForPixelHeight(&font, 15); - stbtt_GetFontVMetrics(&font, &ascent,0,0); - baseline = (int) (ascent*scale); - - while (text[ch]) { - int advance,lsb,x0,y0,x1,y1; - float x_shift = xpos - (float) floor(xpos); - stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); - stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); - stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); - // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong - // because this API is really for baking character bitmaps into textures. if you want to render - // a sequence of characters, you really need to render each bitmap to a temp buffer, then - // "alpha blend" that into the working buffer - xpos += (advance * scale); - if (text[ch+1]) - xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); - ++ch; - } - - for (j=0; j < 20; ++j) { - for (i=0; i < 78; ++i) - putchar(" .:ioVM@"[screen[j][i]>>5]); - putchar('\n'); - } - - return 0; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// INTEGRATION WITH YOUR CODEBASE -//// -//// The following sections allow you to supply alternate definitions -//// of C library functions used by stb_truetype. - -#ifdef STB_TRUETYPE_IMPLEMENTATION - // #define your own (u)stbtt_int8/16/32 before including to override this - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif - - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - - // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif - - #ifndef STBTT_sqrt - #include - #define STBTT_sqrt(x) sqrt(x) - #define STBTT_pow(x,y) pow(x,y) - #endif - - #ifndef STBTT_cos - #include - #define STBTT_cos(x) cos(x) - #define STBTT_acos(x) acos(x) - #endif - - #ifndef STBTT_fabs - #include - #define STBTT_fabs(x) fabs(x) - #endif - - #ifndef STBTT_fabs - #include - #define STBTT_fabs(x) fabs(x) - #endif - - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif - - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif - - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif - - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// INTERFACE -//// -//// - -#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ -#define __STB_INCLUDE_STB_TRUETYPE_H__ - -#ifdef STBTT_STATIC -#define STBTT_DEF static -#else -#define STBTT_DEF extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// private structure -typedef struct -{ - unsigned char *data; - int cursor; - int size; -} stbtt__buf; - -////////////////////////////////////////////////////////////////////////////// -// -// TEXTURE BAKING API -// -// If you use this API, you only have to call two functions ever. -// - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; -} stbtt_bakedchar; - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long -// if return is positive, the first unused row of the bitmap -// if return is negative, returns the negative of the number of characters that fit -// if return is 0, no characters fit and no rows were used -// This uses a very crappy packing. - -typedef struct -{ - float x0,y0,s0,t0; // top-left - float x1,y1,s1,t1; // bottom-right -} stbtt_aligned_quad; - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier -// Call GetBakedQuad with char_index = 'character - first_char', and it -// creates the quad you need to draw and advances the current position. -// -// The coordinate system used assumes y increases downwards. -// -// Characters will extend both above and below the current position; -// see discussion of "BASELINE" above. -// -// It's inefficient; you might want to c&p it and optimize it. - - - -////////////////////////////////////////////////////////////////////////////// -// -// NEW TEXTURE BAKING API -// -// This provides options for packing multiple fonts into one atlas, not -// perfectly but better than nothing. - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; - float xoff2,yoff2; -} stbtt_packedchar; - -typedef struct stbtt_pack_context stbtt_pack_context; -typedef struct stbtt_fontinfo stbtt_fontinfo; -#ifndef STB_RECT_PACK_VERSION -typedef struct stbrp_rect stbrp_rect; -#endif - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); -// Initializes a packing context stored in the passed-in stbtt_pack_context. -// Future calls using this context will pack characters into the bitmap passed -// in here: a 1-channel bitmap that is width * height. stride_in_bytes is -// the distance from one row to the next (or 0 to mean they are packed tightly -// together). "padding" is the amount of padding to leave between each -// character (normally you want '1' for bitmaps you'll use as textures with -// bilinear filtering). -// -// Returns 0 on failure, 1 on success. - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); -// Cleans up the packing context and frees all memory. - -#define STBTT_POINT_SIZE(x) (-(x)) - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); -// Creates character bitmaps from the font_index'th font found in fontdata (use -// font_index=0 if you don't know what that is). It creates num_chars_in_range -// bitmaps for characters with unicode values starting at first_unicode_char_in_range -// and increasing. Data for how to render them is stored in chardata_for_range; -// pass these to stbtt_GetPackedQuad to get back renderable quads. -// -// font_size is the full height of the character from ascender to descender, -// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed -// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() -// and pass that result as 'font_size': -// ..., 20 , ... // font max minus min y is 20 pixels tall -// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall - -typedef struct -{ - float font_size; - int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint - int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints - int num_chars; - stbtt_packedchar *chardata_for_range; // output - unsigned char h_oversample, v_oversample; // don't set these, they're used internally -} stbtt_pack_range; - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); -// Creates character bitmaps from multiple ranges of characters stored in -// ranges. This will usually create a better-packed bitmap than multiple -// calls to stbtt_PackFontRange. Note that you can call this multiple -// times within a single PackBegin/PackEnd. - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); -// Oversampling a font increases the quality by allowing higher-quality subpixel -// positioning, and is especially valuable at smaller text sizes. -// -// This function sets the amount of oversampling for all following calls to -// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given -// pack context. The default (no oversampling) is achieved by h_oversample=1 -// and v_oversample=1. The total number of pixels required is -// h_oversample*v_oversample larger than the default; for example, 2x2 -// oversampling requires 4x the storage of 1x1. For best results, render -// oversampled textures with bilinear filtering. Look at the readme in -// stb/tests/oversample for information about oversampled fonts -// -// To use with PackFontRangesGather etc., you must set it before calls -// call to PackFontRangesGatherRects. - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int align_to_integer); - -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -// Calling these functions in sequence is roughly equivalent to calling -// stbtt_PackFontRanges(). If you more control over the packing of multiple -// fonts, or if you want to pack custom data into a font texture, take a look -// at the source to of stbtt_PackFontRanges() and create a custom version -// using these functions, e.g. call GatherRects multiple times, -// building up a single array of rects, then call PackRects once, -// then call RenderIntoRects repeatedly. This may result in a -// better packing than calling PackFontRanges multiple times -// (or it may not). - -// this is an opaque structure that you shouldn't mess with which holds -// all the context needed from PackBegin to PackEnd. -struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// FONT LOADING -// -// - -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); -// This function will determine the number of fonts in a font file. TrueType -// collection (.ttc) files may contain multiple fonts, while TrueType font -// (.ttf) files only contain one font. The number of fonts can be used for -// indexing with the previous function where the index is between zero and one -// less than the total fonts. If an error occurs, -1 is returned. - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); -// Each .ttf/.ttc file may have more than one font. Each font has a sequential -// index number starting from 0. Call this function to get the font offset for -// a given index; it returns -1 if the index is out of range. A regular .ttf -// file will only define one font and it always be at offset 0, so it will -// return '0' for index 0, and -1 for all other indices. - -// The following structure is defined publically so you can declare one on -// the stack or as a global or etc, but you should treat it as opaque. -struct stbtt_fontinfo -{ - void * userdata; - unsigned char * data; // pointer to .ttf file - int fontstart; // offset of start of font - - int numGlyphs; // number of glyphs, needed for range checking - - int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf - int index_map; // a cmap mapping for our chosen character encoding - int indexToLocFormat; // format needed to map from glyph index to glyph - - stbtt__buf cff; // cff font data - stbtt__buf charstrings; // the charstring index - stbtt__buf gsubrs; // global charstring subroutines index - stbtt__buf subrs; // private charstring subroutines index - stbtt__buf fontdicts; // array of font dicts - stbtt__buf fdselect; // map from glyph to fontdict -}; - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); -// Given an offset into the file that defines a font, this function builds -// the necessary cached info for the rest of the system. You must allocate -// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't -// need to do anything special to free it, because the contents are pure -// value data with no additional data structures. Returns 0 on failure. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER TO GLYPH-INDEX CONVERSIOn - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); -// If you're going to perform multiple operations on the same character -// and you want a speed-up, call this function with the character you're -// going to process, then use glyph-based functions instead of the -// codepoint-based functions. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER PROPERTIES -// - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose "height" is 'pixels' tall. -// Height is measured as the distance from the highest ascender to the lowest -// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics -// and computing: -// scale = pixels / (ascent - descent) -// so if you prefer to measure height by the ascent only, use a similar calculation. - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose EM size is mapped to -// 'pixels' tall. This is probably what traditional APIs compute, but -// I'm not positive. - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); -// ascent is the coordinate above the baseline the font extends; descent -// is the coordinate below the baseline the font extends (i.e. it is typically negative) -// lineGap is the spacing between one row's descent and the next row's ascent... -// so you should advance the vertical position by "*ascent - *descent + *lineGap" -// these are expressed in unscaled coordinates, so you must multiply by -// the scale factor for a given size - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); -// the bounding box around all possible characters - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); -// leftSideBearing is the offset from the current horizontal position to the left edge of the character -// advanceWidth is the offset from the current horizontal position to the next horizontal position -// these are expressed in unscaled coordinates - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); -// an additional amount to add to the 'advance' value between ch1 and ch2 - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); -// Gets the bounding box of the visible part of the glyph, in unscaled coordinates - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); -// as above, but takes one or more glyph indices for greater efficiency - - -////////////////////////////////////////////////////////////////////////////// -// -// GLYPH SHAPES (you probably don't need these, but they have to go before -// the bitmaps for C declaration-order reasons) -// - -#ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve, - STBTT_vcubic - }; -#endif - -#ifndef stbtt_vertex // you can predefine this to use different values - // (we share this with other code at RAD) - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file - typedef struct - { - stbtt_vertex_type x,y,cx,cy,cx1,cy1; - unsigned char type,padding; - } stbtt_vertex; -#endif - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); -// returns non-zero if nothing is drawn for this glyph - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); -// returns # of vertices and fills *vertices with the pointer to them -// these are expressed in "unscaled" coordinates -// -// The shape is a series of countours. Each one starts with -// a STBTT_moveto, then consists of a series of mixed -// STBTT_lineto and STBTT_curveto segments. A lineto -// draws a line from previous endpoint to its x,y; a curveto -// draws a quadratic bezier from previous endpoint to -// its x,y, using cx,cy as the bezier control point. - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); -// frees the data allocated above - -////////////////////////////////////////////////////////////////////////////// -// -// BITMAP RENDERING -// - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); -// frees the bitmap allocated below - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// allocates a large-enough single-channel 8bpp bitmap and renders the -// specified character/glyph at the specified scale into it, with -// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). -// *width & *height are filled out with the width & height of the bitmap, -// which is stored left-to-right, top-to-bottom. -// -// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel -// shift for the character - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); -// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap -// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap -// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the -// width and height and positioning info for it first. - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); -// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel -// shift for the character - -// NOTE sokol-samples: declared static but never defined: T_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); -// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering -// is performed (see stbtt_PackSetOversampling) - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -// get the bbox of the bitmap centered around the glyph origin; so the -// bitmap width is ix1-ix0, height is iy1-iy0, and location to place -// the bitmap top left is (leftSideBearing*scale,iy0). -// (Note that the bitmap uses y-increases-down, but the shape uses -// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); -// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel -// shift for the character - -// the following functions are equivalent to the above functions, but operate -// on glyph indices instead of Unicode codepoints (for efficiency) -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); - - -// @TODO: don't expose this structure -typedef struct -{ - int w,h,stride; - unsigned char *pixels; -} stbtt__bitmap; - -// rasterize a shape with quadratic beziers into a bitmap -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into - float flatness_in_pixels, // allowable error of curve in pixels - stbtt_vertex *vertices, // array of vertices defining shape - int num_verts, // number of vertices in above array - float scale_x, float scale_y, // scale applied to input vertices - float shift_x, float shift_y, // translation applied to input vertices - int x_off, int y_off, // another translation applied to input - int invert, // if non-zero, vertically flip shape - void *userdata); // context for to STBTT_MALLOC - -////////////////////////////////////////////////////////////////////////////// -// -// Signed Distance Function (or Field) rendering - -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); -// frees the SDF bitmap allocated below - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -// These functions compute a discretized SDF field for a single character, suitable for storing -// in a single-channel texture, sampling with bilinear filtering, and testing against -// larger than some threshhold to produce scalable fonts. -// info -- the font -// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap -// glyph/codepoint -- the character to generate the SDF for -// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), -// which allows effects like bit outlines -// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) -// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) -// if positive, > onedge_value is inside; if negative, < onedge_value is inside -// width,height -- output height & width of the SDF bitmap (including padding) -// xoff,yoff -- output origin of the character -// return value -- a 2D array of bytes 0..255, width*height in size -// -// pixel_dist_scale & onedge_value are a scale & bias that allows you to make -// optimal use of the limited 0..255 for your application, trading off precision -// and special effects. SDF values outside the range 0..255 are clamped to 0..255. -// -// Example: -// scale = stbtt_ScaleForPixelHeight(22) -// padding = 5 -// onedge_value = 180 -// pixel_dist_scale = 180/5.0 = 36.0 -// -// This will create an SDF bitmap in which the character is about 22 pixels -// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled -// shape, sample the SDF at each pixel and fill the pixel if the SDF value -// is greater than or equal to 180/255. (You'll actually want to antialias, -// which is beyond the scope of this example.) Additionally, you can compute -// offset outlines (e.g. to stroke the character border inside & outside, -// or only outside). For example, to fill outside the character up to 3 SDF -// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above -// choice of variables maps a range from 5 pixels outside the shape to -// 2 pixels inside the shape to 0..255; this is intended primarily for apply -// outside effects only (the interior range is needed to allow proper -// antialiasing of the font at *smaller* sizes) -// -// The function computes the SDF analytically at each SDF pixel, not by e.g. -// building a higher-res bitmap and approximating it. In theory the quality -// should be as high as possible for an SDF of this size & representation, but -// unclear if this is true in practice (perhaps building a higher-res bitmap -// and computing from that can allow drop-out prevention). -// -// The algorithm has not been optimized at all, so expect it to be slow -// if computing lots of characters or very large sizes. - - - -////////////////////////////////////////////////////////////////////////////// -// -// Finding the right font... -// -// You should really just solve this offline, keep your own tables -// of what font is what, and don't try to get it out of the .ttf file. -// That's because getting it out of the .ttf file is really hard, because -// the names in the file can appear in many possible encodings, in many -// possible languages, and e.g. if you need a case-insensitive comparison, -// the details of that depend on the encoding & language in a complex way -// (actually underspecified in truetype, but also gigantic). -// -// But you can use the provided functions in two possible ways: -// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on -// unicode-encoded names to try to find the font you want; -// you can run this before calling stbtt_InitFont() -// -// stbtt_GetFontNameString() lets you get any of the various strings -// from the file yourself and do your own comparisons on them. -// You have to have called stbtt_InitFont() first. - - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); -// returns the offset (not index) of the font that matches, or -1 if none -// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". -// if you use any other flag, use a font name like "Arial"; this checks -// the 'macStyle' header field; i don't know if fonts set this consistently -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); -// returns 1/0 whether the first string interpreted as utf8 is identical to -// the second string interpreted as big-endian utf16... useful for strings from next func - -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); -// returns the string (which may be big-endian double byte, e.g. for unicode) -// and puts the length in bytes in *length. -// -// some of the values for the IDs are below; for more see the truetype spec: -// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html -// http://www.microsoft.com/typography/otspec/name.htm - -enum { // platformID - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_UNICODE - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 -}; - -enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... - // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D -}; - -enum { // languageID for STBTT_PLATFORM_ID_MAC - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 -}; - -#ifdef __cplusplus -} -#endif - -#endif // __STB_INCLUDE_STB_TRUETYPE_H__ - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// IMPLEMENTATION -//// -//// - -#ifdef STB_TRUETYPE_IMPLEMENTATION - -#ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 -#endif - -#if STBTT_MAX_OVERSAMPLE > 255 -#error "STBTT_MAX_OVERSAMPLE cannot be > 255" -#endif - -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; - -#ifndef STBTT_RASTERIZER_VERSION -#define STBTT_RASTERIZER_VERSION 2 -#endif - -#ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) -#else -#define STBTT__NOTUSED(v) (void)sizeof(v) -#endif - -////////////////////////////////////////////////////////////////////////// -// -// stbtt__buf helpers to parse data from file -// - -static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - assert(b->data); - return b->data[b->cursor++]; -} - -static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor]; -} - -static void stbtt__buf_seek(stbtt__buf *b, int o) -{ - STBTT_assert(!(o > b->size || o < 0)); - b->cursor = (o > b->size || o < 0) ? b->size : o; -} - -static void stbtt__buf_skip(stbtt__buf *b, int o) -{ - stbtt__buf_seek(b, b->cursor + o); -} - -static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) -{ - stbtt_uint32 v = 0; - int i; - STBTT_assert(n >= 1 && n <= 4); - for (i = 0; i < n; i++) - v = (v << 8) | stbtt__buf_get8(b); - return v; -} - -static stbtt__buf stbtt__new_buf(const void *p, size_t size) -{ - stbtt__buf r; - STBTT_assert(size < 0x40000000); - r.data = (stbtt_uint8*) p; - r.size = (int) size; - r.cursor = 0; - return r; -} - -#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) -#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) - -static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) -{ - stbtt__buf r = stbtt__new_buf(NULL, 0); - if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; - r.data = b->data + o; - r.size = s; - return r; -} - -static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) -{ - int count, start, offsize; - start = b->cursor; - count = stbtt__buf_get16(b); - if (count) { - offsize = stbtt__buf_get8(b); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(b, offsize * count); - stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); - } - return stbtt__buf_range(b, start, b->cursor - start); -} - -static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) -{ - int b0 = stbtt__buf_get8(b); - if (b0 >= 32 && b0 <= 246) return b0 - 139; - else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; - else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; - else if (b0 == 28) return stbtt__buf_get16(b); - else if (b0 == 29) return stbtt__buf_get32(b); - STBTT_assert(0); - return 0; -} - -static void stbtt__cff_skip_operand(stbtt__buf *b) { - int v, b0 = stbtt__buf_peek8(b); - STBTT_assert(b0 >= 28); - if (b0 == 30) { - stbtt__buf_skip(b, 1); - while (b->cursor < b->size) { - v = stbtt__buf_get8(b); - if ((v & 0xF) == 0xF || (v >> 4) == 0xF) - break; - } - } else { - stbtt__cff_int(b); - } -} - -static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) -{ - stbtt__buf_seek(b, 0); - while (b->cursor < b->size) { - int start = b->cursor, end, op; - while (stbtt__buf_peek8(b) >= 28) - stbtt__cff_skip_operand(b); - end = b->cursor; - op = stbtt__buf_get8(b); - if (op == 12) op = stbtt__buf_get8(b) | 0x100; - if (op == key) return stbtt__buf_range(b, start, end-start); - } - return stbtt__buf_range(b, 0, 0); -} - -static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) -{ - int i; - stbtt__buf operands = stbtt__dict_get(b, key); - for (i = 0; i < outcount && operands.cursor < operands.size; i++) - out[i] = stbtt__cff_int(&operands); -} - -static int stbtt__cff_index_count(stbtt__buf *b) -{ - stbtt__buf_seek(b, 0); - return stbtt__buf_get16(b); -} - -static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) -{ - int count, offsize, start, end; - stbtt__buf_seek(&b, 0); - count = stbtt__buf_get16(&b); - offsize = stbtt__buf_get8(&b); - STBTT_assert(i >= 0 && i < count); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(&b, i*offsize); - start = stbtt__buf_get(&b, offsize); - end = stbtt__buf_get(&b, offsize); - return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); -} - -////////////////////////////////////////////////////////////////////////// -// -// accessors to parse data from file -// - -// on platforms that don't allow misaligned reads, if we want to allow -// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE - -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) - -static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } -static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) - -static int stbtt__isfont(stbtt_uint8 *font) -{ - // check the version number - if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 - if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts - return 0; -} - -// @OPTIMIZE: binary search -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; -} - -static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) -{ - // if it's just a font, there's only one valid index - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*4); - } - } - return -1; -} - -static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) -{ - // if it's just a font, there's only one valid font - if (stbtt__isfont(font_collection)) - return 1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - return ttLONG(font_collection+8); - } - } - return 0; -} - -static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) -{ - stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; - stbtt__buf pdict; - stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); - if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); - pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); - stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); - if (!subrsoff) return stbtt__new_buf(NULL, 0); - stbtt__buf_seek(&cff, private_loc[1]+subrsoff); - return stbtt__cff_get_index(&cff); -} - -static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) -{ - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; - - info->data = data; - info->fontstart = fontstart; - info->cff = stbtt__new_buf(NULL, 0); - - cmap = stbtt__find_table(data, fontstart, "cmap"); // required - info->loca = stbtt__find_table(data, fontstart, "loca"); // required - info->head = stbtt__find_table(data, fontstart, "head"); // required - info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required - info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required - info->kern = stbtt__find_table(data, fontstart, "kern"); // not required - - if (!cmap || !info->head || !info->hhea || !info->hmtx) - return 0; - if (info->glyf) { - // required for truetype - if (!info->loca) return 0; - } else { - // initialization for CFF / Type2 fonts (OTF) - stbtt__buf b, topdict, topdictidx; - stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; - stbtt_uint32 cff; - - cff = stbtt__find_table(data, fontstart, "CFF "); - if (!cff) return 0; - - info->fontdicts = stbtt__new_buf(NULL, 0); - info->fdselect = stbtt__new_buf(NULL, 0); - - // @TODO this should use size from table (not 512MB) - info->cff = stbtt__new_buf(data+cff, 512*1024*1024); - b = info->cff; - - // read the header - stbtt__buf_skip(&b, 2); - stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize - - // @TODO the name INDEX could list multiple fonts, - // but we just use the first one. - stbtt__cff_get_index(&b); // name INDEX - topdictidx = stbtt__cff_get_index(&b); - topdict = stbtt__cff_index_get(topdictidx, 0); - stbtt__cff_get_index(&b); // string INDEX - info->gsubrs = stbtt__cff_get_index(&b); - - stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); - stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); - stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); - stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); - info->subrs = stbtt__get_subrs(b, topdict); - - // we only support Type 2 charstrings - if (cstype != 2) return 0; - if (charstrings == 0) return 0; - - if (fdarrayoff) { - // looks like a CID font - if (!fdselectoff) return 0; - stbtt__buf_seek(&b, fdarrayoff); - info->fontdicts = stbtt__cff_get_index(&b); - info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); - } - - stbtt__buf_seek(&b, charstrings); - info->charstrings = stbtt__cff_get_index(&b); - } - - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - // find a cmap encoding table we understand *now* to avoid searching - // later. (todo: could make this installable) - // the same regardless of glyph. - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - // find an encoding we understand: - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - // MS/Unicode - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - break; - case STBTT_PLATFORM_ID_UNICODE: - // Mac/iOS has these - // all the encodingIDs are unicode, so we don't bother to check it - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { // apple byte encoding - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - - // do a binary search of the segments - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - stbtt_uint16 end; - searchRange >>= 1; - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - { - stbtt_uint16 offset, start; - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; - - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - stbtt_uint32 ngroups = ttULONG(data+index_map+12); - stbtt_int32 low,high; - low = 0; high = (stbtt_int32)ngroups; - // Binary search the right group. - while (low < high) { - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else // format == 13 - return start_glyph; - } - } - return 0; // not found - } - // @TODO - STBTT_assert(0); - return 0; -} - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); -} - -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) -{ - v->type = type; - v->x = (stbtt_int16) x; - v->y = (stbtt_int16) y; - v->cx = (stbtt_int16) cx; - v->cy = (stbtt_int16) cy; -} - -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; - - STBTT_assert(!info->cff.size); - - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - - return g1==g2 ? -1 : g1; // if length is 0, return -1 -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); - -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - if (info->cff.size) { - stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); - } else { - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - } - return 1; -} - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt_int16 numberOfContours; - int g; - if (info->cff.size) - return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; - g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 1; - numberOfContours = ttSHORT(info->data + g); - return numberOfContours == 0; -} - -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) -{ - if (start_off) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - return num_vertices; -} - -static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + 2*numberOfContours; // a loose bound on how many vertices we might need - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - // in first pass, we load uninterpreted data into the allocated array - // above, shifted to the end of the array so we won't overwrite it when - // we create our final data starting from the front - - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - - // first load flags - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - // now load x coordinates - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; // ??? - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (stbtt_int16) x; - } - - // now load y coordinates - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; // ??? - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (stbtt_int16) y; - } - - // now convert them to our format - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - // now start the new one - start_off = !(flags & 1); - if (start_off) { - // if we start off with an off-curve point, then when we need to find a point on the curve - // where we can start, and we need to save some state for when we wraparound. - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - // next point is also a curve point, so interpolate an on-point curve - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; - } else { - // otherwise just use the next point as our start point - sx = (stbtt_int32) vertices[off+i+1].x; - sy = (stbtt_int32) vertices[off+i+1].y; - ++i; // we're using point i+1 as the starting point, so skip it - } - } else { - sx = x; - sy = y; - } - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) { // if it's a curve - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours == -1) { - // Compound shapes. - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { // XY values - if (flags & 1) { // shorts - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; - } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; - } - } - else { - // @TODO handle matching point - STBTT_assert(0); - } - if (flags & (1<<3)) { // WE_HAVE_A_SCALE - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - // Find transformation scales. - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - // Get indexed glyph. - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - // Transform vertices. - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - // Append vertices. - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; - } - if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; - STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - // More components ? - more = flags & (1<<5); - } - } else if (numberOfContours < 0) { - // @TODO other compound variations? - STBTT_assert(0); - } else { - // numberOfCounters == 0, do nothing - } - - *pvertices = vertices; - return num_vertices; -} - -typedef struct -{ - int bounds; - int started; - float first_x, first_y; - float x, y; - stbtt_int32 min_x, max_x, min_y, max_y; - - stbtt_vertex *pvertices; - int num_vertices; -} stbtt__csctx; - -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} - -static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) -{ - if (x > c->max_x || !c->started) c->max_x = x; - if (y > c->max_y || !c->started) c->max_y = y; - if (x < c->min_x || !c->started) c->min_x = x; - if (y < c->min_y || !c->started) c->min_y = y; - c->started = 1; -} - -static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) -{ - if (c->bounds) { - stbtt__track_vertex(c, x, y); - if (type == STBTT_vcubic) { - stbtt__track_vertex(c, cx, cy); - stbtt__track_vertex(c, cx1, cy1); - } - } else { - stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); - c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; - c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; - } - c->num_vertices++; -} - -static void stbtt__csctx_close_shape(stbtt__csctx *ctx) -{ - if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) -{ - stbtt__csctx_close_shape(ctx); - ctx->first_x = ctx->x = ctx->x + dx; - ctx->first_y = ctx->y = ctx->y + dy; - stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) -{ - ctx->x += dx; - ctx->y += dy; - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) -{ - float cx1 = ctx->x + dx1; - float cy1 = ctx->y + dy1; - float cx2 = cx1 + dx2; - float cy2 = cy1 + dy2; - ctx->x = cx2 + dx3; - ctx->y = cy2 + dy3; - stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); -} - -static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) -{ - int count = stbtt__cff_index_count(&idx); - int bias = 107; - if (count >= 33900) - bias = 32768; - else if (count >= 1240) - bias = 1131; - n += bias; - if (n < 0 || n >= count) - return stbtt__new_buf(NULL, 0); - return stbtt__cff_index_get(idx, n); -} - -static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt__buf fdselect = info->fdselect; - int nranges, start, end, v, fmt, fdselector = -1, i; - - stbtt__buf_seek(&fdselect, 0); - fmt = stbtt__buf_get8(&fdselect); - if (fmt == 0) { - // untested - stbtt__buf_skip(&fdselect, glyph_index); - fdselector = stbtt__buf_get8(&fdselect); - } else if (fmt == 3) { - nranges = stbtt__buf_get16(&fdselect); - start = stbtt__buf_get16(&fdselect); - for (i = 0; i < nranges; i++) { - v = stbtt__buf_get8(&fdselect); - end = stbtt__buf_get16(&fdselect); - if (glyph_index >= start && glyph_index < end) { - fdselector = v; - break; - } - start = end; - } - } - if (fdselector == -1) stbtt__new_buf(NULL, 0); - return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); -} - -static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) -{ - int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; - int has_subrs = 0, clear_stack; - float s[48]; - stbtt__buf subr_stack[10], subrs = info->subrs, b; - float f; - -#define STBTT__CSERR(s) (0) - - // this currently ignores the initial width value, which isn't needed if we have hmtx - b = stbtt__cff_index_get(info->charstrings, glyph_index); - while (b.cursor < b.size) { - i = 0; - clear_stack = 1; - b0 = stbtt__buf_get8(&b); - switch (b0) { - // @TODO implement hinting - case 0x13: // hintmask - case 0x14: // cntrmask - if (in_header) - maskbits += (sp / 2); // implicit "vstem" - in_header = 0; - stbtt__buf_skip(&b, (maskbits + 7) / 8); - break; - - case 0x01: // hstem - case 0x03: // vstem - case 0x12: // hstemhm - case 0x17: // vstemhm - maskbits += (sp / 2); - break; - - case 0x15: // rmoveto - in_header = 0; - if (sp < 2) return STBTT__CSERR("rmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); - break; - case 0x04: // vmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("vmoveto stack"); - stbtt__csctx_rmove_to(c, 0, s[sp-1]); - break; - case 0x16: // hmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("hmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-1], 0); - break; - - case 0x05: // rlineto - if (sp < 2) return STBTT__CSERR("rlineto stack"); - for (; i + 1 < sp; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical - // starting from a different place. - - case 0x07: // vlineto - if (sp < 1) return STBTT__CSERR("vlineto stack"); - goto vlineto; - case 0x06: // hlineto - if (sp < 1) return STBTT__CSERR("hlineto stack"); - for (;;) { - if (i >= sp) break; - stbtt__csctx_rline_to(c, s[i], 0); - i++; - vlineto: - if (i >= sp) break; - stbtt__csctx_rline_to(c, 0, s[i]); - i++; - } - break; - - case 0x1F: // hvcurveto - if (sp < 4) return STBTT__CSERR("hvcurveto stack"); - goto hvcurveto; - case 0x1E: // vhcurveto - if (sp < 4) return STBTT__CSERR("vhcurveto stack"); - for (;;) { - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); - i += 4; - hvcurveto: - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); - i += 4; - } - break; - - case 0x08: // rrcurveto - if (sp < 6) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x18: // rcurveline - if (sp < 8) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp - 2; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - case 0x19: // rlinecurve - if (sp < 8) return STBTT__CSERR("rlinecurve stack"); - for (; i + 1 < sp - 6; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x1A: // vvcurveto - case 0x1B: // hhcurveto - if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); - f = 0.0; - if (sp & 1) { f = s[i]; i++; } - for (; i + 3 < sp; i += 4) { - if (b0 == 0x1B) - stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); - else - stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); - f = 0.0; - } - break; - - case 0x0A: // callsubr - if (!has_subrs) { - if (info->fdselect.size) - subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); - has_subrs = 1; - } - // fallthrough - case 0x1D: // callgsubr - if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); - v = (int) s[--sp]; - if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); - subr_stack[subr_stack_height++] = b; - b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); - if (b.size == 0) return STBTT__CSERR("subr not found"); - b.cursor = 0; - clear_stack = 0; - break; - - case 0x0B: // return - if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); - b = subr_stack[--subr_stack_height]; - clear_stack = 0; - break; - - case 0x0E: // endchar - stbtt__csctx_close_shape(c); - return 1; - - case 0x0C: { // two-byte escape - float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; - float dx, dy; - int b1 = stbtt__buf_get8(&b); - switch (b1) { - // @TODO These "flex" implementations ignore the flex-depth and resolution, - // and always draw beziers. - case 0x22: // hflex - if (sp < 7) return STBTT__CSERR("hflex stack"); - dx1 = s[0]; - dx2 = s[1]; - dy2 = s[2]; - dx3 = s[3]; - dx4 = s[4]; - dx5 = s[5]; - dx6 = s[6]; - stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); - break; - - case 0x23: // flex - if (sp < 13) return STBTT__CSERR("flex stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = s[10]; - dy6 = s[11]; - //fd is s[12] - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - case 0x24: // hflex1 - if (sp < 9) return STBTT__CSERR("hflex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dx4 = s[5]; - dx5 = s[6]; - dy5 = s[7]; - dx6 = s[8]; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); - break; - - case 0x25: // flex1 - if (sp < 11) return STBTT__CSERR("flex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = dy6 = s[10]; - dx = dx1+dx2+dx3+dx4+dx5; - dy = dy1+dy2+dy3+dy4+dy5; - if (STBTT_fabs(dx) > STBTT_fabs(dy)) - dy6 = -dy; - else - dx6 = -dx; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - default: - return STBTT__CSERR("unimplemented"); - } - } break; - - default: - if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) - return STBTT__CSERR("reserved operator"); - - // push immediate - if (b0 == 255) { - f = (float)stbtt__buf_get32(&b) / 0x10000; - } else { - stbtt__buf_skip(&b, -1); - f = (float)(stbtt_int16)stbtt__cff_int(&b); - } - if (sp >= 48) return STBTT__CSERR("push stack overflow"); - s[sp++] = f; - clear_stack = 0; - break; - } - if (clear_stack) sp = 0; - } - return STBTT__CSERR("no endchar"); - -#undef STBTT__CSERR -} - -static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - // runs the charstring twice, once to count and once to output (to avoid realloc) - stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); - stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); - if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { - *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); - output_ctx.pvertices = *pvertices; - if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { - STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); - return output_ctx.num_vertices; - } - } - *pvertices = NULL; - return 0; -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - stbtt__csctx c = STBTT__CSCTX_INIT(1); - int r = stbtt__run_charstring(info, glyph_index, &c); - if (x0) { - *x0 = r ? c.min_x : 0; - *y0 = r ? c.min_y : 0; - *x1 = r ? c.max_x : 0; - *y1 = r ? c.max_y : 0; - } - return r ? c.num_vertices : 0; -} - -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - if (!info->cff.size) - return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); - else - return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); -} - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint8 *data = info->data + info->kern; - stbtt_uint32 needle, straw; - int l, r, m; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - l = 0; - r = ttUSHORT(data+10) - 1; - needle = glyph1 << 16 | glyph2; - while (l <= r) { - m = (l + r) >> 1; - straw = ttULONG(data+18+(m*6)); // note: unaligned read - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else - return ttSHORT(data+22+(m*6)); - } - return 0; -} - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs - return 0; - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); -} - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); -} - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); -} - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) -{ - *x0 = ttSHORT(info->data + info->head + 36); - *y0 = ttSHORT(info->data + info->head + 38); - *x1 = ttSHORT(info->data + info->head + 40); - *y1 = ttSHORT(info->data + info->head + 42); -} - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; -} - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) -{ - int unitsPerEm = ttUSHORT(info->data + info->head + 18); - return pixels / unitsPerEm; -} - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); -} - -////////////////////////////////////////////////////////////////////////////// -// -// antialiasing software rasterizer -// - -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - // e.g. space character - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - // move to integral bboxes (treating pixels as little squares, what pixels get touched)? - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); - } -} - -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); -} - -////////////////////////////////////////////////////////////////////////////// -// -// Rasterizer - -typedef struct stbtt__hheap_chunk -{ - struct stbtt__hheap_chunk *next; -} stbtt__hheap_chunk; - -typedef struct stbtt__hheap -{ - struct stbtt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; -} stbtt__hheap; - -static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); - if (c == NULL) - return NULL; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk; - } -} - -static void stbtt__hheap_free(stbtt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; -} - -static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) -{ - stbtt__hheap_chunk *c = hh->head; - while (c) { - stbtt__hheap_chunk *n = c->next; - STBTT_free(c, userdata); - c = n; - } -} - -typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; -} stbtt__edge; - - -typedef struct stbtt__active_edge -{ - struct stbtt__active_edge *next; - #if STBTT_RASTERIZER_VERSION==1 - int x,dx; - float ey; - int direction; - #elif STBTT_RASTERIZER_VERSION==2 - float fx,fdx,fdy; - float direction; - float sy; - float ey; - #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" - #endif -} stbtt__active_edge; - -#if STBTT_RASTERIZER_VERSION == 1 -#define STBTT_FIXSHIFT 10 -#define STBTT_FIX (1 << STBTT_FIXSHIFT) -#define STBTT_FIXMASK (STBTT_FIX-1) - -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - if (!z) return z; - - // round dx down to avoid overshooting - if (dxdy < 0) - z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); - else - z->dx = STBTT_ifloor(STBTT_FIX * dxdy); - - z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount - z->x -= off_x * STBTT_FIX; - - z->ey = e->y1; - z->next = 0; - z->direction = e->invert ? 1 : -1; - return z; -} -#elif STBTT_RASTERIZER_VERSION == 2 -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - //STBTT_assert(e->y0 <= start_point); - if (!z) return z; - z->fdx = dxdy; - z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; -} -#else -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - -#if STBTT_RASTERIZER_VERSION == 1 -// note: this routine clips fills that extend off the edges... ideally this -// wouldn't happen, but it could happen if the truetype glyph bounding boxes -// are wrong, or if the user supplies a too-small bitmap -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - // non-zero winding fill - int x0=0, w=0; - - while (e) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->direction; - } else { - int x1 = e->x; w += e->direction; - // if we went to zero, we need to draw - if (w == 0) { - int i = x0 >> STBTT_FIXSHIFT; - int j = x1 >> STBTT_FIXSHIFT; - - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } - } - } - } - - e = e->next; - } -} - -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); // weight per vertical scanline - int s; // vertical subsample index - unsigned char scanline_data[512], *scanline; - - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; - - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; - - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - // find center of pixel for this scanline - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); - if (z != NULL) { - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - } - ++e; - } - - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); - - ++y; - } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } - - stbtt__hheap_cleanup(&hh, userdata); - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} - -#elif STBTT_RASTERIZER_VERSION == 2 - -// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 -// (i.e. it has already been clipped to those) -static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - STBTT_assert(y0 < y1); - STBTT_assert(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } - - if (x0 == x) - STBTT_assert(x1 <= x+1); - else if (x0 == x+1) - STBTT_assert(x1 >= x); - else if (x0 <= x) - STBTT_assert(x1 <= x); - else if (x0 >= x+1) - STBTT_assert(x1 >= x+1); - else - STBTT_assert(x1 >= x && x1 <= x+1); - - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1) - ; - else { - STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position - } -} - -static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; - - while (e) { - // brute force every pixel - - // compute intersection points with top & bottom - STBTT_assert(e->ey >= y_top); - - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); - } else { - stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); - } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float sy0,sy1; - float dy = e->fdy; - STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); - - // compute endpoints of line segment clipped to this scanline (if the - // line segment starts on this scanline. x0 is the intersection of the - // line with y_top, but that may be off the line segment. - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - sy0 = e->sy; - } else { - x_top = x0; - sy0 = y_top; - } - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - sy1 = e->ey; - } else { - x_bottom = xb; - sy1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { - // from here on, we don't have to range check x values - - if ((int) x_top == (int) x_bottom) { - float height; - // simple case, only spans one pixel - int x = (int) x_top; - height = sy1 - sy0; - STBTT_assert(x >= 0 && x < len); - scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; - scanline_fill[x] += e->direction * height; // everything right of this pixel is filled - } else { - int x,x1,x2; - float y_crossing, step, sign, area; - // covers 2+ pixels - if (x_top > x_bottom) { - // flip scanline vertically; signed area is the same - float t; - sy0 = y_bottom - (sy0 - y_top); - sy1 = y_bottom - (sy1 - y_top); - t = sy0, sy0 = sy1, sy1 = t; - t = x_bottom, x_bottom = x_top, x_top = t; - // SOKOL FIXME: static analyzer fix 'Value stored to 'dx' is never read' - //dx = -dx; - dy = -dy; - // SOKOL FIXME: static analyzer fix 'Although the value stored to 'xb' is used in the enclosing expression, the value is never actually read from 'xb'' - /*t = x0,*/x0 = xb/*xb = t*/; - } - - x1 = (int) x_top; - x2 = (int) x_bottom; - // compute intersection with y axis at x1+1 - y_crossing = (x1+1 - x0) * dy + y_top; - - sign = e->direction; - // area of the rectangle covered from y0..y_crossing - area = sign * (y_crossing-sy0); - // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) - scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); - - step = sign * dy; - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; - area += step; - } - y_crossing += dy * (x2 - (x1+1)); - - STBTT_assert(STBTT_fabs(area) <= 1.01f); - - scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); - - scanline_fill[x2] += sign * (sy1-sy0); - } - } else { - // if edge goes outside of box we're drawing, we require - // clipping logic. since this does not match the intended use - // of this library, we use a different, very slow brute - // force implementation - int x; - for (x=0; x < len; ++x) { - // cases: - // - // there can be up to two intersections with the pixel. any intersection - // with left or right edges can be handled by splitting into two (or three) - // regions. intersections with top & bottom do not necessitate case-wise logic. - // - // the old way of doing this found the intersections with the left & right edges, - // then used some simple logic to produce up to three segments in sorted order - // from top-to-bottom. however, this had a problem: if an x edge was epsilon - // across the x border, then the corresponding y position might not be distinct - // from the other y segment, and it might ignored as an empty segment. to avoid - // that, we need to explicitly produce segments based on x positions. - - // rename variables to clearly-defined pairs - float y0 = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - - // x = e->x + e->dx * (y-y_top) - // (y-y_top) = (x - e->x) / e->dx - // y = (x - e->x) / e->dx + y_top - float y1 = (x - x0) / dx + y_top; - float y2 = (x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { // three segments descending down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { // three segments descending down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { // one segment - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); - } - } - } - } - e = e->next; - } -} - -// directly AA rasterize edges w/o supersampling -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; - - STBTT__NOTUSED(vsubsample); - - if (result->w > 64) - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); - else - scanline = scanline_data; - - scanline2 = scanline + result->w; - - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; - - while (j < result->h) { - // find center of pixel for this scanline - float scan_y_top = y + 0.0f; - float scan_y_bottom = y + 1.0f; - stbtt__active_edge **step = &active; - - STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); - STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); - - // update all active edges; - // remove all active edges that terminate before the top of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - step = &((*step)->next); // advance through list - } - } - - // insert all edges that start before the bottom of this scanline - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); - if (z != NULL) { - STBTT_assert(z->ey >= scan_y_top); - // insert at front - z->next = active; - active = z; - } - } - ++e; - } - - // now process all active edges - if (active) - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); - - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) STBTT_fabs(k)*255 + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - // advance all the edges - step = &active; - while (*step) { - stbtt__active_edge *z = *step; - z->fx += z->fdx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - - ++y; - ++j; - } - - stbtt__hheap_cleanup(&hh, userdata); - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} -#else -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - -#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) - -static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - stbtt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - stbtt__edge *b = &p[j-1]; - int c = STBTT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } -} - -static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) -{ - /* threshhold for transitioning to insertion sort */ - while (n > 12) { - stbtt__edge t; - int c01,c12,c,m,i,j; - - /* compute median of three */ - m = n >> 1; - c01 = STBTT__COMPARE(&p[0],&p[m]); - c12 = STBTT__COMPARE(&p[m],&p[n-1]); - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = STBTT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; - p[m] = t; - - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!STBTT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!STBTT__COMPARE(&p[0], &p[j])) break; - } - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; - - ++i; - --j; - } - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - stbtt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - stbtt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } -} - -static void stbtt__sort_edges(stbtt__edge *p, int n) -{ - stbtt__sort_edges_quicksort(p, n); - stbtt__sort_edges_ins_sort(p, n); -} - -typedef struct -{ - float x,y; -} stbtt__point; - -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; -#if STBTT_RASTERIZER_VERSION == 1 - int vsubsample = result->h < 8 ? 15 : 5; -#elif STBTT_RASTERIZER_VERSION == 2 - int vsubsample = 1; -#else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity - - // now we have to blow out the windings into explicit edge lists - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - // skip the edge if horizontal - if (p[j].y == p[k].y) - continue; - // add edge from j to k to the list - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; - ++n; - } - } - - // now sort the edges by their highest point (should snap to integer, and then by x) - //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); - stbtt__sort_edges(e, n); - - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); - - STBTT_free(e, userdata); -} - -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; // during first pass, it's unallocated - points[n].x = x; - points[n].y = y; -} - -// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - // midpoint - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - // versus directly drawn line - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) // 65536 segments on one curve better be enough! - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) -{ - // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough - float dx0 = x1-x0; - float dy0 = y1-y0; - float dx1 = x2-x1; - float dy1 = y2-y1; - float dx2 = x3-x2; - float dy2 = y3-y2; - float dx = x3-x0; - float dy = y3-y0; - float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); - float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); - float flatness_squared = longlen*longlen-shortlen*shortlen; - - if (n > 16) // 65536 segments on one curve better be enough! - return; - - if (flatness_squared > objspace_flatness_squared) { - float x01 = (x0+x1)/2; - float y01 = (y0+y1)/2; - float x12 = (x1+x2)/2; - float y12 = (y1+y2)/2; - float x23 = (x2+x3)/2; - float y23 = (y2+y3)/2; - - float xa = (x01+x12)/2; - float ya = (y01+y12)/2; - float xb = (x12+x23)/2; - float yb = (y12+y23)/2; - - float mx = (xa+xb)/2; - float my = (ya+yb)/2; - - stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x3,y3); - *num_points = *num_points+1; - } -} - -// returns number of contours -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; - - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; - - // count how many "moves" there are to get the contour count - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - // make two passes through the points so we don't need to realloc - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; - } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { - case STBTT_vmove: - // start the next contour - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; - case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; - case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - case STBTT_vcubic: - stbtt__tesselate_cubic(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].cx1, vertices[i].cy1, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } - - return points; -error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; -} - -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count, *winding_lengths; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } -} - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) { - STBTT_free(vertices, info->userdata); - return NULL; - } - scale_y = scale_x; - } - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); - - // now we get the size - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; // in case we error - - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; - - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); - - STBTT_free(vertices, info->userdata); -} - -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); -} - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-CRAPPY packing to keep source code small - -static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - f.userdata = NULL; - if (!stbtt_InitFont(&f, data, offset)) - return -1; - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - x=y=1; - bottom_y = 1; - - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; // advance to next row - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 1; - if (y+gh+1 > bottom_y) - bottom_y = y+gh+1; - } - return bottom_y; -} - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); - - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -////////////////////////////////////////////////////////////////////////////// -// -// rectangle packing replacement routines if you don't have stb_rect_pack.h -// - -#ifndef STB_RECT_PACK_VERSION - -typedef int stbrp_coord; - -//////////////////////////////////////////////////////////////////////////////////// -// // -// // -// COMPILER WARNING ?!?!? // -// // -// // -// if you get a compile warning due to these symbols being defined more than // -// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // -// // -//////////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - int width,height; - int x,y,bottom_y; -} stbrp_context; - -typedef struct -{ - unsigned char x; -} stbrp_node; - -struct stbrp_rect -{ - stbrp_coord x,y; - int id,w,h,was_packed; -}; - -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) -{ - con->width = pw; - con->height = ph; - con->x = 0; - con->y = 0; - con->bottom_y = 0; - STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); -} - -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) -{ - int i; - for (i=0; i < num_rects; ++i) { - if (con->x + rects[i].w > con->width) { - con->x = 0; - con->y = con->bottom_y; - } - if (con->y + rects[i].h > con->height) - break; - rects[i].x = con->x; - rects[i].y = con->y; - rects[i].was_packed = 1; - con->x += rects[i].w; - if (con->y + rects[i].h > con->bottom_y) - con->bottom_y = con->y + rects[i].h; - } - for ( ; i < num_rects; ++i) - rects[i].was_packed = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If -// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) -{ - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw - padding; - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); - - if (context == NULL || nodes == NULL) { - if (context != NULL) STBTT_free(context, alloc_context); - if (nodes != NULL) STBTT_free(nodes , alloc_context); - return 0; - } - - spc->user_allocator_context = alloc_context; - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - - if (pixels) - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - - return 1; -} - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) -{ - STBTT_free(spc->nodes , spc->user_allocator_context); - STBTT_free(spc->pack_info, spc->user_allocator_context); -} - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) -{ - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); - if (h_oversample <= STBTT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= STBTT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) - -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < h; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < w; ++i) { - STBTT_assert(pixels[i] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = (unsigned char) (total / kernel_width); - } - - pixels += stride_in_bytes; - } -} - -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < w; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < h; ++i) { - STBTT_assert(pixels[i*stride_in_bytes] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - - pixels += 1; - } -} - -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; - - // The prefilter is a box filter of width "oversample", - // which shifts phase by (oversample - 1)/2 pixels in - // oversampled space. We want to shift in the opposite - // direction to counter this. - return (float)-(oversample - 1) / (2.0f * (float)oversample); -} - -// rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k; - - k=0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - ++k; - } - } - - return k; -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, - output, - out_w - (prefilter_x - 1), - out_h - (prefilter_y - 1), - out_stride, - scale_x, - scale_y, - shift_x, - shift_y, - glyph); - - if (prefilter_x > 1) - stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); - - if (prefilter_y > 1) - stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); - - *sub_x = stbtt__oversample_shift(prefilter_x); - *sub_y = stbtt__oversample_shift(prefilter_y); -} - -// rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k, return_value = 1; - - // save current values - int old_h_over = spc->h_oversample; - int old_v_over = spc->v_oversample; - - k = 0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - float recip_h,recip_v,sub_x,sub_y; - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - recip_h = 1.0f / spc->h_oversample; - recip_v = 1.0f / spc->v_oversample; - sub_x = stbtt__oversample_shift(spc->h_oversample); - sub_y = stbtt__oversample_shift(spc->v_oversample); - for (j=0; j < ranges[i].num_chars; ++j) { - stbrp_rect *r = &rects[k]; - if (r->was_packed) { - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbrp_coord pad = (stbrp_coord) spc->padding; - - // pad on left and top - r->x += pad; - r->y += pad; - r->w -= pad; - r->h -= pad; - stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(info, glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - &x0,&y0,&x1,&y1); - stbtt_MakeGlyphBitmapSubpixel(info, - spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w - spc->h_oversample+1, - r->h - spc->v_oversample+1, - spc->stride_in_bytes, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - glyph); - - if (spc->h_oversample > 1) - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->h_oversample); - - if (spc->v_oversample > 1) - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->v_oversample); - - bc->x0 = (stbtt_int16) r->x; - bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w); - bc->y1 = (stbtt_int16) (r->y + r->h); - bc->xadvance = scale * advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; - } else { - return_value = 0; // if any fail, report failure - } - - ++k; - } - } - - // restore original values - spc->h_oversample = old_h_over; - spc->v_oversample = old_v_over; - - return return_value; -} - -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) -{ - stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); -} - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) -{ - stbtt_fontinfo info; - int i,j,n, return_value = 1; - //stbrp_context *context = (stbrp_context *) spc->pack_info; - stbrp_rect *rects; - - // flag all characters as NOT packed - for (i=0; i < num_ranges; ++i) - for (j=0; j < ranges[i].num_chars; ++j) - ranges[i].chardata_for_range[j].x0 = - ranges[i].chardata_for_range[j].y0 = - ranges[i].chardata_for_range[j].x1 = - ranges[i].chardata_for_range[j].y1 = 0; - - n = 0; - for (i=0; i < num_ranges; ++i) - n += ranges[i].num_chars; - - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); - if (rects == NULL) - return 0; - - info.userdata = spc->user_allocator_context; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); - - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); - - stbtt_PackFontRangesPackRects(spc, rects, n); - - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); - - STBTT_free(rects, spc->user_allocator_context); - return return_value; -} - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) -{ - stbtt_pack_range range; - range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; - range.array_of_unicode_codepoints = NULL; - range.num_chars = num_chars_in_range; - range.chardata_for_range = chardata_for_range; - range.font_size = font_size; - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); -} - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) -{ - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_packedchar *b = chardata + char_index; - - if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -////////////////////////////////////////////////////////////////////////////// -// -// sdf computation -// - -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) - -static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) -{ - float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; - float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; - float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; - float roperp = orig[1]*ray[0] - orig[0]*ray[1]; - - float a = q0perp - 2*q1perp + q2perp; - float b = q1perp - q0perp; - float c = q0perp - roperp; - - float s0 = 0., s1 = 0.; - int num_s = 0; - - if (a != 0.0) { - float discr = b*b - a*c; - if (discr > 0.0) { - float rcpna = -1 / a; - float d = (float) sqrt(discr); - s0 = (b+d) * rcpna; - s1 = (b-d) * rcpna; - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { - if (num_s == 0) s0 = s1; - ++num_s; - } - } - } else { - // 2*b*s + c = 0 - // s = -c / (2*b) - s0 = c / (-2 * b); - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - } - - if (num_s == 0) - return 0; - else { - float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); - float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; - - float q0d = q0[0]*rayn_x + q0[1]*rayn_y; - float q1d = q1[0]*rayn_x + q1[1]*rayn_y; - float q2d = q2[0]*rayn_x + q2[1]*rayn_y; - float rod = orig[0]*rayn_x + orig[1]*rayn_y; - - float q10d = q1d - q0d; - float q20d = q2d - q0d; - float q0rd = q0d - rod; - - hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; - hits[0][1] = a*s0+b; - - if (num_s > 1) { - hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; - hits[1][1] = a*s1+b; - return 2; - } else { - return 1; - } - } -} - -static int equal(float *a, float *b) -{ - return (a[0] == b[0] && a[1] == b[1]); -} - -static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) -{ - int i; - float orig[2], ray[2] = { 1, 0 }; - float y_frac; - int winding = 0; - - orig[0] = x; - orig[1] = y; - - // make sure y never passes through a vertex of the shape - y_frac = (float) fmod(y, 1.0f); - if (y_frac < 0.01f) - y += 0.01f; - else if (y_frac > 0.99f) - y -= 0.01f; - orig[1] = y; - - // test a ray from (-infinity,y) to (x,y) - for (i=0; i < nverts; ++i) { - if (verts[i].type == STBTT_vline) { - int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; - int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } - if (verts[i].type == STBTT_vcurve) { - int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; - int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; - int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; - int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); - int by = STBTT_max(y0,STBTT_max(y1,y2)); - if (y > ay && y < by && x > ax) { - float q0[2],q1[2],q2[2]; - float hits[2][2]; - q0[0] = (float)x0; - q0[1] = (float)y0; - q1[0] = (float)x1; - q1[1] = (float)y1; - q2[0] = (float)x2; - q2[1] = (float)y2; - if (equal(q0,q1) || equal(q1,q2)) { - x0 = (int)verts[i-1].x; - y0 = (int)verts[i-1].y; - x1 = (int)verts[i ].x; - y1 = (int)verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } else { - int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); - if (num_hits >= 1) - if (hits[0][0] < 0) - winding += (hits[0][1] < 0 ? -1 : 1); - if (num_hits >= 2) - if (hits[1][0] < 0) - winding += (hits[1][1] < 0 ? -1 : 1); - } - } - } - } - return winding; -} - -static float stbtt__cuberoot( float x ) -{ - if (x<0) - return -(float) STBTT_pow(-x,1.0f/3.0f); - else - return (float) STBTT_pow( x,1.0f/3.0f); -} - -// x^3 + c*x^2 + b*x + a = 0 -static int stbtt__solve_cubic(float a, float b, float c, float* r) -{ - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; - float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative - float m = (float) STBTT_cos(v); - float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); - - //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? - //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); - //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); - return 3; - } -} - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - float scale_x = scale, scale_y = scale; - int ix0,iy0,ix1,iy1; - int w,h; - unsigned char *data; - - // if one scale is 0, use same scale for both - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) return NULL; // if both scales are 0, return NULL - scale_y = scale_x; - } - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); - - // if empty, return NULL - if (ix0 == ix1 || iy0 == iy1) - return NULL; - - ix0 -= padding; - iy0 -= padding; - ix1 += padding; - iy1 += padding; - - w = (ix1 - ix0); - h = (iy1 - iy0); - - if (width ) *width = w; - if (height) *height = h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - // invert for y-downwards bitmaps - scale_y = -scale_y; - - { - int x,y,i,j; - float *precompute; - stbtt_vertex *verts; - int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); - data = (unsigned char *) STBTT_malloc(w * h, info->userdata); - precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); - - for (i=0,j=num_verts-1; i < num_verts; j=i++) { - if (verts[i].type == STBTT_vline) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; - float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); - precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; - float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; - float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float len2 = bx*bx + by*by; - if (len2 != 0.0f) - precompute[i] = 1.0f / (bx*bx + by*by); - else - precompute[i] = 0.0f; - } else - precompute[i] = 0.0f; - } - - for (y=iy0; y < iy1; ++y) { - for (x=ix0; x < ix1; ++x) { - float val; - float min_dist = 999999.0f; - float sx = (float) x + 0.5f; - float sy = (float) y + 0.5f; - float x_gspace = (sx / scale_x); - float y_gspace = (sy / scale_y); - - int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path - - for (i=0; i < num_verts; ++i) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - - // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve - float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - if (verts[i].type == STBTT_vline) { - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; - - // coarse culling against bbox - //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && - // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) - float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; - STBTT_assert(i != 0); - if (dist < min_dist) { - // check position along line - // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) - // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) - float dx = x1-x0, dy = y1-y0; - float px = x0-sx, py = y0-sy; - // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy - // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve - float t = -(px*dx + py*dy) / (dx*dx + dy*dy); - if (t >= 0.0f && t <= 1.0f) - min_dist = dist; - } - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; - float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; - float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); - float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); - float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); - float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); - // coarse culling against bbox to avoid computing cubic unnecessarily - if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { - int num=0; - float ax = x1-x0, ay = y1-y0; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float mx = x0 - sx, my = y0 - sy; - float res[3],px,py,t,it; - float a_inv = precompute[i]; - if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula - float a = 3*(ax*bx + ay*by); - float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); - float c = mx*ax+my*ay; - if (a == 0.0) { // if a is 0, it's linear - if (b != 0.0) { - res[num++] = -c/b; - } - } else { - float discriminant = b*b - 4*a*c; - if (discriminant < 0) - num = 0; - else { - float root = (float) STBTT_sqrt(discriminant); - res[0] = (-b - root)/(2*a); - res[1] = (-b + root)/(2*a); - num = 2; // don't bother distinguishing 1-solution case, as code below will still work - } - } - } else { - float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point - float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; - float d = (mx*ax+my*ay) * a_inv; - num = stbtt__solve_cubic(b, c, d, res); - } - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { - t = res[0], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { - t = res[1], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { - t = res[2], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - } - } - } - if (winding == 0) - min_dist = -min_dist; // if outside the shape, value is negative - val = onedge_value + pixel_dist_scale * min_dist; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; - } - } - STBTT_free(precompute, info->userdata); - STBTT_free(verts, info->userdata); - } - return data; -} - -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -////////////////////////////////////////////////////////////////////////////// -// -// font name matching -- recommended not to use this -// - -// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; - - // convert utf16 to utf8 and compare the results while converting - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; // plus another 2 below - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; - len2 -= 2; - } - return i; -} - -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); -} - -// returns results in whatever encoding you request... but note that 2-byte encodings -// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; - - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; -} - -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); - - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - // find the encoding - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); - - // is this a Unicode encoding? - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8); - stbtt_int32 off = ttUSHORT(fc+loc+10); - - // check if there's a prefix match - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - // check for target_id+1 immediately following, with same encoding & language - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - slen = ttUSHORT(fc+loc+12+8); - off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - // if nothing immediately following - if (matchlen == nlen) - return 1; - } - } - } - - // @TODO handle other encodings - } - } - return 0; -} - -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; - - // check italics/bold/underline flags in macStyle... - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } - - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; - - if (flags) { - // if we checked the macStyle flags, then just check the family and ignore the subfamily - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } - - return 0; -} - -static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, - float pixel_height, unsigned char *pixels, int pw, int ph, - int first_char, int num_chars, stbtt_bakedchar *chardata) -{ - return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); -} - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) -{ - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); -} - -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) -{ - return stbtt_GetNumberOfFonts_internal((unsigned char *) data); -} - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) -{ - return stbtt_InitFont_internal(info, (unsigned char *) data, offset); -} - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) -{ - return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); -} - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#endif // STB_TRUETYPE_IMPLEMENTATION - - -// FULL VERSION HISTORY -// -// 1.16 (2017-07-12) SDF support -// 1.15 (2017-03-03) make more arguments const -// 1.14 (2017-01-16) num-fonts-in-TTC function -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual -// 1.11 (2016-04-02) fix unused-variable warning -// 1.10 (2016-04-02) allow user-defined fabs() replacement -// fix memory leak if fontsize=0.0 -// fix warning from duplicate typedef -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; -// allow PackFontRanges to pack and render in separate phases; -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); -// fixed an assert() bug in the new rasterizer -// replace assert() with STBTT_assert() in new rasterizer -// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) -// also more precise AA rasterizer, except if shapes overlap -// remove need for STBTT_sort -// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC -// 1.04 (2015-04-15) typo in example -// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes -// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ -// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match -// non-oversampled; STBTT_POINT_SIZE for packed case only -// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling -// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) -// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID -// 0.8b (2014-07-07) fix a warning -// 0.8 (2014-05-25) fix a few more warnings -// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back -// 0.6c (2012-07-24) improve documentation -// 0.6b (2012-07-20) fix a few more warnings -// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, -// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty -// 0.5 (2011-12-09) bugfixes: -// subpixel glyph renderer computed wrong bounding box -// first vertex of shape can be off-curve (FreeSans) -// 0.4b (2011-12-03) fixed an error in the font baking example -// 0.4 (2011-12-01) kerning, subpixel rendering (tor) -// bugfixes for: -// codepoint-to-glyph conversion using table fmt=12 -// codepoint-to-glyph conversion using table fmt=4 -// stbtt_GetBakedQuad with non-square texture (Zer) -// updated Hello World! sample to use kerning and subpixel -// fixed some warnings -// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) -// userdata, malloc-from-userdata, non-zero fill (stb) -// 0.2 (2009-03-11) Fix unsigned/signed char warnings -// 0.1 (2009-03-09) First public release -// - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ diff --git a/source/engine/thirdparty/sokol/tests/functional/CMakeLists.txt b/source/engine/thirdparty/sokol/tests/functional/CMakeLists.txt deleted file mode 100644 index 9a73c08..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -if (NOT ANDROID) - -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/assets/comsi.s3m DESTINATION ${CMAKE_BINARY_DIR}) -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/assets/comsi.s3m DESTINATION ${CMAKE_BINARY_DIR}/Debug) - -set(c_sources - sokol_log_test.c - sokol_args_test.c - sokol_audio_test.c - sokol_debugtext_test.c - sokol_fetch_test.c - sokol_gfx_test.c - sokol_gl_test.c - sokol_shape_test.c - sokol_color_test.c - sokol_spine_test.c - sokol_test.c -) -add_executable(sokol-test ${c_sources}) -target_link_libraries(sokol-test PUBLIC spine) -configure_c(sokol-test) - -endif() diff --git a/source/engine/thirdparty/sokol/tests/functional/README.txt b/source/engine/thirdparty/sokol/tests/functional/README.txt deleted file mode 100644 index 28fd594..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/README.txt +++ /dev/null @@ -1 +0,0 @@ -Test the public API behaviour with dummy backends. diff --git a/source/engine/thirdparty/sokol/tests/functional/assets/comsi.s3m b/source/engine/thirdparty/sokol/tests/functional/assets/comsi.s3m deleted file mode 100644 index a33c90a..0000000 Binary files a/source/engine/thirdparty/sokol/tests/functional/assets/comsi.s3m and /dev/null differ diff --git a/source/engine/thirdparty/sokol/tests/functional/assets/readme.txt b/source/engine/thirdparty/sokol/tests/functional/assets/readme.txt deleted file mode 100644 index 568e95c..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/assets/readme.txt +++ /dev/null @@ -1,3 +0,0 @@ -Spine examples taken from: - -https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/examples diff --git a/source/engine/thirdparty/sokol/tests/functional/force_dummy_backend.h b/source/engine/thirdparty/sokol/tests/functional/force_dummy_backend.h deleted file mode 100644 index 22390e7..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/force_dummy_backend.h +++ /dev/null @@ -1,18 +0,0 @@ -#if defined(SOKOL_GLES3) -#undef SOKOL_GLES3 -#endif -#if defined(SOKOL_GLCORE33) -#undef SOKOL_GLCORE33 -#endif -#if defined(SOKOL_METAL) -#undef SOKOL_METAL -#endif -#if defined(SOKOL_D3D11) -#undef SOKOL_D3D11 -#endif -#if defined(SOKOL_WGPU) -#undef SOKOL_WGPU -#endif -#ifndef SOKOL_DUMMY_BACKEND -#define SOKOL_DUMMY_BACKEND -#endif diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_args_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_args_test.c deleted file mode 100644 index e2928d1..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_args_test.c +++ /dev/null @@ -1,302 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-args-test.c -//------------------------------------------------------------------------------ -#define SOKOL_IMPL -#include "sokol_args.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) -#define TSTR(s0, s1) EXPECT_TRUE(0 == strcmp(s0,s1)) -#define NUM_ARGS(x) (sizeof(x)/sizeof(void*)) - -static char* argv_0[] = { "exe_name " }; -UTEST(sokol_args, init_shutdown) { - sargs_setup(&(sargs_desc){0}); - T(sargs_isvalid()); - T(_sargs.max_args == _SARGS_MAX_ARGS_DEF); - T(_sargs.args); - T(_sargs.buf_size == _SARGS_BUF_SIZE_DEF); - T(_sargs.buf_pos == 1); - T(_sargs.buf); - T(sargs_num_args() == 0); - TSTR(sargs_key_at(0), ""); - TSTR(sargs_value_at(0), ""); - sargs_shutdown(); - T(!sargs_isvalid()); - T(0 == _sargs.args); - T(0 == _sargs.buf); -} - -UTEST(sokol_args, no_args) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_0), - .argv = argv_0 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 0); - TSTR(sargs_key_at(0), ""); - TSTR(sargs_value_at(0), ""); - T(-1 == sargs_find("bla")); - T(!sargs_exists("bla")); - TSTR(sargs_value("bla"), ""); - TSTR(sargs_value_def("bla", "blub"), "blub"); - sargs_shutdown(); -} - -static char* argv_1[] = { "exe_name", "kvp0=val0", "kvp1=val1", "kvp2=val2" }; -UTEST(sokol_args, simple_args) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_1), - .argv = argv_1, - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "val0"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "val0"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), "val1"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), "val1"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "val2"); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "val2"); - T(_sargs.buf_pos == 31); - sargs_shutdown(); -} - -static char* argv_2[] = { "exe_name", "kvp0 = val0 ", " \tkvp1= val1", "kvp2 = val2 "}; -UTEST(sokol_args, simple_whitespace) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_2), - .argv = argv_2 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "val0"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "val0"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), "val1"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), "val1"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "val2"); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "val2"); - T(_sargs.buf_pos == 31); - sargs_shutdown(); -} - -static char* argv_4[] = { "exe_name", "kvp0 ", "=val0 ", " kvp1", "=", "val1", "kvp2 \t", "= val2 "}; -UTEST(sokol_args, standalone_separator) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_4), - .argv = argv_4 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "val0"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "val0"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), "val1"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), "val1"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "val2"); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "val2"); - T(_sargs.buf_pos == 31); - sargs_shutdown(); -} - -static char* argv_5[] = { "exe_name", "kvp0='bla bla'", "kvp1=' blub blub'", "kvp2='blob blob '"}; -UTEST(sokol_args, single_quotes) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_5), - .argv = argv_5 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "bla bla"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "bla bla"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), " blub blub"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), " blub blub"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "blob blob "); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "blob blob "); - sargs_shutdown(); -} - -static char* argv_6[] = { "exe_name", "kvp0=\"bla bla\"", "kvp1=\" blub blub\"", "kvp2=\"blob blob \""}; -UTEST(sokol_args, double_quotes) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_6), - .argv = argv_6 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "bla bla"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "bla bla"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), " blub blub"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), " blub blub"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "blob blob "); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "blob blob "); - sargs_shutdown(); -} - -static char* argv_7[] = { "exe_name", "kvp0='bla \"bla\"'", "kvp1=' \"blub blub\"'", "kvp2='blob \"blob\" '"}; -UTEST(sokol_args, double_in_single_quotes) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_7), - .argv = argv_7 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "bla \"bla\""); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "bla \"bla\""); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), " \"blub blub\""); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), " \"blub blub\""); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "blob \"blob\" "); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "blob \"blob\" "); - sargs_shutdown(); -} - -static char* argv_8[] = { "exe_name", "kvp0=\"bla 'bla'\"", "kvp1=\" 'blub blub'\"", "kvp2=\"blob 'blob' \""}; -UTEST(sokol_args, single_in_double_quotes) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_8), - .argv = argv_8 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "bla 'bla'"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "bla 'bla'"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), " 'blub blub'"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), " 'blub blub'"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "blob 'blob' "); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "blob 'blob' "); - sargs_shutdown(); -} - -static char* argv_9[] = { "exe_name", "kvp0='bla ", "bla'", "kvp1= ' blub", " blub'", "kvp2='blob blob '"}; -UTEST(sokol_args, test_split_quotes) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_9), - .argv = argv_9 - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "bla bla"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "bla bla"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), " blub blub"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), " blub blub"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "blob blob "); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "blob blob "); - sargs_shutdown(); -} - -static char* argv_10[] = { "exe_name", "kvp0=\\\\val0\\nval1", "kvp1=val1\\rval2", "kvp2='val2\\tval3'" }; -UTEST(sokol_args, escape_sequence) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_10), - .argv = argv_10, - }); - T(sargs_isvalid()); - T(sargs_num_args() == 3); - T(0 == sargs_find("kvp0")); - TSTR(sargs_value("kvp0"), "\\val0\nval1"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_value_at(0), "\\val0\nval1"); - T(1 == sargs_find("kvp1")); - TSTR(sargs_value("kvp1"), "val1\rval2"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_value_at(1), "val1\rval2"); - T(2 == sargs_find("kvp2")); - TSTR(sargs_value("kvp2"), "val2\tval3"); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_value_at(2), "val2\tval3"); - sargs_shutdown(); -} - -static char* argv_11[] = { "exe_name", "kvp0 kvp1", "kvp2 = val2", "kvp3", "kvp4=val4" }; -UTEST(sokol_args, key_only_args) { - sargs_setup(&(sargs_desc){ - .argc = NUM_ARGS(argv_11), - .argv = argv_11, - }); - T(sargs_isvalid()); - T(sargs_num_args() == 5); - T(0 == sargs_find("kvp0")); - T(1 == sargs_find("kvp1")); - T(2 == sargs_find("kvp2")); - T(3 == sargs_find("kvp3")); - T(4 == sargs_find("kvp4")) - T(-1 == sargs_find("kvp5")); - T(-1 == sargs_find("val2")); - T(-1 == sargs_find("val4")); - T(sargs_exists("kvp0")); - T(sargs_exists("kvp1")); - T(sargs_exists("kvp2")); - T(sargs_exists("kvp3")); - T(sargs_exists("kvp4")); - T(!sargs_exists("kvp5")); - TSTR(sargs_value("kvp0"), ""); - TSTR(sargs_value("kvp1"), ""); - TSTR(sargs_value("kvp2"), "val2"); - TSTR(sargs_value("kvp3"), ""); - TSTR(sargs_value("kvp4"), "val4"); - TSTR(sargs_value("kvp5"), ""); - TSTR(sargs_value_def("kvp0", "bla0"), "bla0"); - TSTR(sargs_value_def("kvp1", "bla1"), "bla1"); - TSTR(sargs_value_def("kvp2", "bla2"), "val2"); - TSTR(sargs_value_def("kvp3", "bla3"), "bla3"); - TSTR(sargs_value_def("kvp4", "bla4"), "val4"); - TSTR(sargs_value_def("kvp5", "bla5"), "bla5"); - TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_key_at(1), "kvp1"); - TSTR(sargs_key_at(2), "kvp2"); - TSTR(sargs_key_at(3), "kvp3"); - TSTR(sargs_key_at(4), "kvp4"); - TSTR(sargs_key_at(5), ""); - TSTR(sargs_value_at(0), ""); - TSTR(sargs_value_at(1), ""); - TSTR(sargs_value_at(2), "val2"); - TSTR(sargs_value_at(3), ""); - TSTR(sargs_value_at(4), "val4"); - TSTR(sargs_value_at(5), ""); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_audio_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_audio_test.c deleted file mode 100644 index a607d29..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_audio_test.c +++ /dev/null @@ -1,99 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol_audio_test.c -//------------------------------------------------------------------------------ -#define SOKOL_IMPL -#ifndef SOKOL_DUMMY_BACKEND -#define SOKOL_DUMMY_BACKEND -#endif -#include "sokol_audio.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) - -UTEST(sokol_audio, ring_buffer) { - _saudio_ring_t rb; - _saudio_ring_init(&rb, 4); - T(0 == rb.head); - T(0 == rb.tail); - T(5 == rb.num); - T(!_saudio_ring_full(&rb)); - T(_saudio_ring_empty(&rb)); - T(0 == _saudio_ring_count(&rb)); - - _saudio_ring_enqueue(&rb, 23); - T(1 == rb.head); - T(0 == rb.tail); - T(!_saudio_ring_full(&rb)); - T(!_saudio_ring_empty(&rb)); - T(1 == _saudio_ring_count(&rb)); - - T(23 == _saudio_ring_dequeue(&rb)); - T(1 == rb.head); - T(1 == rb.tail); - T(!_saudio_ring_full(&rb)); - T(_saudio_ring_empty(&rb)); - T(0 == _saudio_ring_count(&rb)); - - _saudio_ring_enqueue(&rb, 23); - _saudio_ring_enqueue(&rb, 46); - T(3 == rb.head); - T(1 == rb.tail); - T(!_saudio_ring_full(&rb)); - T(!_saudio_ring_empty(&rb)); - T(2 == _saudio_ring_count(&rb)); - T(23 == _saudio_ring_dequeue(&rb)); - T(46 == _saudio_ring_dequeue(&rb)); - T(3 == rb.head); - T(3 == rb.tail); - T(!_saudio_ring_full(&rb)); - T(_saudio_ring_empty(&rb)); - T(0 == _saudio_ring_count(&rb)); - - _saudio_ring_enqueue(&rb, 12); - _saudio_ring_enqueue(&rb, 34); - _saudio_ring_enqueue(&rb, 56); - _saudio_ring_enqueue(&rb, 78); - T(2 == rb.head); - T(3 == rb.tail); - T(_saudio_ring_full(&rb)); - T(!_saudio_ring_empty(&rb)); - T(4 == _saudio_ring_count(&rb)); - T(12 == _saudio_ring_dequeue(&rb)); - T(2 == rb.head); - T(4 == rb.tail); - T(!_saudio_ring_full(&rb)); - T(!_saudio_ring_empty(&rb)); - T(3 == _saudio_ring_count(&rb)); - _saudio_ring_enqueue(&rb, 90); - T(3 == rb.head); - T(4 == rb.tail); - T(_saudio_ring_full(&rb)); - T(!_saudio_ring_empty(&rb)); - T(4 == _saudio_ring_count(&rb)); - T(34 == _saudio_ring_dequeue(&rb)); - T(56 == _saudio_ring_dequeue(&rb)); - T(78 == _saudio_ring_dequeue(&rb)); - T(90 == _saudio_ring_dequeue(&rb)); - T(!_saudio_ring_full(&rb)); - T(_saudio_ring_empty(&rb)); - T(3 == rb.head); - T(3 == rb.tail); -} - -UTEST(saudio, api_test) { - saudio_setup(&(saudio_desc){ - .sample_rate = 22050, - .num_channels = 2, - .buffer_frames = 8192, - .num_packets = 128, - .packet_frames = 8192 / 128, - .user_data = (void*)12345 - }); - T(saudio_isvalid()); - T(saudio_query_desc().sample_rate == 22050); - T(saudio_userdata() == (void*)12345); - T(saudio_sample_rate() == 22050); - T(saudio_channels() == 2); - T(saudio_expect() == 8192); - T(saudio_buffer_frames() == 8192); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_color_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_color_test.c deleted file mode 100644 index c3c1345..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_color_test.c +++ /dev/null @@ -1,70 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol_color_test.c -//------------------------------------------------------------------------------ -#include "sokol_gfx.h" -#define SOKOL_COLOR_IMPL -#include "sokol_color.h" -#include "utest.h" -#include - -#define T(b) EXPECT_TRUE(b) -#define TFLT(f0,f1,epsilon) {T(fabs((f0)-(f1))<=(epsilon));} - -UTEST(sokol_color, make_color) { - const sg_color c0 = sg_make_color_4b(255, 127, 0, 255); - TFLT(c0.r, 1.0f, 0.01f); - TFLT(c0.g, 0.5f, 0.01f); - TFLT(c0.b, 0.0f, 0.01f); - TFLT(c0.a, 1.0f, 0.01f); - const sg_color c1 = sg_make_color_1i(SG_BLACK_RGBA32); - TFLT(c1.r, 0.0f, 0.01f); - TFLT(c1.g, 0.0f, 0.01f); - TFLT(c1.b, 0.0f, 0.01f); - TFLT(c1.a, 1.0f, 0.01f); - const sg_color c2 = sg_make_color_1i(SG_GREEN_RGBA32); - TFLT(c2.r, 0.0f, 0.01f); - TFLT(c2.g, 1.0f, 0.01f); - TFLT(c2.b, 0.0f, 0.01f); - TFLT(c2.a, 1.0f, 0.01f); - const sg_color c3 = sg_make_color_1i(SG_RED_RGBA32); - TFLT(c3.r, 1.0f, 0.01f); - TFLT(c3.g, 0.0f, 0.01f); - TFLT(c3.b, 0.0f, 0.01f); - TFLT(c3.a, 1.0f, 0.01f); - const sg_color c4 = sg_make_color_1i(SG_BLUE_RGBA32); - TFLT(c4.r, 0.0f, 0.01f); - TFLT(c4.g, 0.0f, 0.01f); - TFLT(c4.b, 1.0f, 0.01f); - TFLT(c4.a, 1.0f, 0.01f); -} - -UTEST(sokol_color, lerp) { - const sg_color c0 = sg_color_lerp(&sg_red, &sg_green, 0.5f); - TFLT(c0.r, 0.5f, 0.001f); - TFLT(c0.g, 0.5f, 0.001f); - TFLT(c0.b, 0.0f, 0.001f); - TFLT(c0.a, 1.0f, 0.001f); - const sg_color c1 = sg_color_lerp_precise(&sg_red, &sg_green, 0.5f); - TFLT(c1.r, 0.5f, 0.001f); - TFLT(c1.g, 0.5f, 0.001f); - TFLT(c1.b, 0.0f, 0.001f); - TFLT(c1.a, 1.0f, 0.001f); -} - -UTEST(sokol_color, multiply) { - const sg_color c0 = sg_color_multiply(&sg_red, 0.5f); - TFLT(c0.r, 0.5f, 0.001f); - TFLT(c0.g, 0.0f, 0.001f); - TFLT(c0.b, 0.0f, 0.001f); - TFLT(c0.a, 0.5f, 0.001f); - const sg_color c1 = sg_color_multiply(&sg_green, 0.5f); - TFLT(c1.r, 0.0f, 0.001f); - TFLT(c1.g, 0.5f, 0.001f); - TFLT(c1.b, 0.0f, 0.001f); - TFLT(c1.a, 0.5f, 0.001f); - const sg_color c2 = sg_color_multiply(&sg_blue, 0.5f); - TFLT(c2.r, 0.0f, 0.001f); - TFLT(c2.g, 0.0f, 0.001f); - TFLT(c2.b, 0.5f, 0.001f); - TFLT(c2.a, 0.5f, 0.001f); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_debugtext_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_debugtext_test.c deleted file mode 100644 index 205fd53..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_debugtext_test.c +++ /dev/null @@ -1,520 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-debugtext-test.c -// For best results, run with ASAN and UBSAN. -//------------------------------------------------------------------------------ -#include "sokol_gfx.h" -#include "sokol_log.h" -#define SOKOL_DEBUGTEXT_IMPL -#include "sokol_debugtext.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) -#define TFLT(f0,f1) {T(fabs((f0)-(f1))<=(0.000001));} - -static void init(void) { - sg_setup(&(sg_desc){ .logger = { .func = slog_func }}); - sdtx_setup(&(sdtx_desc_t){ .logger = { .func = slog_func }}); -} - -static void init_with(const sdtx_desc_t* desc) { - sg_setup(&(sg_desc){0}); - sdtx_setup(desc); -} - -static void shutdown(void) { - sdtx_shutdown(); - sg_shutdown(); -} - -UTEST(sokol_debugtext, default_init_shutdown) { - init(); - T(_sdtx.init_cookie == _SDTX_INIT_COOKIE); - T(_sdtx.desc.context_pool_size == _SDTX_DEFAULT_CONTEXT_POOL_SIZE); - T(_sdtx.desc.printf_buf_size == _SDTX_DEFAULT_PRINTF_BUF_SIZE); - T(_sdtx.desc.context.char_buf_size == _SDTX_DEFAULT_CHAR_BUF_SIZE); - T(_sdtx.desc.context.canvas_width == _SDTX_DEFAULT_CANVAS_WIDTH); - T(_sdtx.desc.context.canvas_height == _SDTX_DEFAULT_CANVAS_HEIGHT); - T(_sdtx.desc.context.tab_width == _SDTX_DEFAULT_TAB_WIDTH); - T(_sdtx.desc.context.color_format == 0); - T(_sdtx.desc.context.depth_format == 0); - T(_sdtx.desc.context.sample_count == 0); - for (int i = 0; i < SDTX_MAX_FONTS; i++) { - T(_sdtx.desc.fonts[i].data.ptr == 0); - T(_sdtx.desc.fonts[i].data.size == 0); - T(_sdtx.desc.fonts[i].first_char == 0); - T(_sdtx.desc.fonts[i].last_char == 0); - } - T(_sdtx.font_img.id != SG_INVALID_ID); - T(_sdtx.shader.id != SG_INVALID_ID); - T(_sdtx.fmt_buf_size == (_SDTX_DEFAULT_CHAR_BUF_SIZE + 1)); - T(_sdtx.fmt_buf); - T(_sdtx.def_ctx_id.id != 0); - T(_sdtx.def_ctx_id.id == _sdtx.cur_ctx_id.id); - T(_sdtx.cur_ctx == _sdtx_lookup_context(_sdtx.cur_ctx_id.id)); - T(_sdtx.cur_ctx->desc.char_buf_size == _sdtx.desc.context.char_buf_size); - T(_sdtx.cur_ctx->desc.canvas_width == _sdtx.desc.context.canvas_width); - T(_sdtx.cur_ctx->desc.canvas_height == _sdtx.desc.context.canvas_height); - T(_sdtx.cur_ctx->desc.tab_width == _sdtx.desc.context.tab_width); - T(_sdtx.cur_ctx->desc.color_format == 0); - T(_sdtx.cur_ctx->desc.depth_format == 0); - T(_sdtx.cur_ctx->desc.sample_count == 0); - T(_sdtx.cur_ctx->vertices.cap == _SDTX_DEFAULT_CHAR_BUF_SIZE * 6); - T(_sdtx.cur_ctx->vertices.next == 0); - T(_sdtx.cur_ctx->vertices.ptr); - T(_sdtx.cur_ctx->commands.cap == _SDTX_DEFAULT_MAX_COMMANDS); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr); - T(_sdtx.cur_ctx->vbuf.id != 0); - T(_sdtx.cur_ctx->pip.id != 0); - TFLT(_sdtx.cur_ctx->canvas_size.x, 640.0f); - TFLT(_sdtx.cur_ctx->canvas_size.y, 480.0f); - TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 640.0f); - TFLT(_sdtx.cur_ctx->glyph_size.y, 8.0f / 480.0f); - TFLT(_sdtx.cur_ctx->origin.x, 0.0f); - TFLT(_sdtx.cur_ctx->origin.y, 0.0f); - TFLT(_sdtx.cur_ctx->pos.x, 0.0f); - TFLT(_sdtx.cur_ctx->pos.y, 0.0f); - TFLT(_sdtx.cur_ctx->tab_width, 4.0f); - T(_sdtx.cur_ctx->color == _SDTX_DEFAULT_COLOR); - T(_sdtx.context_pool.contexts); - T(_sdtx.context_pool.pool.size == (_SDTX_DEFAULT_CONTEXT_POOL_SIZE + 1)); - shutdown(); - T(_sdtx.init_cookie == 0); -} - -UTEST(sokol_debugtext, init_with_params) { - init_with(&(sdtx_desc_t){ - .context_pool_size = 2, - .printf_buf_size = 128, - .context = { - .char_buf_size = 256, - .canvas_width = 320, - .canvas_height = 200, - .tab_width = 8, - .color_format = SG_PIXELFORMAT_RGBA8, - .depth_format = SG_PIXELFORMAT_DEPTH_STENCIL, - .sample_count = 4, - } - }); - T(_sdtx.init_cookie == _SDTX_INIT_COOKIE); - T(_sdtx.desc.context_pool_size == 2); - T(_sdtx.desc.printf_buf_size == 128); - T(_sdtx.desc.context.char_buf_size == 256); - T(_sdtx.desc.context.canvas_width == 320); - T(_sdtx.desc.context.canvas_height == 200); - T(_sdtx.desc.context.tab_width == 8); - T(_sdtx.desc.context.color_format == SG_PIXELFORMAT_RGBA8); - T(_sdtx.desc.context.depth_format == SG_PIXELFORMAT_DEPTH_STENCIL); - T(_sdtx.desc.context.sample_count == 4); - T(_sdtx.fmt_buf_size == 129); - T(_sdtx.cur_ctx->desc.char_buf_size == _sdtx.desc.context.char_buf_size); - T(_sdtx.cur_ctx->desc.canvas_width == _sdtx.desc.context.canvas_width); - T(_sdtx.cur_ctx->desc.canvas_height == _sdtx.desc.context.canvas_height); - T(_sdtx.cur_ctx->desc.tab_width == _sdtx.desc.context.tab_width); - T(_sdtx.cur_ctx->desc.color_format == SG_PIXELFORMAT_RGBA8); - T(_sdtx.cur_ctx->desc.depth_format == SG_PIXELFORMAT_DEPTH_STENCIL); - T(_sdtx.cur_ctx->desc.sample_count == 4); - T(_sdtx.cur_ctx->vertices.cap == (256 * 6)); - TFLT(_sdtx.cur_ctx->canvas_size.x, 320.0f); - TFLT(_sdtx.cur_ctx->canvas_size.y, 200.0f); - TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 320.0f); - TFLT(_sdtx.cur_ctx->glyph_size.y, 8.0f / 200.0f); - TFLT(_sdtx.cur_ctx->tab_width, 8.0f); - T(_sdtx.context_pool.pool.size == 3); - shutdown(); -} - -UTEST(sokol_debugtext, make_destroy_context) { - init(); - sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ - .char_buf_size = 64, - .canvas_width = 1024, - .canvas_height = 768, - .tab_width = 3, - .color_format = SG_PIXELFORMAT_RGBA32F, - .sample_count = 2 - }); - T(ctx_id.id != 0); - T(ctx_id.id != _sdtx.cur_ctx_id.id); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - T(ctx); - T(ctx != _sdtx.cur_ctx); - T(ctx->desc.char_buf_size == 64); - T(ctx->desc.canvas_width == 1024); - T(ctx->desc.canvas_height == 768); - T(ctx->desc.tab_width == 3); - T(ctx->desc.color_format == SG_PIXELFORMAT_RGBA32F); - T(ctx->desc.depth_format == 0); - T(ctx->desc.sample_count == 2); - T(ctx->vertices.ptr); - T(ctx->vertices.next == 0); - T(ctx->vertices.cap == (64 * 6)); - TFLT(ctx->canvas_size.x, 1024.0f); - TFLT(ctx->canvas_size.y, 768.0f); - TFLT(ctx->glyph_size.x, 8.0f / 1024.0f); - TFLT(ctx->glyph_size.y, 8.0f / 768.0f); - TFLT(ctx->tab_width, 3.0f); - sdtx_destroy_context(ctx_id); - T(0 == _sdtx_lookup_context(ctx_id.id)); - T(ctx->desc.char_buf_size == 0); - T(ctx->vertices.ptr == 0); - shutdown(); -} - -UTEST(sokol_debugtext, get_default_context) { - // getting the default context must always return SDTX_DEFAULT_CONTEXT - init(); - T(sdtx_get_context().id == SDTX_DEFAULT_CONTEXT.id); - shutdown(); -} - -UTEST(sokol_debugtext, set_get_context) { - init(); - sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ 0 }); - T(ctx_id.id != 0); - T(ctx_id.id != _sdtx.cur_ctx_id.id); - sdtx_set_context(ctx_id); - T(sdtx_get_context().id == ctx_id.id); - T(ctx_id.id == _sdtx.cur_ctx_id.id); - const _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - T(ctx == _sdtx.cur_ctx); - sdtx_set_context(SDTX_DEFAULT_CONTEXT); - T(sdtx_get_context().id == SDTX_DEFAULT_CONTEXT.id); - T(_sdtx.cur_ctx); - T(ctx != _sdtx.cur_ctx); - T(_sdtx.cur_ctx == _sdtx_lookup_context(_sdtx.def_ctx_id.id)); - shutdown(); -} - -UTEST(sokol_debugtext, destroy_default_context) { - // destroying the default context is not allowed - init(); - sdtx_context def_ctx_id = _sdtx.def_ctx_id; - T(def_ctx_id.id == _sdtx.cur_ctx_id.id); - sdtx_destroy_context(def_ctx_id); - T(def_ctx_id.id == _sdtx.def_ctx_id.id); - T(def_ctx_id.id == _sdtx.cur_ctx_id.id); - T(_sdtx.cur_ctx); - shutdown(); -} - -UTEST(sokol_debugtext, destroy_current_context) { - // destroying the current context has the same effect - // as setting a current context with an invalid context handle - init(); - sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ 0 }); - sdtx_set_context(ctx_id); - T(sdtx_get_context().id == ctx_id.id); - T(ctx_id.id == _sdtx.cur_ctx_id.id); - T(_sdtx_lookup_context(ctx_id.id) == _sdtx.cur_ctx); - sdtx_destroy_context(ctx_id); - T(_sdtx.cur_ctx_id.id == ctx_id.id); - T(_sdtx.cur_ctx == 0); - T(sdtx_get_context().id == ctx_id.id); - shutdown(); -} - -UTEST(sokol_debugtext, ignore_invalid_context_handle) { - // trying to render with an invalid context handle must not crash, - // instead ignore all operations - init(); - sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ 0 }); - sdtx_set_context(ctx_id); - sdtx_destroy_context(ctx_id); - T(0 == _sdtx.cur_ctx); - T(sdtx_get_context().id == ctx_id.id); - sdtx_font(0); - sdtx_canvas(100.0f, 200.0f); - sdtx_origin(10.0f, 10.0f); - sdtx_home(); - sdtx_pos(1.0f, 2.0f); - sdtx_pos_x(1.0f); - sdtx_pos_y(2.0f); - sdtx_move(2.0f, 3.0f); - sdtx_move_x(2.0f); - sdtx_move_y(3.0f); - sdtx_crlf(); - sdtx_color3b(255, 255, 255); - sdtx_color3f(1.0f, 1.0f, 1.0f); - sdtx_color4b(255, 255, 255, 255); - sdtx_color4f(1.0f, 1.0f, 1.0f, 1.0f); - sdtx_color1i(0xFFFFFFFF); - sdtx_putc('A'); - sdtx_puts("Hello World!"); - sdtx_putr("Hello World!", 5); - sdtx_printf("Hello World %d %d %d", 1, 2, 3); - shutdown(); -} - -UTEST(sokol_debugtext, set_font) { - init(); - T(0 == _sdtx.cur_ctx->cur_font); - sdtx_font(1); - T(1 == _sdtx.cur_ctx->cur_font); - sdtx_font(2); - T(2 == _sdtx.cur_ctx->cur_font); - shutdown(); -} - -UTEST(sokol_debugtext, set_canvas) { - init(); - sdtx_origin(10.0f, 11.0f); - sdtx_pos(1.0f, 2.0f); - sdtx_canvas(320.0f, 200.0f); - TFLT(_sdtx.cur_ctx->canvas_size.x, 320.0f); - TFLT(_sdtx.cur_ctx->canvas_size.y, 200.0f); - TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 320.0f); - TFLT(_sdtx.cur_ctx->glyph_size.y, 8.0f / 200.0f); - // origin and pos must be reset to 0 when canvas is set - TFLT(_sdtx.cur_ctx->origin.x, 0.0f); - TFLT(_sdtx.cur_ctx->origin.y, 0.0f); - TFLT(_sdtx.cur_ctx->pos.x, 0.0f); - TFLT(_sdtx.cur_ctx->pos.y, 0.0f); - shutdown(); -} - -UTEST(sokol_debugtext, set_origin) { - init(); - sdtx_origin(10.0f, 20.0f); - TFLT(_sdtx.cur_ctx->origin.x, 10.0f); - TFLT(_sdtx.cur_ctx->origin.y, 20.0f); - shutdown(); -} - -UTEST(sokol_debugtext, cursor_movement) { - init(); - sdtx_pos(1.0f, 2.0f); - TFLT(_sdtx.cur_ctx->pos.x, 1.0f); - TFLT(_sdtx.cur_ctx->pos.y, 2.0f); - sdtx_pos_x(5.0f); - TFLT(_sdtx.cur_ctx->pos.x, 5.0f); - TFLT(_sdtx.cur_ctx->pos.y, 2.0f); - sdtx_pos_y(6.0f); - TFLT(_sdtx.cur_ctx->pos.x, 5.0f); - TFLT(_sdtx.cur_ctx->pos.y, 6.0f); - sdtx_move(-1.0f, -3.0f); - TFLT(_sdtx.cur_ctx->pos.x, 4.0f); - TFLT(_sdtx.cur_ctx->pos.y, 3.0f); - sdtx_move_x(+1.0f); - TFLT(_sdtx.cur_ctx->pos.x, 5.0f); - TFLT(_sdtx.cur_ctx->pos.y, 3.0f); - sdtx_move_y(+3.0f); - TFLT(_sdtx.cur_ctx->pos.x, 5.0f); - TFLT(_sdtx.cur_ctx->pos.y, 6.0f); - sdtx_crlf(); - TFLT(_sdtx.cur_ctx->pos.x, 0.0f); - TFLT(_sdtx.cur_ctx->pos.y, 7.0f); - sdtx_pos(20.0f, 30.0f); - sdtx_home(); - TFLT(_sdtx.cur_ctx->pos.x, 0.0f); - TFLT(_sdtx.cur_ctx->pos.y, 0.0f); - shutdown(); -} - -UTEST(sokol_debugtext, set_color) { - init(); - T(_sdtx.cur_ctx->color == _SDTX_DEFAULT_COLOR); - sdtx_color3b(255, 127, 0); - T(_sdtx.cur_ctx->color == 0xFF007FFF); - sdtx_color4b(0, 127, 255, 255); - T(_sdtx.cur_ctx->color == 0xFFFF7F00); - sdtx_color3f(1.0f, 0.5f, 0.0f); - T(_sdtx.cur_ctx->color == 0xFF007FFF); - sdtx_color4f(0.0f, 0.5f, 1.0f, 1.0f); - T(_sdtx.cur_ctx->color == 0xFFFF7F00); - sdtx_color1i(0xFF000000); - T(_sdtx.cur_ctx->color == 0xFF000000); - shutdown(); -} - -UTEST(sokol_debugtext, vertex_overflow) { - // overflowing the vertex buffer must not crash - init_with(&(sdtx_desc_t){ - .context.char_buf_size = 8, - }); - for (int i = 0; i < 32; i++) { - sdtx_putc('A'); - } - sdtx_puts("1234567890"); - sdtx_putr("1234567890", 5); - sdtx_printf("Hello World %d!\n", 12); - T(_sdtx.cur_ctx->vertices.next == _sdtx.cur_ctx->vertices.cap); - shutdown(); -} - -UTEST(sokol_debugtext, context_overflow) { - // creating too many contexts should not crash - init_with(&(sdtx_desc_t){ - .context_pool_size = 4, - }); - T(_sdtx.context_pool.pool.size == 5); - // one slot is taken by the default context - sdtx_context ctx[4]; - for (int i = 0; i < 4; i++) { - ctx[i] = sdtx_make_context(&(sdtx_context_desc_t){ 0 }); - if (i < 3) { - T(ctx[i].id != 0); - } - else { - T(ctx[i].id == 0); - } - } - // destroying an invalid context should not crash - for (int i = 0; i < 4; i++) { - sdtx_destroy_context(ctx[i]); - } - shutdown(); -} - -UTEST(sokol_debugtext, printf_overflow) { - // overflowing the printf formatting buffer should not crash - init_with(&(sdtx_desc_t){ - .printf_buf_size = 8 - }); - T(9 == _sdtx.fmt_buf_size); - T(16 == sdtx_printf("Hello %d\n", 123456789)); - T('H' == _sdtx.fmt_buf[0]) - T('e' == _sdtx.fmt_buf[1]) - T('l' == _sdtx.fmt_buf[2]) - T('l' == _sdtx.fmt_buf[3]) - T('o' == _sdtx.fmt_buf[4]) - T(' ' == _sdtx.fmt_buf[5]) - T('1' == _sdtx.fmt_buf[6]) - T('2' == _sdtx.fmt_buf[7]) - T(0 == _sdtx.fmt_buf[8]) - shutdown(); -} - -UTEST(sokol_debugtext, rewind_after_draw) { - // calling sdtx_draw() must rewind the cursor position, font and - // vertex pointer, to keep canvas size and origin as is - init(); - sdtx_canvas(256, 128); - TFLT(_sdtx.cur_ctx->canvas_size.x, 256); - TFLT(_sdtx.cur_ctx->canvas_size.y, 128); - sdtx_origin(5, 5); - TFLT(_sdtx.cur_ctx->origin.x, 5); - TFLT(_sdtx.cur_ctx->origin.y, 5); - sdtx_pos(10, 20); - TFLT(_sdtx.cur_ctx->pos.x, 10); - TFLT(_sdtx.cur_ctx->pos.y, 20); - sdtx_font(3); - T(_sdtx.cur_ctx->cur_font == 3); - sdtx_printf("Hello World!\n"); - T(_sdtx.cur_ctx->vertices.next != 0); - sg_begin_pass(&(sg_pass){ - .swapchain = { - .width = 256, - .height = 256, - .sample_count = 1, - .color_format = SG_PIXELFORMAT_RGBA8, - .depth_format = SG_PIXELFORMAT_DEPTH_STENCIL, - } - }); - sdtx_draw(); - sg_end_pass(); - sg_commit(); - TFLT(_sdtx.cur_ctx->canvas_size.x, 256); - TFLT(_sdtx.cur_ctx->canvas_size.y, 128); - TFLT(_sdtx.cur_ctx->origin.x, 5); - TFLT(_sdtx.cur_ctx->origin.y, 5); - TFLT(_sdtx.cur_ctx->pos.x, 0); - TFLT(_sdtx.cur_ctx->pos.x, 0); - T(_sdtx.cur_ctx->cur_font == 0); - T(_sdtx.cur_ctx->vertices.next == 0); - shutdown(); -} - -UTEST(sokol_debugtext, putr) { - // test if sdtx_putr() draws the right amount of characters - init(); - int start_index = _sdtx.cur_ctx->vertices.next; - sdtx_putr("Hello World!", 5); - T((5 * 6) == (_sdtx.cur_ctx->vertices.next - start_index)); - - start_index = _sdtx.cur_ctx->vertices.next; - sdtx_putr("Hello!\n\n\n\n\n\n\n\n\n\n\n", 10); - // NOTE: the \n's don't result in rendered vertices - T((6 * 6) == (_sdtx.cur_ctx->vertices.next - start_index)); - shutdown(); -} - -UTEST(sokol_debugtext, default_context) { - init(); - T(sdtx_default_context().id == SDTX_DEFAULT_CONTEXT.id); - shutdown(); -} - -// switching layers without any text inbetween should not advance the current draw command -UTEST(sokol_debug_text, empty_layers) { - init(); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); - sdtx_layer(1); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 1); - sdtx_layer(2); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 2); - sdtx_layer(0); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); - shutdown(); -} - -// switching layers with text inbetween should advance the current draw command -UTEST(sokol_debug_text, non_empty_layers) { - init(); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); - T(_sdtx.cur_ctx->commands.ptr[0].first_vertex == 0); - T(_sdtx.cur_ctx->commands.ptr[0].num_vertices == 0); - sdtx_puts("123"); - T(_sdtx.cur_ctx->commands.next == 1); - T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); - T(_sdtx.cur_ctx->commands.ptr[0].first_vertex == 0); - T(_sdtx.cur_ctx->commands.ptr[0].num_vertices == (3 * 6)); - sdtx_layer(1); - sdtx_puts("1234"); - T(_sdtx.cur_ctx->commands.next == 2); - T(_sdtx.cur_ctx->commands.ptr[1].layer_id == 1); - T(_sdtx.cur_ctx->commands.ptr[1].first_vertex == (3 * 6)); - T(_sdtx.cur_ctx->commands.ptr[1].num_vertices == (4 * 6)); - // switching to same layer should not start a new draw commands - sdtx_layer(1); - sdtx_puts("12345"); - T(_sdtx.cur_ctx->commands.next == 2); - T(_sdtx.cur_ctx->commands.ptr[1].layer_id == 1); - T(_sdtx.cur_ctx->commands.ptr[1].first_vertex == (3 * 6)); - T(_sdtx.cur_ctx->commands.ptr[1].num_vertices == (9 * 6)); - sdtx_layer(0); - sdtx_puts("123456"); - T(_sdtx.cur_ctx->commands.next == 3); - T(_sdtx.cur_ctx->commands.ptr[2].layer_id == 0); - T(_sdtx.cur_ctx->commands.ptr[2].first_vertex == (12 * 6)); - T(_sdtx.cur_ctx->commands.ptr[2].num_vertices == (6 * 6)); - shutdown(); -} - -UTEST(sokol_debug_text, command_buffer_overflow) { - init_with(&(sdtx_desc_t){ - .context = { - .max_commands = 4 - } - }); - sdtx_puts("0"); - T(_sdtx.cur_ctx->commands.next == 1); - sdtx_layer(1); - sdtx_puts("1"); - T(_sdtx.cur_ctx->commands.next == 2); - sdtx_layer(2); - sdtx_puts("2"); - T(_sdtx.cur_ctx->commands.next == 3); - sdtx_layer(3); - sdtx_puts("3"); - T(_sdtx.cur_ctx->commands.next == 4); - // from here on should fail - sdtx_layer(4); - sdtx_puts("4"); - T(_sdtx.cur_ctx->commands.next == 4); -} \ No newline at end of file diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_fetch_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_fetch_test.c deleted file mode 100644 index 8318a9e..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_fetch_test.c +++ /dev/null @@ -1,862 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-fetch-test.c -// -// FIXME: simulate allocation errors -//------------------------------------------------------------------------------ -#define SOKOL_IMPL -#define SFETCH_MAX_USERDATA_UINT64 (8) -#define SFETCH_MAX_PATH (32) -#include "sokol_fetch.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) -#define TSTR(s0, s1) EXPECT_TRUE(0 == strcmp(s0,s1)) - -static uint8_t load_file_buf[500000]; -static const uint64_t combatsignal_file_size = 409482; - -typedef struct { - int a, b, c; -} userdata_t; - -static const _sfetch_item_t zeroed_item = {0}; - -#ifdef _WIN32 -#include -static void sleep_ms(int ms) { - Sleep((DWORD)ms); -} -#else -#include -static void sleep_ms(uint32_t ms) { - usleep(ms * 1000); -} -#endif - -/* private implementation functions */ -UTEST(sokol_fetch, path_make) { - const char* str31 = "1234567890123456789012345678901"; - const char* str32 = "12345678901234567890123456789012"; - // max allowed string length (MAX_PATH - 1) - _sfetch_path_t p31 = _sfetch_path_make(str31); - TSTR(p31.buf, str31); - // overflow - _sfetch_path_t p32 = _sfetch_path_make(str32); - T(p32.buf[0] == 0); -} - -UTEST(sokol_fetch, make_id) { - uint32_t slot_id = _sfetch_make_id(123, 456); - T(slot_id == ((456<<16)|123)); - T(_sfetch_slot_index(slot_id) == 123); -} - -UTEST(sokol_fetch, item_init_discard) { - userdata_t user_data = { - .a = 123, - .b = 456, - .c = 789 - }; - sfetch_request_t request = { - .channel = 4, - .path = "hello_world.txt", - .chunk_size = 128, - .user_data = SFETCH_RANGE(user_data) - }; - _sfetch_item_t item = zeroed_item; - uint32_t slot_id = _sfetch_make_id(1, 1); - _sfetch_item_init(&item, slot_id, &request); - T(item.handle.id == slot_id); - T(item.channel == 4); - T(item.lane == _SFETCH_INVALID_LANE); - T(item.chunk_size == 128); - T(item.state == _SFETCH_STATE_INITIAL); - TSTR(item.path.buf, request.path); - T(item.user.user_data_size == sizeof(userdata_t)); - const userdata_t* ud = (const userdata_t*) item.user.user_data; - T((((uintptr_t)ud) & 0x7) == 0); // check alignment - T(ud->a == 123); - T(ud->b == 456); - T(ud->c == 789); - - item.state = _SFETCH_STATE_FETCHING; - _sfetch_item_discard(&item); - T(item.handle.id == 0); - T(item.path.buf[0] == 0); - T(item.state == _SFETCH_STATE_INITIAL); - T(item.user.user_data_size == 0); - T(item.user.user_data[0] == 0); -} - -UTEST(sokol_fetch, item_init_path_overflow) { - sfetch_request_t request = { - .path = "012345678901234567890123456789012", - }; - _sfetch_item_t item = zeroed_item; - _sfetch_item_init(&item, _sfetch_make_id(1, 1), &request); - T(item.path.buf[0] == 0); -} - -UTEST(sokol_fetch, item_init_userdata_overflow) { - uint8_t big_data[128] = { 0xFF }; - sfetch_request_t request = { - .path = "hello_world.txt", - .user_data = SFETCH_RANGE(big_data), - }; - _sfetch_item_t item = zeroed_item; - _sfetch_item_init(&item, _sfetch_make_id(1, 1), &request); - T(item.user.user_data_size == 0); - T(item.user.user_data[0] == 0); -} - -UTEST(sokol_fetch, pool_init_discard) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_pool_t pool = {0}; - const uint32_t num_items = 127; - T(_sfetch_pool_init(&pool, num_items)); - T(pool.valid); - T(pool.size == 128); - T(pool.free_top == 127); - T(pool.free_slots[0] == 127); - T(pool.free_slots[1] == 126); - T(pool.free_slots[126] == 1); - _sfetch_pool_discard(&pool); - T(!pool.valid); - T(pool.free_slots == 0); - T(pool.items == 0); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, pool_alloc_free) { - sfetch_setup(&(sfetch_desc_t){0}); - uint8_t buf[32]; - _sfetch_pool_t pool = {0}; - const uint32_t num_items = 16; - _sfetch_pool_init(&pool, num_items); - uint32_t slot_id = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ - .path = "hello_world.txt", - .buffer = SFETCH_RANGE(buf), - }); - T(slot_id == 0x00010001); - T(pool.items[1].state == _SFETCH_STATE_ALLOCATED); - T(pool.items[1].handle.id == slot_id); - TSTR(pool.items[1].path.buf, "hello_world.txt"); - T(pool.items[1].buffer.ptr == buf); - T(pool.items[1].buffer.size == sizeof(buf)); - T(pool.free_top == 15); - _sfetch_pool_item_free(&pool, slot_id); - T(pool.items[1].handle.id == 0); - T(pool.items[1].state == _SFETCH_STATE_INITIAL); - T(pool.items[1].path.buf[0] == 0); - T(pool.items[1].buffer.ptr == 0); - T(pool.items[1].buffer.size == 0); - T(pool.free_top == 16); - _sfetch_pool_discard(&pool); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, pool_overflow) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_pool_t pool = {0}; - _sfetch_pool_init(&pool, 4); - uint32_t id0 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path0" }); - uint32_t id1 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path1" }); - uint32_t id2 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path2" }); - uint32_t id3 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path3" }); - // next alloc should fail - uint32_t id4 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path4" }); - T(id0 == 0x00010001); - T(id1 == 0x00010002); - T(id2 == 0x00010003); - T(id3 == 0x00010004); - T(id4 == 0); - T(pool.items[1].handle.id == id0); - T(pool.items[2].handle.id == id1); - T(pool.items[3].handle.id == id2); - T(pool.items[4].handle.id == id3); - // free one item, alloc should work now - _sfetch_pool_item_free(&pool, id0); - uint32_t id5 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path5" }); - T(id5 == 0x00020001); - T(pool.items[1].handle.id == id5); - TSTR(pool.items[1].path.buf, "path5"); - _sfetch_pool_discard(&pool); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, lookup_item) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_pool_t pool = {0}; - _sfetch_pool_init(&pool, 4); - uint32_t id0 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path0" }); - uint32_t id1 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path1" }); - const _sfetch_item_t* item0 = _sfetch_pool_item_lookup(&pool, id0); - const _sfetch_item_t* item1 = _sfetch_pool_item_lookup(&pool, id1); - T(item0 == &pool.items[1]); - T(item1 == &pool.items[2]); - /* invalid handle always returns 0-ptr */ - T(0 == _sfetch_pool_item_lookup(&pool, _sfetch_make_id(0, 0))); - /* free an item and make sure it's detected as dangling */ - _sfetch_pool_item_free(&pool, id0); - T(0 == _sfetch_pool_item_lookup(&pool, id0)); - _sfetch_pool_discard(&pool); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, ring_init_discard) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_ring_t ring = {0}; - const uint32_t num_slots = 4; - T(_sfetch_ring_init(&ring, num_slots)); - T(ring.head == 0); - T(ring.tail == 0); - T(ring.num == (num_slots + 1)); - T(ring.buf); - _sfetch_ring_discard(&ring); - T(ring.head == 0); - T(ring.tail == 0); - T(ring.num == 0); - T(ring.buf == 0); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, ring_enqueue_dequeue) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_ring_t ring = {0}; - const uint32_t num_slots = 4; - _sfetch_ring_init(&ring, num_slots); - T(_sfetch_ring_count(&ring) == 0); - T(_sfetch_ring_empty(&ring)); - T(!_sfetch_ring_full(&ring)); - for (uint32_t i = 0; i < num_slots; i++) { - T(!_sfetch_ring_full(&ring)); - _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1)); - T(_sfetch_ring_count(&ring) == (i+1)); - T(!_sfetch_ring_empty(&ring)); - } - T(_sfetch_ring_count(&ring) == 4); - T(!_sfetch_ring_empty(&ring)); - T(_sfetch_ring_full(&ring)); - for (uint32_t i = 0; i < num_slots; i++) { - T(_sfetch_ring_peek(&ring, i) == _sfetch_make_id(1, i+1)); - } - for (uint32_t i = 0; i < num_slots; i++) { - T(!_sfetch_ring_empty(&ring)); - const uint32_t slot_id = _sfetch_ring_dequeue(&ring); - T(slot_id == _sfetch_make_id(1, i+1)); - T(!_sfetch_ring_full(&ring)); - } - T(_sfetch_ring_count(&ring) == 0); - T(_sfetch_ring_empty(&ring)); - T(!_sfetch_ring_full(&ring)); - _sfetch_ring_discard(&ring); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, ring_wrap_around) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_ring_t ring = {0}; - _sfetch_ring_init(&ring, 4); - uint32_t i = 0; - for (i = 0; i < 4; i++) { - _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1)); - } - T(_sfetch_ring_full(&ring)); - for (; i < 64; i++) { - T(_sfetch_ring_full(&ring)); - T(_sfetch_ring_dequeue(&ring) == _sfetch_make_id(1, (i - 3))); - T(!_sfetch_ring_full(&ring)); - _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1)); - } - T(_sfetch_ring_full(&ring)); - for (i = 0; i < 4; i++) { - T(_sfetch_ring_dequeue(&ring) == _sfetch_make_id(1, (i + 61))); - } - T(_sfetch_ring_empty(&ring)); - _sfetch_ring_discard(&ring); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, ring_wrap_count) { - sfetch_setup(&(sfetch_desc_t){0}); - _sfetch_ring_t ring = {0}; - _sfetch_ring_init(&ring, 8); - // add and remove 4 items to move tail to the middle - for (uint32_t i = 0; i < 4; i++) { - _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1)); - _sfetch_ring_dequeue(&ring); - T(_sfetch_ring_empty(&ring)); - } - // add another 8 items - for (uint32_t i = 0; i < 8; i++) { - _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1)); - } - // now test, dequeue and test... - T(_sfetch_ring_full(&ring)); - for (uint32_t i = 0; i < 8; i++) { - T(_sfetch_ring_count(&ring) == (8 - i)); - _sfetch_ring_dequeue(&ring); - } - T(_sfetch_ring_count(&ring) == 0); - T(_sfetch_ring_empty(&ring)); - _sfetch_ring_discard(&ring); - sfetch_shutdown(); -} - -/* NOTE: channel_worker is called from a thread */ -static int num_processed_items = 0; -static void channel_worker(_sfetch_t* ctx, uint32_t slot_id) { - (void)ctx; - (void)slot_id; - num_processed_items++; -} - -UTEST(sokol_fetch, channel_init_discard) { - sfetch_setup(&(sfetch_desc_t){0}); - num_processed_items = 0; - _sfetch_channel_t chn = {0}; - const uint32_t num_slots = 12; - const uint32_t num_lanes = 64; - _sfetch_channel_init(&chn, 0, num_slots, num_lanes, channel_worker); - T(chn.valid); - T(_sfetch_ring_full(&chn.free_lanes)); - T(_sfetch_ring_empty(&chn.user_sent)); - T(_sfetch_ring_empty(&chn.user_incoming)); - #if !defined(__EMSCRIPTEN__) - T(_sfetch_ring_empty(&chn.thread_incoming)); - T(_sfetch_ring_empty(&chn.thread_outgoing)); - #endif - T(_sfetch_ring_empty(&chn.user_outgoing)); - _sfetch_channel_discard(&chn); - T(!chn.valid); - sfetch_shutdown(); -} - -/* public API functions */ -UTEST(sokol_fetch, setup_shutdown) { - sfetch_setup(&(sfetch_desc_t){0}); - T(sfetch_valid()); - // check default values - T(sfetch_desc().max_requests == 128); - T(sfetch_desc().num_channels == 1); - T(sfetch_desc().num_lanes == 1); - sfetch_shutdown(); - T(!sfetch_valid()); -} - -UTEST(sokol_fetch, setup_too_many_channels) { - /* try to initialize with too many channels, this should clamp to - SFETCH_MAX_CHANNELS - */ - sfetch_setup(&(sfetch_desc_t){ - .num_channels = 64 - }); - T(sfetch_valid()); - T(sfetch_desc().num_channels == SFETCH_MAX_CHANNELS); - sfetch_shutdown(); -} - -UTEST(sokol_fetch, max_path) { - T(sfetch_max_path() == SFETCH_MAX_PATH); -} - -UTEST(sokol_fetch, max_userdata) { - T(sfetch_max_userdata_bytes() == (SFETCH_MAX_USERDATA_UINT64 * sizeof(uint64_t))); -} - -static uint8_t fail_open_buffer[128]; -static bool fail_open_passed; -static void fail_open_callback(const sfetch_response_t* response) { - /* if opening a file fails, it will immediate switch into CLOSED state */ - if ((response->failed) && (response->error_code == SFETCH_ERROR_FILE_NOT_FOUND)) { - fail_open_passed = true; - } -} - -UTEST(sokol_fetch, fail_open) { - sfetch_setup(&(sfetch_desc_t){0}); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "non_existing_file.txt", - .callback = fail_open_callback, - .buffer = SFETCH_RANGE(fail_open_buffer), - }); - fail_open_passed = false; - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(fail_open_passed); - sfetch_shutdown(); -} - -static bool load_file_fixed_buffer_passed; - -// The file callback is called from the "current user thread" (the same -// thread where the sfetch_send() for this request was called). Note that you -// can call sfetch_setup/shutdown() on multiple threads, each thread will -// get its own thread-local "sokol-fetch instance" and its own set of -// IO-channel threads. -static void load_file_fixed_buffer_callback(const sfetch_response_t* response) { - // when loading the whole file at once, the fetched state - // is the best place to grab/process the data - if (response->fetched) { - if ((response->data_offset == 0) && - (response->data.ptr == load_file_buf) && - (response->data.size == combatsignal_file_size) && - (response->buffer.ptr == load_file_buf) && - (response->buffer.size == sizeof(load_file_buf)) && - response->finished) - { - load_file_fixed_buffer_passed = true; - } - } -} - -UTEST(sokol_fetch, load_file_fixed_buffer) { - memset(load_file_buf, 0, sizeof(load_file_buf)); - sfetch_setup(&(sfetch_desc_t){0}); - // send a load-request for a file where we know the max size upfront, - // so we can provide a buffer right in the fetch request (otherwise - // the buffer needs to be provided in the callback when the request - // is in OPENED state, since only then the file size will be known). - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_fixed_buffer_callback, - .buffer = SFETCH_RANGE(load_file_buf), - }); - // simulate a frame-loop for as long as the request is in flight, normally - // the sfetch_dowork() function is just called somewhere in the frame - // to pump messages in and out of the IO threads, and invoke user-callbacks - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_fixed_buffer_passed); - sfetch_shutdown(); -} - -/* tests whether files with unknown size are processed correctly */ -static bool load_file_unknown_size_opened_passed; -static bool load_file_unknown_size_fetched_passed; -static void load_file_unknown_size_callback(const sfetch_response_t* response) { - if (response->dispatched) { - if ((response->data_offset == 0) && - (response->data.ptr == 0) && - (response->data.size == 0) && - (response->buffer.ptr == 0) && - (response->buffer.size == 0) && - !response->finished) - { - load_file_unknown_size_opened_passed = true; - sfetch_bind_buffer(response->handle, SFETCH_RANGE(load_file_buf)); - } - } - else if (response->fetched) { - if ((response->data_offset == 0) && - (response->data.ptr == load_file_buf) && - (response->data.size == combatsignal_file_size) && - (response->buffer.ptr == load_file_buf) && - (response->buffer.size == sizeof(load_file_buf)) && - response->finished) - { - load_file_unknown_size_fetched_passed = true; - } - } -} - -UTEST(sokol_fetch, load_file_unknown_size) { - memset(load_file_buf, 0, sizeof(load_file_buf)); - sfetch_setup(&(sfetch_desc_t){0}); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_unknown_size_callback - }); - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_unknown_size_opened_passed); - T(load_file_unknown_size_fetched_passed); - sfetch_shutdown(); -} - -/* tests whether not providing a buffer in OPENED properly fails */ -static bool load_file_no_buffer_opened_passed; -static bool load_file_no_buffer_failed_passed; -static void load_file_no_buffer_callback(const sfetch_response_t* response) { - if (response->dispatched) { - if ((response->data_offset == 0) && - (response->data.ptr == 0) && - (response->data.size == 0) && - (response->buffer.ptr == 0) && - (response->buffer.size == 0) && - !response->finished) - { - /* DO NOT provide a buffer here, see if that properly fails */ - load_file_no_buffer_opened_passed = true; - } - } - else if ((response->failed) && (response->error_code == SFETCH_ERROR_NO_BUFFER)) { - if (load_file_no_buffer_opened_passed) { - load_file_no_buffer_failed_passed = true; - } - } -} - -UTEST(sokol_fetch, load_file_no_buffer) { - memset(load_file_buf, 0, sizeof(load_file_buf)); - sfetch_setup(&(sfetch_desc_t){0}); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_no_buffer_callback - }); - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_no_buffer_opened_passed); - T(load_file_no_buffer_failed_passed); - sfetch_shutdown(); -} - -static bool load_file_too_small_passed; -static uint8_t load_file_too_small_buf[8192]; -static void load_file_too_small_callback(const sfetch_response_t* response) { - if (response->failed && (response->error_code == SFETCH_ERROR_BUFFER_TOO_SMALL)) { - load_file_too_small_passed = true; - } -} - -UTEST(sokol_fetch, load_file_too_small_buffer) { - memset(load_file_buf, 0, sizeof(load_file_buf)); - sfetch_setup(&(sfetch_desc_t){0}); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_too_small_callback, - .buffer = SFETCH_RANGE(load_file_too_small_buf), - }); - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_too_small_passed); - sfetch_shutdown(); -} - - -/* test loading a big file via a small chunk-buffer, the callback will - be called multiple times with the FETCHED state until the entire file - is loaded -*/ -static bool load_file_chunked_passed; -static uint8_t load_chunk_buf[8192]; -static uint8_t load_file_chunked_content[500000]; -static void load_file_chunked_callback(const sfetch_response_t* response) { - if (response->fetched) { - uint8_t* dst = &load_file_chunked_content[response->data_offset]; - const uint8_t* src = response->data.ptr; - size_t num_bytes = response->data.size; - memcpy(dst, src, num_bytes); - if (response->finished) { - load_file_chunked_passed = true; - } - } -} - -UTEST(sokol_fetch, load_file_chunked) { - memset(load_file_buf, 0, sizeof(load_file_buf)); - memset(load_chunk_buf, 0, sizeof(load_chunk_buf)); - memset(load_file_chunked_content, 0, sizeof(load_file_chunked_content)); - load_file_fixed_buffer_passed = false; - sfetch_setup(&(sfetch_desc_t){0}); - // request for chunked-loading - sfetch_handle_t h0 = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_chunked_callback, - .buffer = SFETCH_RANGE(load_chunk_buf), - .chunk_size = sizeof(load_chunk_buf) - }); - // request for all-in-one loading for comparing with the chunked buffer - sfetch_handle_t h1 = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_fixed_buffer_callback, - .buffer = SFETCH_RANGE(load_file_buf), - }); - int frame_count = 0; - const int max_frames = 10000; - while ((sfetch_handle_valid(h0) || sfetch_handle_valid(h1)) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_chunked_passed); - T(0 == memcmp(load_file_chunked_content, load_file_buf, combatsignal_file_size)); - sfetch_shutdown(); -} - -/* load N big files in small chunks interleaved on the same channel via lanes */ -#define LOAD_FILE_LANES_NUM_LANES (4) - -static uint8_t load_file_lanes_chunk_buf[LOAD_FILE_LANES_NUM_LANES][8192]; -static uint8_t load_file_lanes_content[LOAD_FILE_LANES_NUM_LANES][500000]; -static int load_file_lanes_passed[LOAD_FILE_LANES_NUM_LANES]; -static void load_file_lanes_callback(const sfetch_response_t* response) { - assert((response->channel == 0) && (response->lane < LOAD_FILE_LANES_NUM_LANES)); - if (response->fetched) { - uint8_t* dst = &load_file_lanes_content[response->lane][response->data_offset]; - const uint8_t* src = response->data.ptr; - size_t num_bytes = response->data.size; - memcpy(dst, src, num_bytes); - if (response->finished) { - load_file_lanes_passed[response->lane]++; - } - } -} - -UTEST(sokol_fetch, load_file_lanes) { - for (int i = 0; i < LOAD_FILE_LANES_NUM_LANES; i++) { - memset(load_file_lanes_content[i], i, sizeof(load_file_lanes_content[i])); - } - sfetch_setup(&(sfetch_desc_t){ - .num_channels = 1, - .num_lanes = LOAD_FILE_LANES_NUM_LANES, - }); - sfetch_handle_t h[LOAD_FILE_LANES_NUM_LANES]; - for (int lane = 0; lane < LOAD_FILE_LANES_NUM_LANES; lane++) { - h[lane] = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_lanes_callback, - .buffer = { .ptr = load_file_lanes_chunk_buf[lane], .size = sizeof(load_file_lanes_chunk_buf[0]) }, - .chunk_size = sizeof(load_file_lanes_chunk_buf[0]) - }); - } - bool done = false; - int frame_count = 0; - const int max_frames = 10000; - while (!done && (frame_count++ < max_frames)) { - done = true; - for (int i = 0; i < LOAD_FILE_LANES_NUM_LANES; i++) { - done &= !sfetch_handle_valid(h[i]); - } - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - for (int i = 0; i < LOAD_FILE_LANES_NUM_LANES; i++) { - T(1 == load_file_lanes_passed[i]); - T(0 == memcmp(load_file_lanes_content[0], load_file_lanes_content[i], combatsignal_file_size)); - } - sfetch_shutdown(); -} - -/* same as above, but issue more requests than available lanes to test if rate-limiting works */ -#define LOAD_FILE_THROTTLE_NUM_LANES (4) -#define LOAD_FILE_THROTTLE_NUM_PASSES (3) -#define LOAD_FILE_THROTTLE_NUM_REQUESTS (12) // lanes * passes - -static uint8_t load_file_throttle_chunk_buf[LOAD_FILE_THROTTLE_NUM_LANES][128000]; -static uint8_t load_file_throttle_content[LOAD_FILE_THROTTLE_NUM_PASSES][LOAD_FILE_THROTTLE_NUM_LANES][500000]; -static int load_file_throttle_passed[LOAD_FILE_THROTTLE_NUM_LANES]; - -static void load_file_throttle_callback(const sfetch_response_t* response) { - assert((response->channel == 0) && (response->lane < LOAD_FILE_LANES_NUM_LANES)); - if (response->fetched) { - assert(load_file_throttle_passed[response->lane] < LOAD_FILE_THROTTLE_NUM_PASSES); - uint8_t* dst = &load_file_throttle_content[load_file_throttle_passed[response->lane]][response->lane][response->data_offset]; - const uint8_t* src = response->data.ptr; - size_t num_bytes = response->data.size; - memcpy(dst, src, num_bytes); - if (response->finished) { - load_file_throttle_passed[response->lane]++; - } - } -} - -UTEST(sokol_fetch, load_file_throttle) { - for (int pass = 0; pass < LOAD_FILE_THROTTLE_NUM_PASSES; pass++) { - for (int lane = 0; lane < LOAD_FILE_THROTTLE_NUM_LANES; lane++) { - memset(load_file_throttle_content[pass][lane], 10*pass+lane, sizeof(load_file_throttle_content[pass][lane])); - } - } - sfetch_setup(&(sfetch_desc_t){ - .num_channels = 1, - .num_lanes = LOAD_FILE_THROTTLE_NUM_LANES, - }); - sfetch_handle_t h[LOAD_FILE_THROTTLE_NUM_REQUESTS]; - for (int i = 0; i < LOAD_FILE_THROTTLE_NUM_REQUESTS; i++) { - h[i] = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_throttle_callback, - .buffer = { - .ptr = load_file_throttle_chunk_buf[i % LOAD_FILE_THROTTLE_NUM_LANES], - .size = sizeof(load_file_throttle_chunk_buf[0]), - }, - .chunk_size = sizeof(load_file_throttle_chunk_buf[0]) - }); - T(sfetch_handle_valid(h[i])); - } - bool done = false; - int frame_count = 0; - const int max_frames = 10000; - while (!done && (frame_count++ < max_frames)) { - done = true; - for (int i = 0; i < LOAD_FILE_THROTTLE_NUM_REQUESTS; i++) { - done &= !sfetch_handle_valid(h[i]); - } - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - for (int lane = 0; lane < LOAD_FILE_THROTTLE_NUM_LANES; lane++) { - T(LOAD_FILE_THROTTLE_NUM_PASSES == load_file_throttle_passed[lane]); - for (int pass = 0; pass < LOAD_FILE_THROTTLE_NUM_PASSES; pass++) { - T(0 == memcmp(load_file_throttle_content[0][0], load_file_throttle_content[pass][lane], combatsignal_file_size)); - } - } - sfetch_shutdown(); -} - -/* test parallel fetches on multiple channels */ -#define LOAD_CHANNEL_NUM_CHANNELS (16) -static uint8_t load_channel_buf[LOAD_CHANNEL_NUM_CHANNELS][500000]; -static bool load_channel_passed[LOAD_CHANNEL_NUM_CHANNELS]; - -void load_channel_callback(const sfetch_response_t* response) { - assert(response->channel < LOAD_CHANNEL_NUM_CHANNELS); - assert(!load_channel_passed[response->channel]); - if (response->fetched) { - if ((response->data.size == combatsignal_file_size) && response->finished) { - load_channel_passed[response->channel] = true; - } - } -} - -UTEST(sokol_fetch, load_channel) { - for (int chn = 0; chn < LOAD_CHANNEL_NUM_CHANNELS; chn++) { - memset(load_channel_buf[chn], chn, sizeof(load_channel_buf[chn])); - } - sfetch_setup(&(sfetch_desc_t){ - .num_channels = LOAD_CHANNEL_NUM_CHANNELS - }); - sfetch_handle_t h[LOAD_CHANNEL_NUM_CHANNELS]; - for (uint32_t chn = 0; chn < LOAD_CHANNEL_NUM_CHANNELS; chn++) { - h[chn] = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .channel = chn, - .callback = load_channel_callback, - .buffer = SFETCH_RANGE(load_channel_buf[chn]), - }); - } - bool done = false; - int frame_count = 0; - const int max_frames = 100000; - while (!done && (frame_count++ < max_frames)) { - done = true; - for (int i = 0; i < LOAD_CHANNEL_NUM_CHANNELS; i++) { - done &= !sfetch_handle_valid(h[i]); - } - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - for (int chn = 0; chn < LOAD_CHANNEL_NUM_CHANNELS; chn++) { - T(load_channel_passed[chn]); - T(0 == memcmp(load_channel_buf[0], load_channel_buf[chn], combatsignal_file_size)); - } - sfetch_shutdown(); -} - -static bool load_file_cancel_passed = false; -static void load_file_cancel_callback(const sfetch_response_t* response) { - if (response->dispatched) { - sfetch_cancel(response->handle); - } - if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) { - load_file_cancel_passed = true; - } -} - -UTEST(sokol_fetch, load_file_cancel) { - sfetch_setup(&(sfetch_desc_t){ - .num_channels = 1 - }); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_cancel_callback, - }); - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_cancel_passed); - sfetch_shutdown(); -} - -static bool load_file_cancel_before_dispatch_passed = false; -static void load_file_cancel_before_dispatch_callback(const sfetch_response_t* response) { - // cancelled, finished, failed and error code must all be set - if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) { - load_file_cancel_before_dispatch_passed = true; - } -} - -UTEST(sokol_fetch, load_file_cancel_before_dispatch) { - sfetch_setup(&(sfetch_desc_t){ - .num_channels = 1, - }); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_cancel_before_dispatch_callback, - }); - sfetch_cancel(h); - sfetch_dowork(); - T(load_file_cancel_before_dispatch_passed); - sfetch_shutdown(); -} - -static bool load_file_cancel_after_dispatch_passed = false; -static void load_file_cancel_after_dispatch_callback(const sfetch_response_t* response) { - // when cancelled, then finished, failed and error code must all be set - if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) { - load_file_cancel_after_dispatch_passed = true; - } -} - -UTEST(sokol_fetch, load_file_cancel_after_dispatch) { - sfetch_setup(&(sfetch_desc_t){ - .num_channels = 1, - }); - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "comsi.s3m", - .callback = load_file_cancel_after_dispatch_callback, - .buffer = SFETCH_RANGE(load_file_buf), - }); - int frame_count = 0; - const int max_frames = 10000; - while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { - sfetch_dowork(); - sfetch_cancel(h); - sleep_ms(1); - } - T(frame_count < max_frames); - T(load_file_cancel_after_dispatch_passed); - sfetch_shutdown(); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_gfx_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_gfx_test.c deleted file mode 100644 index 7535605..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_gfx_test.c +++ /dev/null @@ -1,2975 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-gfx-test.c -// NOTE: this is not only testing the public API behaviour, but also -// accesses private functions and data. It may make sense to split -// these into two separate tests. -//------------------------------------------------------------------------------ -#include "force_dummy_backend.h" -#define SOKOL_IMPL -#include "sokol_gfx.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) - -#define MAX_LOGITEMS (32) -static int num_log_called = 0; -static sg_log_item log_items[MAX_LOGITEMS]; - -static void test_logger(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data) { - (void)tag; - (void)log_level; - (void)message_or_null; - (void)line_nr; - (void)filename_or_null; - (void)user_data; - if (num_log_called < MAX_LOGITEMS) { - log_items[num_log_called++] = log_item_id; - } - if (message_or_null) { - printf("%s\n", message_or_null); - } -} - -static void reset_log_items(void) { - num_log_called = 0; - memset(log_items, 0, sizeof(log_items)); -} - -static void setup(const sg_desc* desc) { - reset_log_items(); - sg_desc desc_with_logger = *desc; - desc_with_logger.logger.func = test_logger; - sg_setup(&desc_with_logger); -} - -static sg_buffer create_buffer(void) { - static const float data[] = { 1, 2, 3, 4 }; - return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(data) }); -} - -static sg_image create_image(void) { - return sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 128 - }); -} - -static sg_shader create_shader(void) { - return sg_make_shader(&(sg_shader_desc){0}); -} - -static sg_pipeline create_pipeline(void) { - return sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .attrs[0].format = SG_VERTEXFORMAT_FLOAT3 - }, - .shader = sg_make_shader(&(sg_shader_desc){0}) - }); -} - -static sg_attachments create_attachments(void) { - sg_image_desc img_desc = { - .render_target = true, - .width = 128, - .height = 128, - }; - return sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = sg_make_image(&img_desc), - [1].image = sg_make_image(&img_desc), - [2].image = sg_make_image(&img_desc) - }, - }); -} - -UTEST(sokol_gfx, init_shutdown) { - setup(&(sg_desc){0}); - T(sg_isvalid()); - sg_shutdown(); - T(!sg_isvalid()); -} - -UTEST(sokol_gfx, query_desc) { - setup(&(sg_desc){ - .buffer_pool_size = 1024, - .sampler_pool_size = 8, - .shader_pool_size = 128, - .attachments_pool_size = 64, - }); - const sg_desc desc = sg_query_desc(); - T(desc.buffer_pool_size == 1024); - T(desc.image_pool_size == _SG_DEFAULT_IMAGE_POOL_SIZE); - T(desc.sampler_pool_size == 8); - T(desc.shader_pool_size == 128); - T(desc.pipeline_pool_size == _SG_DEFAULT_PIPELINE_POOL_SIZE); - T(desc.attachments_pool_size == 64); - T(desc.uniform_buffer_size == _SG_DEFAULT_UB_SIZE); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_backend) { - setup(&(sg_desc){0}); - T(sg_query_backend() == SG_BACKEND_DUMMY); - sg_shutdown(); -} - -UTEST(sokol_gfx, pool_size) { - setup(&(sg_desc){ - .buffer_pool_size = 1024, - .image_pool_size = 2048, - .shader_pool_size = 128, - .pipeline_pool_size = 256, - .attachments_pool_size = 64, - }); - T(sg_isvalid()); - /* pool slot 0 is reserved (this is the "invalid slot") */ - T(_sg.pools.buffer_pool.size == 1025); - T(_sg.pools.image_pool.size == 2049); - T(_sg.pools.shader_pool.size == 129); - T(_sg.pools.pipeline_pool.size == 257); - T(_sg.pools.attachments_pool.size == 65); - T(_sg.pools.buffer_pool.queue_top == 1024); - T(_sg.pools.image_pool.queue_top == 2048); - T(_sg.pools.shader_pool.queue_top == 128); - T(_sg.pools.pipeline_pool.queue_top == 256); - T(_sg.pools.attachments_pool.queue_top == 64); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_fail_destroy_buffers) { - setup(&(sg_desc){ - .buffer_pool_size = 3 - }); - T(sg_isvalid()); - - sg_buffer buf[3] = { {0} }; - for (int i = 0; i < 3; i++) { - buf[i] = sg_alloc_buffer(); - T(buf[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.buffer_pool.queue_top); - T(sg_query_buffer_state(buf[i]) == SG_RESOURCESTATE_ALLOC); - } - /* the next alloc will fail because the pool is exhausted */ - sg_buffer b3 = sg_alloc_buffer(); - T(b3.id == SG_INVALID_ID); - T(sg_query_buffer_state(b3) == SG_RESOURCESTATE_INVALID); - - /* before destroying, the resources must be either in valid or failed state */ - for (int i = 0; i < 3; i++) { - sg_fail_buffer(buf[i]); - T(sg_query_buffer_state(buf[i]) == SG_RESOURCESTATE_FAILED); - } - for (int i = 0; i < 3; i++) { - sg_destroy_buffer(buf[i]); - T(sg_query_buffer_state(buf[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.buffer_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_fail_destroy_images) { - setup(&(sg_desc){ - .image_pool_size = 3 - }); - T(sg_isvalid()); - - sg_image img[3] = { {0} }; - for (int i = 0; i < 3; i++) { - img[i] = sg_alloc_image(); - T(img[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.image_pool.queue_top); - T(sg_query_image_state(img[i]) == SG_RESOURCESTATE_ALLOC); - } - /* the next alloc will fail because the pool is exhausted */ - sg_image i3 = sg_alloc_image(); - T(i3.id == SG_INVALID_ID); - T(sg_query_image_state(i3) == SG_RESOURCESTATE_INVALID); - - /* before destroying, the resources must be either in valid or failed state */ - for (int i = 0; i < 3; i++) { - sg_fail_image(img[i]); - T(sg_query_image_state(img[i]) == SG_RESOURCESTATE_FAILED); - } - for (int i = 0; i < 3; i++) { - sg_destroy_image(img[i]); - T(sg_query_image_state(img[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.image_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_fail_destroy_samplers) { - setup(&(sg_desc){ - .sampler_pool_size = 3, - }); - - sg_sampler smp[3] = { {0} }; - for (int i = 0; i < 3; i++) { - smp[i] = sg_alloc_sampler(); - T(smp[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.sampler_pool.queue_top); - T(sg_query_sampler_state(smp[i]) == SG_RESOURCESTATE_ALLOC); - } - // the next alloc will fail because the pool is exhausted - sg_sampler s3 = sg_alloc_sampler(); - T(s3.id == SG_INVALID_ID); - T(sg_query_sampler_state(s3) == SG_RESOURCESTATE_INVALID); - - // before destroying, the resources must be either in valid or failed state - for (int i = 0; i < 3; i++) { - sg_fail_sampler(smp[i]); - T(sg_query_sampler_state(smp[i]) == SG_RESOURCESTATE_FAILED); - } - for (int i = 0; i < 3; i++) { - sg_destroy_sampler(smp[i]); - T(sg_query_sampler_state(smp[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.sampler_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_fail_destroy_shaders) { - setup(&(sg_desc){ - .shader_pool_size = 3 - }); - T(sg_isvalid()); - - sg_shader shd[3] = { {0} }; - for (int i = 0; i < 3; i++) { - shd[i] = sg_alloc_shader(); - T(shd[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.shader_pool.queue_top); - T(sg_query_shader_state(shd[i]) == SG_RESOURCESTATE_ALLOC); - } - /* the next alloc will fail because the pool is exhausted */ - sg_shader s3 = sg_alloc_shader(); - T(s3.id == SG_INVALID_ID); - T(sg_query_shader_state(s3) == SG_RESOURCESTATE_INVALID); - - /* before destroying, the resources must be either in valid or failed state */ - for (int i = 0; i < 3; i++) { - sg_fail_shader(shd[i]); - T(sg_query_shader_state(shd[i]) == SG_RESOURCESTATE_FAILED); - } - for (int i = 0; i < 3; i++) { - sg_destroy_shader(shd[i]); - T(sg_query_shader_state(shd[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.shader_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_fail_destroy_pipelines) { - setup(&(sg_desc){ - .pipeline_pool_size = 3 - }); - T(sg_isvalid()); - - sg_pipeline pip[3] = { {0} }; - for (int i = 0; i < 3; i++) { - pip[i] = sg_alloc_pipeline(); - T(pip[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.pipeline_pool.queue_top); - T(sg_query_pipeline_state(pip[i]) == SG_RESOURCESTATE_ALLOC); - } - - /* the next alloc will fail because the pool is exhausted */ - sg_pipeline p3 = sg_alloc_pipeline(); - T(p3.id == SG_INVALID_ID); - T(sg_query_pipeline_state(p3) == SG_RESOURCESTATE_INVALID); - - /* before destroying, the resources must be either in valid or failed state */ - for (int i = 0; i < 3; i++) { - sg_fail_pipeline(pip[i]); - T(sg_query_pipeline_state(pip[i]) == SG_RESOURCESTATE_FAILED); - } - for (int i = 0; i < 3; i++) { - sg_destroy_pipeline(pip[i]); - T(sg_query_pipeline_state(pip[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.pipeline_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_fail_destroy_attachments) { - setup(&(sg_desc){ - .attachments_pool_size = 3 - }); - T(sg_isvalid()); - - sg_attachments atts[3] = { {0} }; - for (int i = 0; i < 3; i++) { - atts[i] = sg_alloc_attachments(); - T(atts[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.attachments_pool.queue_top); - T(sg_query_attachments_state(atts[i]) == SG_RESOURCESTATE_ALLOC); - } - /* the next alloc will fail because the pool is exhausted */ - sg_attachments a3 = sg_alloc_attachments(); - T(a3.id == SG_INVALID_ID); - T(sg_query_attachments_state(a3) == SG_RESOURCESTATE_INVALID); - - /* before destroying, the resources must be either in valid or failed state */ - for (int i = 0; i < 3; i++) { - sg_fail_attachments(atts[i]); - T(sg_query_attachments_state(atts[i]) == SG_RESOURCESTATE_FAILED); - } - for (int i = 0; i < 3; i++) { - sg_destroy_attachments(atts[i]); - T(sg_query_attachments_state(atts[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.attachments_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, make_destroy_buffers) { - setup(&(sg_desc){ - .buffer_pool_size = 3 - }); - T(sg_isvalid()); - - float data[] = { 1.0f, 2.0f, 3.0f, 4.0f }; - - sg_buffer buf[3] = { {0} }; - sg_buffer_desc desc = { .data = SG_RANGE(data) }; - for (int i = 0; i < 3; i++) { - buf[i] = sg_make_buffer(&desc); - T(buf[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.buffer_pool.queue_top); - T(sg_query_buffer_state(buf[i]) == SG_RESOURCESTATE_VALID); - const _sg_buffer_t* bufptr = _sg_lookup_buffer(&_sg.pools, buf[i].id); - T(bufptr); - T(bufptr->slot.id == buf[i].id); - T(bufptr->slot.state == SG_RESOURCESTATE_VALID); - T(bufptr->cmn.size == sizeof(data)); - T(bufptr->cmn.append_pos == 0); - T(!bufptr->cmn.append_overflow); - T(bufptr->cmn.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(bufptr->cmn.usage == SG_USAGE_IMMUTABLE); - T(bufptr->cmn.update_frame_index == 0); - T(bufptr->cmn.append_frame_index == 0); - T(bufptr->cmn.num_slots == 1); - T(bufptr->cmn.active_slot == 0); - } - /* trying to create another one fails because pool is exhausted */ - T(sg_make_buffer(&desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sg_destroy_buffer(buf[i]); - T(sg_query_buffer_state(buf[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.buffer_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, make_destroy_images) { - setup(&(sg_desc){ - .image_pool_size = 3 - }); - T(sg_isvalid()); - - uint32_t data[8*8] = { 0 }; - - sg_image img[3] = { {0} }; - sg_image_desc desc = { - .width = 8, - .height = 8, - .data.subimage[0][0] = SG_RANGE(data) - }; - for (int i = 0; i < 3; i++) { - img[i] = sg_make_image(&desc); - T(img[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.image_pool.queue_top); - T(sg_query_image_state(img[i]) == SG_RESOURCESTATE_VALID); - const _sg_image_t* imgptr = _sg_lookup_image(&_sg.pools, img[i].id); - T(imgptr); - T(imgptr->slot.id == img[i].id); - T(imgptr->slot.state == SG_RESOURCESTATE_VALID); - T(imgptr->cmn.type == SG_IMAGETYPE_2D); - T(!imgptr->cmn.render_target); - T(imgptr->cmn.width == 8); - T(imgptr->cmn.height == 8); - T(imgptr->cmn.num_slices == 1); - T(imgptr->cmn.num_mipmaps == 1); - T(imgptr->cmn.usage == SG_USAGE_IMMUTABLE); - T(imgptr->cmn.pixel_format == SG_PIXELFORMAT_RGBA8); - T(imgptr->cmn.sample_count == 1); - T(imgptr->cmn.upd_frame_index == 0); - T(imgptr->cmn.num_slots == 1); - T(imgptr->cmn.active_slot == 0); - } - // trying to create another one fails because pool is exhausted - T(sg_make_image(&desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sg_destroy_image(img[i]); - T(sg_query_image_state(img[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.image_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, make_destroy_samplers) { - setup(&(sg_desc){ - .sampler_pool_size = 3 - }); - T(sg_isvalid()); - - sg_sampler smp[3] = { {0} }; - sg_sampler_desc desc = { 0 }; - for (int i = 0; i < 3; i++) { - smp[i] = sg_make_sampler(&desc); - T(smp[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.sampler_pool.queue_top); - T(sg_query_sampler_state(smp[i]) == SG_RESOURCESTATE_VALID); - const _sg_sampler_t* smpptr = _sg_lookup_sampler(&_sg.pools, smp[i].id); - T(smpptr); - T(smpptr->slot.id == smp[i].id); - T(smpptr->slot.state == SG_RESOURCESTATE_VALID); - T(smpptr->cmn.min_filter == SG_FILTER_NEAREST); - T(smpptr->cmn.mag_filter == SG_FILTER_NEAREST); - T(smpptr->cmn.mipmap_filter == SG_FILTER_NONE); - T(smpptr->cmn.wrap_u == SG_WRAP_REPEAT); - T(smpptr->cmn.wrap_v == SG_WRAP_REPEAT); - T(smpptr->cmn.wrap_w == SG_WRAP_REPEAT); - T(smpptr->cmn.min_lod == 0.0f); - T(smpptr->cmn.max_lod == FLT_MAX); - T(smpptr->cmn.border_color == SG_BORDERCOLOR_OPAQUE_BLACK); - T(smpptr->cmn.compare == SG_COMPAREFUNC_NEVER); - T(smpptr->cmn.max_anisotropy == 1); - } - // trying to create another one fails because pool is exhausted - T(sg_make_sampler(&desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sg_destroy_sampler(smp[i]); - T(sg_query_sampler_state(smp[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.sampler_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, make_destroy_shaders) { - setup(&(sg_desc){ - .shader_pool_size = 3 - }); - T(sg_isvalid()); - - sg_shader shd[3] = { {0} }; - sg_shader_desc desc = { - .vs.uniform_blocks[0] = { - .size = 16 - } - }; - for (int i = 0; i < 3; i++) { - shd[i] = sg_make_shader(&desc); - T(shd[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.shader_pool.queue_top); - T(sg_query_shader_state(shd[i]) == SG_RESOURCESTATE_VALID); - const _sg_shader_t* shdptr = _sg_lookup_shader(&_sg.pools, shd[i].id); - T(shdptr); - T(shdptr->slot.id == shd[i].id); - T(shdptr->slot.state == SG_RESOURCESTATE_VALID); - T(shdptr->cmn.stage[SG_SHADERSTAGE_VS].num_uniform_blocks == 1); - T(shdptr->cmn.stage[SG_SHADERSTAGE_VS].num_images == 0); - T(shdptr->cmn.stage[SG_SHADERSTAGE_VS].uniform_blocks[0].size == 16); - T(shdptr->cmn.stage[SG_SHADERSTAGE_FS].num_uniform_blocks == 0); - T(shdptr->cmn.stage[SG_SHADERSTAGE_FS].num_images == 0); - } - /* trying to create another one fails because pool is exhausted */ - T(sg_make_shader(&desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sg_destroy_shader(shd[i]); - T(sg_query_shader_state(shd[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.shader_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, make_destroy_pipelines) { - setup(&(sg_desc){ - .pipeline_pool_size = 3 - }); - T(sg_isvalid()); - - sg_pipeline pip[3] = { {0} }; - sg_pipeline_desc desc = { - .shader = sg_make_shader(&(sg_shader_desc){ 0 }), - .layout = { - .attrs = { - [0] = { .format=SG_VERTEXFORMAT_FLOAT3 }, - [1] = { .format=SG_VERTEXFORMAT_FLOAT4 } - } - }, - }; - for (int i = 0; i < 3; i++) { - pip[i] = sg_make_pipeline(&desc); - T(pip[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.pipeline_pool.queue_top); - T(sg_query_pipeline_state(pip[i]) == SG_RESOURCESTATE_VALID); - const _sg_pipeline_t* pipptr = _sg_lookup_pipeline(&_sg.pools, pip[i].id); - T(pipptr); - T(pipptr->slot.id == pip[i].id); - T(pipptr->slot.state == SG_RESOURCESTATE_VALID); - T(pipptr->shader == _sg_lookup_shader(&_sg.pools, desc.shader.id)); - T(pipptr->cmn.shader_id.id == desc.shader.id); - T(pipptr->cmn.color_count == 1); - T(pipptr->cmn.colors[0].pixel_format == SG_PIXELFORMAT_RGBA8); - T(pipptr->cmn.depth.pixel_format == SG_PIXELFORMAT_DEPTH_STENCIL); - T(pipptr->cmn.sample_count == 1); - T(pipptr->cmn.index_type == SG_INDEXTYPE_NONE); - T(pipptr->cmn.vertex_buffer_layout_active[0]); - T(!pipptr->cmn.vertex_buffer_layout_active[1]); - } - /* trying to create another one fails because pool is exhausted */ - T(sg_make_pipeline(&desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sg_destroy_pipeline(pip[i]); - T(sg_query_pipeline_state(pip[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.pipeline_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, make_destroy_attachments) { - setup(&(sg_desc){ - .attachments_pool_size = 3 - }); - T(sg_isvalid()); - - sg_attachments atts[3] = { {0} }; - - sg_image_desc img_desc = { - .render_target = true, - .width = 128, - .height = 128, - }; - sg_attachments_desc atts_desc = (sg_attachments_desc){ - .colors = { - [0].image = sg_make_image(&img_desc), - [1].image = sg_make_image(&img_desc), - [2].image = sg_make_image(&img_desc) - }, - }; - for (int i = 0; i < 3; i++) { - atts[i] = sg_make_attachments(&atts_desc); - T(atts[i].id != SG_INVALID_ID); - T((2-i) == _sg.pools.attachments_pool.queue_top); - T(sg_query_attachments_state(atts[i]) == SG_RESOURCESTATE_VALID); - const _sg_attachments_t* attsptr = _sg_lookup_attachments(&_sg.pools, atts[i].id); - T(attsptr); - T(attsptr->slot.id == atts[i].id); - T(attsptr->slot.state == SG_RESOURCESTATE_VALID); - T(attsptr->cmn.num_colors == 3); - for (int ai = 0; ai < 3; ai++) { - const _sg_image_t* img = _sg_attachments_color_image(attsptr, ai); - T(img == _sg_lookup_image(&_sg.pools, atts_desc.colors[ai].image.id)); - T(attsptr->cmn.colors[ai].image_id.id == atts_desc.colors[ai].image.id); - } - } - /* trying to create another one fails because pool is exhausted */ - T(sg_make_attachments(&atts_desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sg_destroy_attachments(atts[i]); - T(sg_query_attachments_state(atts[i]) == SG_RESOURCESTATE_INVALID); - T((i+1) == _sg.pools.attachments_pool.queue_top); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, generation_counter) { - setup(&(sg_desc){ - .buffer_pool_size = 1, - }); - - static float data[] = { 1.0f, 2.0f, 3.0f, 4.0f }; - for (int i = 0; i < 64; i++) { - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(data) }); - T(buf.id != SG_INVALID_ID); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID); - T((buf.id >> 16) == (uint32_t)(i + 1)); /* this is the generation counter */ - T(_sg_slot_index(buf.id) == 1); /* slot index should remain the same */ - sg_destroy_buffer(buf); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, query_buffer_defaults) { - setup(&(sg_desc){0}); - sg_buffer_desc desc; - desc = sg_query_buffer_defaults(&(sg_buffer_desc){0}); - T(desc.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(desc.usage == SG_USAGE_IMMUTABLE); - desc = sg_query_buffer_defaults(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_INDEXBUFFER, - }); - T(desc.type == SG_BUFFERTYPE_INDEXBUFFER); - T(desc.usage == SG_USAGE_IMMUTABLE); - desc = sg_query_buffer_defaults(&(sg_buffer_desc){ - .usage = SG_USAGE_DYNAMIC - }); - T(desc.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(desc.usage == SG_USAGE_DYNAMIC); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_image_defaults) { - setup(&(sg_desc){0}); - const sg_image_desc desc = sg_query_image_defaults(&(sg_image_desc){0}); - T(desc.type == SG_IMAGETYPE_2D); - T(!desc.render_target); - T(desc.num_mipmaps == 1); - T(desc.usage == SG_USAGE_IMMUTABLE); - T(desc.pixel_format == SG_PIXELFORMAT_RGBA8); - T(desc.sample_count == 1); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_sampler_defaults) { - setup(&(sg_desc){0}); - const sg_sampler_desc desc = sg_query_sampler_defaults(&(sg_sampler_desc){0}); - T(desc.min_filter == SG_FILTER_NEAREST); - T(desc.mag_filter == SG_FILTER_NEAREST); - T(desc.mipmap_filter == SG_FILTER_NONE); - T(desc.wrap_u == SG_WRAP_REPEAT); - T(desc.wrap_v == SG_WRAP_REPEAT); - T(desc.wrap_w == SG_WRAP_REPEAT); - T(desc.min_lod == 0.0f); - T(desc.max_lod == FLT_MAX); - T(desc.border_color == SG_BORDERCOLOR_OPAQUE_BLACK); - T(desc.compare == SG_COMPAREFUNC_NEVER); - T(desc.max_anisotropy == 1); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_shader_defaults) { - setup(&(sg_desc){0}); - const sg_shader_desc desc = sg_query_shader_defaults(&(sg_shader_desc){0}); - T(0 == strcmp(desc.vs.entry, "main")); - T(0 == strcmp(desc.fs.entry, "main")); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_pipeline_defaults) { - setup(&(sg_desc){0}); - const sg_pipeline_desc desc = sg_query_pipeline_defaults(&(sg_pipeline_desc){ - .layout.attrs = { - [0].format = SG_VERTEXFORMAT_FLOAT3, - [1].format = SG_VERTEXFORMAT_FLOAT4 - } - }); - T(desc.layout.buffers[0].stride == 28); - T(desc.layout.buffers[0].step_rate == 1); - T(desc.layout.buffers[0].step_func == SG_VERTEXSTEP_PER_VERTEX); - T(desc.layout.attrs[0].offset == 0); - T(desc.layout.attrs[0].buffer_index == 0); - T(desc.layout.attrs[0].format == SG_VERTEXFORMAT_FLOAT3); - T(desc.layout.attrs[1].offset == 12); - T(desc.layout.attrs[1].buffer_index == 0); - T(desc.layout.attrs[1].format == SG_VERTEXFORMAT_FLOAT4); - T(desc.stencil.front.fail_op == SG_STENCILOP_KEEP); - T(desc.stencil.front.depth_fail_op == SG_STENCILOP_KEEP); - T(desc.stencil.front.pass_op == SG_STENCILOP_KEEP); - T(desc.stencil.front.compare == SG_COMPAREFUNC_ALWAYS); - T(desc.stencil.back.fail_op == SG_STENCILOP_KEEP); - T(desc.stencil.back.depth_fail_op == SG_STENCILOP_KEEP); - T(desc.stencil.back.pass_op == SG_STENCILOP_KEEP); - T(desc.stencil.back.compare == SG_COMPAREFUNC_ALWAYS); - T(desc.stencil.enabled == false); - T(desc.stencil.read_mask == 0); - T(desc.stencil.write_mask == 0); - T(desc.stencil.ref == 0); - T(desc.depth.pixel_format == SG_PIXELFORMAT_DEPTH_STENCIL); - T(desc.depth.compare == SG_COMPAREFUNC_ALWAYS); - T(desc.depth.write_enabled == false); - T(desc.depth.bias == 0); - T(desc.depth.bias_slope_scale == 0); - T(desc.depth.bias_clamp == 0); - T(desc.color_count == 1); - T(desc.colors[0].pixel_format == SG_PIXELFORMAT_RGBA8); - T(desc.colors[0].write_mask == 0xF); - T(desc.colors[0].blend.enabled == false); - T(desc.colors[0].blend.src_factor_rgb == SG_BLENDFACTOR_ONE); - T(desc.colors[0].blend.dst_factor_rgb == SG_BLENDFACTOR_ZERO); - T(desc.colors[0].blend.op_rgb == SG_BLENDOP_ADD); - T(desc.colors[0].blend.src_factor_alpha == SG_BLENDFACTOR_ONE); - T(desc.colors[0].blend.dst_factor_alpha == SG_BLENDFACTOR_ZERO); - T(desc.colors[0].blend.op_alpha == SG_BLENDOP_ADD); - T(desc.alpha_to_coverage_enabled == false); - T(desc.primitive_type == SG_PRIMITIVETYPE_TRIANGLES); - T(desc.index_type == SG_INDEXTYPE_NONE); - T(desc.cull_mode == SG_CULLMODE_NONE); - T(desc.face_winding == SG_FACEWINDING_CW); - T(desc.sample_count == 1); - sg_shutdown(); -} - -// test that color attachment defaults are set in all attachments -UTEST(sokol_gfx, query_mrt_pipeline_defaults) { - setup(&(sg_desc){0}); - const sg_pipeline_desc desc = sg_query_pipeline_defaults(&(sg_pipeline_desc){ - .color_count = 3, - }); - T(desc.color_count == 3); - for (int i = 0; i < desc.color_count; i++) { - T(desc.colors[i].pixel_format == SG_PIXELFORMAT_RGBA8); - T(desc.colors[i].write_mask == 0xF); - T(desc.colors[i].blend.enabled == false); - T(desc.colors[i].blend.src_factor_rgb == SG_BLENDFACTOR_ONE); - T(desc.colors[i].blend.dst_factor_rgb == SG_BLENDFACTOR_ZERO); - T(desc.colors[i].blend.op_rgb == SG_BLENDOP_ADD); - T(desc.colors[i].blend.src_factor_alpha == SG_BLENDFACTOR_ONE); - T(desc.colors[i].blend.dst_factor_alpha == SG_BLENDFACTOR_ZERO); - T(desc.colors[i].blend.op_alpha == SG_BLENDOP_ADD); - }; - sg_shutdown(); -} - -// test that first color attachment values are duplicated to other attachments -UTEST(sokol_gfx, multiple_color_state) { - setup(&(sg_desc){0}); - const sg_pipeline_desc desc = sg_query_pipeline_defaults(&(sg_pipeline_desc){ - .color_count = 3, - .colors = { - [0] = { - .pixel_format = SG_PIXELFORMAT_R8, - .write_mask = SG_COLORMASK_BA, - .blend = { - .enabled = true, - .src_factor_rgb = SG_BLENDFACTOR_SRC_COLOR, - .dst_factor_rgb = SG_BLENDFACTOR_DST_COLOR, - .op_rgb = SG_BLENDOP_SUBTRACT, - .src_factor_alpha = SG_BLENDFACTOR_SRC_ALPHA, - .dst_factor_alpha = SG_BLENDFACTOR_DST_ALPHA, - .op_alpha = SG_BLENDOP_REVERSE_SUBTRACT - } - }, - [2] = { - .pixel_format = SG_PIXELFORMAT_RG8, - .write_mask = SG_COLORMASK_GA, - .blend = { - .enabled = true, - .src_factor_rgb = SG_BLENDFACTOR_DST_COLOR, - .dst_factor_rgb = SG_BLENDFACTOR_SRC_COLOR, - .op_rgb = SG_BLENDOP_REVERSE_SUBTRACT, - .src_factor_alpha = SG_BLENDFACTOR_DST_ALPHA, - .dst_factor_alpha = SG_BLENDFACTOR_SRC_ALPHA, - .op_alpha = SG_BLENDOP_SUBTRACT - } - }, - } - }); - T(desc.color_count == 3); - - T(desc.colors[0].pixel_format == SG_PIXELFORMAT_R8); - T(desc.colors[0].write_mask == SG_COLORMASK_BA); - T(desc.colors[0].blend.enabled == true); - T(desc.colors[0].blend.src_factor_rgb == SG_BLENDFACTOR_SRC_COLOR); - T(desc.colors[0].blend.dst_factor_rgb == SG_BLENDFACTOR_DST_COLOR); - T(desc.colors[0].blend.op_rgb == SG_BLENDOP_SUBTRACT); - T(desc.colors[0].blend.src_factor_alpha == SG_BLENDFACTOR_SRC_ALPHA); - T(desc.colors[0].blend.dst_factor_alpha == SG_BLENDFACTOR_DST_ALPHA); - T(desc.colors[0].blend.op_alpha == SG_BLENDOP_REVERSE_SUBTRACT); - - T(desc.colors[1].pixel_format == SG_PIXELFORMAT_RGBA8); - T(desc.colors[1].write_mask == SG_COLORMASK_RGBA); - T(desc.colors[1].blend.enabled == false); - T(desc.colors[1].blend.src_factor_rgb == SG_BLENDFACTOR_ONE); - T(desc.colors[1].blend.dst_factor_rgb == SG_BLENDFACTOR_ZERO); - T(desc.colors[1].blend.op_rgb == SG_BLENDOP_ADD); - T(desc.colors[1].blend.src_factor_alpha == SG_BLENDFACTOR_ONE); - T(desc.colors[1].blend.dst_factor_alpha == SG_BLENDFACTOR_ZERO); - T(desc.colors[1].blend.op_alpha == SG_BLENDOP_ADD); - - T(desc.colors[2].pixel_format == SG_PIXELFORMAT_RG8); - T(desc.colors[2].write_mask == SG_COLORMASK_GA); - T(desc.colors[2].blend.enabled == true); - T(desc.colors[2].blend.src_factor_rgb == SG_BLENDFACTOR_DST_COLOR); - T(desc.colors[2].blend.dst_factor_rgb == SG_BLENDFACTOR_SRC_COLOR); - T(desc.colors[2].blend.op_rgb == SG_BLENDOP_REVERSE_SUBTRACT); - T(desc.colors[2].blend.src_factor_alpha == SG_BLENDFACTOR_DST_ALPHA); - T(desc.colors[2].blend.dst_factor_alpha == SG_BLENDFACTOR_SRC_ALPHA); - T(desc.colors[2].blend.op_alpha == SG_BLENDOP_SUBTRACT); - - sg_shutdown(); -} - -UTEST(sokol_gfx, query_attachments_defaults) { - setup(&(sg_desc){0}); - /* sg_attachments_desc doesn't actually have any meaningful default values */ - const sg_attachments_desc desc = sg_query_attachments_defaults(&(sg_attachments_desc){0}); - T(desc.colors[0].image.id == SG_INVALID_ID); - T(desc.colors[0].mip_level == 0); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_buffer_info) { - setup(&(sg_desc){0}); - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - .size = 256, - .type = SG_BUFFERTYPE_VERTEXBUFFER, - .usage = SG_USAGE_STREAM - }); - T(buf.id != SG_INVALID_ID); - const sg_buffer_info info = sg_query_buffer_info(buf); - T(info.slot.state == SG_RESOURCESTATE_VALID); - T(info.slot.res_id == buf.id); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_image_info) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 128 - }); - T(img.id != SG_INVALID_ID); - const sg_image_info info = sg_query_image_info(img); - T(info.slot.state == SG_RESOURCESTATE_VALID); - T(info.slot.res_id == img.id); - T(info.num_slots == 1); - sg_shutdown(); -} - -UTEST(sokoL_gfx, query_sampler_info) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){ 0 }); - T(smp.id != SG_INVALID_ID); - const sg_sampler_info info = sg_query_sampler_info(smp); - T(info.slot.state == SG_RESOURCESTATE_VALID); - T(info.slot.res_id == smp.id); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_shader_info) { - setup(&(sg_desc){0}); - sg_shader shd = sg_make_shader(&(sg_shader_desc){ - .attrs = { - [0] = { .name = "pos" } - }, - .vs.source = "bla", - .fs.source = "blub" - }); - const sg_shader_info info = sg_query_shader_info(shd); - T(info.slot.state == SG_RESOURCESTATE_VALID); - T(info.slot.res_id == shd.id); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_pipeline_info) { - setup(&(sg_desc){0}); - sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .attrs[0].format = SG_VERTEXFORMAT_FLOAT3 - }, - .shader = sg_make_shader(&(sg_shader_desc){ - .attrs = { - [0] = { .name = "pos" } - }, - .vs.source = "bla", - .fs.source = "blub" - }) - }); - const sg_pipeline_info info = sg_query_pipeline_info(pip); - T(info.slot.state == SG_RESOURCESTATE_VALID); - T(info.slot.res_id == pip.id); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_attachments_info) { - setup(&(sg_desc){0}); - sg_image_desc img_desc = { - .render_target = true, - .width = 128, - .height = 128, - }; - sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = sg_make_image(&img_desc), - [1].image = sg_make_image(&img_desc), - [2].image = sg_make_image(&img_desc) - }, - }); - const sg_attachments_info info = sg_query_attachments_info(atts); - T(info.slot.state == SG_RESOURCESTATE_VALID); - T(info.slot.res_id == atts.id); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_buffer_desc) { - setup(&(sg_desc){0}); - - sg_buffer b0 = sg_make_buffer(&(sg_buffer_desc){ - .size = 32, - .usage = SG_USAGE_STREAM, - .label = "bla", - }); - const sg_buffer_desc b0_desc = sg_query_buffer_desc(b0); - T(b0_desc.size == 32); - T(b0_desc.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(b0_desc.usage == SG_USAGE_STREAM); - T(b0_desc.data.ptr == 0); - T(b0_desc.data.size == 0); - T(b0_desc.gl_buffers[0] == 0); - T(b0_desc.mtl_buffers[0] == 0); - T(b0_desc.d3d11_buffer == 0); - T(b0_desc.wgpu_buffer == 0); - - float vtx_data[16]; - sg_buffer b1 = sg_make_buffer(&(sg_buffer_desc){ - .data = SG_RANGE(vtx_data) - }); - const sg_buffer_desc b1_desc = sg_query_buffer_desc(b1); - T(b1_desc.size == sizeof(vtx_data)); - T(b1_desc.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(b1_desc.usage == SG_USAGE_IMMUTABLE); - T(b1_desc.data.ptr == 0); - T(b1_desc.data.size == 0); - - uint16_t idx_data[8]; - sg_buffer b2 = sg_make_buffer(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_INDEXBUFFER, - .data = SG_RANGE(idx_data), - }); - const sg_buffer_desc b2_desc = sg_query_buffer_desc(b2); - T(b2_desc.size == sizeof(idx_data)); - T(b2_desc.type == SG_BUFFERTYPE_INDEXBUFFER); - T(b2_desc.usage == SG_USAGE_IMMUTABLE); - T(b2_desc.data.ptr == 0); - T(b2_desc.data.size == 0); - - // invalid buffer (returns zeroed desc) - sg_buffer b3 = sg_make_buffer(&(sg_buffer_desc){ - .size = 32, - .usage = SG_USAGE_STREAM, - .label = "bla", - }); - sg_destroy_buffer(b3); - const sg_buffer_desc b3_desc = sg_query_buffer_desc(b3); - T(b3_desc.size == 0); - T(b3_desc.type == 0); - T(b3_desc.usage == 0); - - sg_shutdown(); -} - -UTEST(sokol_gfx, query_image_desc) { - setup(&(sg_desc){0}); - - sg_image i0 = sg_make_image(&(sg_image_desc){ - .width = 256, - .height = 512, - .pixel_format = SG_PIXELFORMAT_R8, - .usage = SG_USAGE_DYNAMIC, - }); - const sg_image_desc i0_desc = sg_query_image_desc(i0); - T(i0_desc.type == SG_IMAGETYPE_2D); - T(i0_desc.render_target == false); - T(i0_desc.width == 256); - T(i0_desc.height == 512); - T(i0_desc.num_slices == 1); - T(i0_desc.num_mipmaps == 1); - T(i0_desc.usage == SG_USAGE_DYNAMIC); - T(i0_desc.pixel_format == SG_PIXELFORMAT_R8); - T(i0_desc.sample_count == 1); - T(i0_desc.data.subimage[0][0].ptr == 0); - T(i0_desc.data.subimage[0][0].size == 0); - T(i0_desc.gl_textures[0] == 0); - T(i0_desc.gl_texture_target == 0); - T(i0_desc.mtl_textures[0] == 0); - T(i0_desc.d3d11_texture == 0); - T(i0_desc.d3d11_shader_resource_view == 0); - T(i0_desc.wgpu_texture == 0); - - sg_destroy_image(i0); - const sg_image_desc i0_desc_x = sg_query_image_desc(i0); - T(i0_desc_x.type == 0); - T(i0_desc_x.render_target == false); - T(i0_desc_x.width == 0); - T(i0_desc_x.height == 0); - T(i0_desc_x.num_slices == 0); - T(i0_desc_x.num_mipmaps == 0); - T(i0_desc_x.usage == 0); - T(i0_desc_x.pixel_format == 0); - T(i0_desc_x.sample_count == 0); - - sg_shutdown(); -} - -UTEST(sokol_gfx, query_sampler_desc) { - setup(&(sg_desc){0}); - sg_sampler s0 = sg_make_sampler(&(sg_sampler_desc){ - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .mipmap_filter = SG_FILTER_LINEAR, - .wrap_v = SG_WRAP_MIRRORED_REPEAT, - .max_anisotropy = 8, - .border_color = SG_BORDERCOLOR_TRANSPARENT_BLACK, - .compare = SG_COMPAREFUNC_GREATER, - }); - const sg_sampler_desc s0_desc = sg_query_sampler_desc(s0); - T(s0_desc.min_filter == SG_FILTER_LINEAR); - T(s0_desc.mag_filter == SG_FILTER_LINEAR); - T(s0_desc.mipmap_filter == SG_FILTER_LINEAR); - T(s0_desc.wrap_u == SG_WRAP_REPEAT); - T(s0_desc.wrap_v == SG_WRAP_MIRRORED_REPEAT); - T(s0_desc.wrap_w == SG_WRAP_REPEAT); - T(s0_desc.min_lod == 0.0f); - T(s0_desc.max_lod == FLT_MAX); - T(s0_desc.border_color == SG_BORDERCOLOR_TRANSPARENT_BLACK); - T(s0_desc.compare == SG_COMPAREFUNC_GREATER); - T(s0_desc.max_anisotropy == 8); - - sg_destroy_sampler(s0); - const sg_sampler_desc s0_desc_x = sg_query_sampler_desc(s0); - T(s0_desc_x.min_filter == 0); - T(s0_desc_x.compare == 0); - - sg_shutdown(); -} - -UTEST(sokol_gfx, query_shader_desc) { - setup(&(sg_desc){0}); - - sg_shader s0 = sg_make_shader(&(sg_shader_desc){ - .attrs = { - [0] = { .name = "pos", .sem_name = "POS", .sem_index = 1 }, - }, - .vs = { - .source = "vs_source", - .uniform_blocks = { - [0] = { - .size = 128, - .layout = SG_UNIFORMLAYOUT_STD140, - .uniforms = { - [0] = { .name = "blub", .type = SG_UNIFORMTYPE_FLOAT4, .array_count = 1 }, - [1] = { .name = "blob", .type = SG_UNIFORMTYPE_FLOAT2, .array_count = 1 }, - } - } - }, - .images[0] = { .used = true, .image_type = SG_IMAGETYPE_2D, .sample_type = SG_IMAGESAMPLETYPE_FLOAT, .multisampled = true }, - .images[1] = { .used = true, .image_type = SG_IMAGETYPE_3D, .sample_type = SG_IMAGESAMPLETYPE_DEPTH }, - .samplers[0] = { .used = true, .sampler_type = SG_SAMPLERTYPE_FILTERING }, - .samplers[1] = { .used = true, .sampler_type = SG_SAMPLERTYPE_COMPARISON }, - .image_sampler_pairs[0] = { .used = true, .image_slot = 0, .sampler_slot = 0, .glsl_name = "img0" }, - .image_sampler_pairs[1] = { .used = true, .image_slot = 1, .sampler_slot = 1, .glsl_name = "img1" }, - }, - .fs = { - .source = "fs_source", - .images[0] = { .used = true, .image_type = SG_IMAGETYPE_ARRAY, .sample_type = SG_IMAGESAMPLETYPE_DEPTH }, - .images[1] = { .used = true, .image_type = SG_IMAGETYPE_CUBE, .sample_type = SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT }, - .samplers[0] = { .used = true, .sampler_type = SG_SAMPLERTYPE_COMPARISON }, - .samplers[1] = { .used = true, .sampler_type = SG_SAMPLERTYPE_NONFILTERING }, - .image_sampler_pairs[0] = { .used = true, .image_slot = 0, .sampler_slot = 0, .glsl_name = "img3" }, - .image_sampler_pairs[1] = { .used = true, .image_slot = 1, .sampler_slot = 1, .glsl_name = "img4" }, - }, - .label = "label", - }); - const sg_shader_desc s0_desc = sg_query_shader_desc(s0); - T(s0_desc.attrs[0].name == 0); - T(s0_desc.attrs[0].sem_name == 0); - T(s0_desc.attrs[0].sem_index == 0); - T(s0_desc.vs.source == 0); - T(s0_desc.vs.uniform_blocks[0].size == 128); - T(s0_desc.vs.uniform_blocks[0].layout == 0); - T(s0_desc.vs.uniform_blocks[0].uniforms[0].name == 0); - T(s0_desc.vs.uniform_blocks[0].uniforms[0].type == 0); - T(s0_desc.vs.uniform_blocks[0].uniforms[0].array_count == 0); - T(s0_desc.vs.images[0].used); - T(s0_desc.vs.images[0].image_type == SG_IMAGETYPE_2D); - T(s0_desc.vs.images[0].sample_type == SG_IMAGESAMPLETYPE_FLOAT); - T(s0_desc.vs.images[0].multisampled); - T(s0_desc.vs.images[1].used); - T(s0_desc.vs.images[1].image_type == SG_IMAGETYPE_3D); - T(s0_desc.vs.images[1].sample_type == SG_IMAGESAMPLETYPE_DEPTH); - T(s0_desc.vs.images[1].multisampled == false); - T(s0_desc.vs.samplers[0].used); - T(s0_desc.vs.samplers[0].sampler_type == SG_SAMPLERTYPE_FILTERING); - T(s0_desc.vs.samplers[1].used); - T(s0_desc.vs.samplers[1].sampler_type == SG_SAMPLERTYPE_COMPARISON); - T(s0_desc.vs.image_sampler_pairs[0].used); - T(s0_desc.vs.image_sampler_pairs[0].image_slot == 0); - T(s0_desc.vs.image_sampler_pairs[0].sampler_slot == 0); - T(s0_desc.vs.image_sampler_pairs[0].glsl_name == 0); - T(s0_desc.vs.image_sampler_pairs[1].used); - T(s0_desc.vs.image_sampler_pairs[1].image_slot == 1); - T(s0_desc.vs.image_sampler_pairs[1].sampler_slot == 1); - T(s0_desc.vs.image_sampler_pairs[1].glsl_name == 0); - T(s0_desc.fs.source == 0); - T(s0_desc.fs.uniform_blocks[0].size == 0); - T(s0_desc.fs.uniform_blocks[0].layout == 0); - T(s0_desc.fs.uniform_blocks[0].uniforms[0].name == 0); - T(s0_desc.fs.uniform_blocks[0].uniforms[0].type == 0); - T(s0_desc.fs.uniform_blocks[0].uniforms[0].array_count == 0); - T(s0_desc.fs.images[0].used); - T(s0_desc.fs.images[0].image_type == SG_IMAGETYPE_ARRAY); - T(s0_desc.fs.images[0].sample_type == SG_IMAGESAMPLETYPE_DEPTH); - T(s0_desc.fs.images[0].multisampled == false); - T(s0_desc.fs.images[1].used); - T(s0_desc.fs.images[1].image_type == SG_IMAGETYPE_CUBE); - T(s0_desc.fs.images[1].sample_type == SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT); - T(s0_desc.fs.images[1].multisampled == false); - T(s0_desc.fs.samplers[0].used); - T(s0_desc.fs.samplers[0].sampler_type == SG_SAMPLERTYPE_COMPARISON); - T(s0_desc.fs.samplers[1].used); - T(s0_desc.fs.samplers[1].sampler_type == SG_SAMPLERTYPE_NONFILTERING); - T(s0_desc.fs.image_sampler_pairs[0].used); - T(s0_desc.fs.image_sampler_pairs[0].image_slot == 0); - T(s0_desc.fs.image_sampler_pairs[0].sampler_slot == 0); - T(s0_desc.fs.image_sampler_pairs[0].glsl_name == 0); - T(s0_desc.fs.image_sampler_pairs[1].used); - T(s0_desc.fs.image_sampler_pairs[1].image_slot == 1); - T(s0_desc.fs.image_sampler_pairs[1].sampler_slot == 1); - T(s0_desc.fs.image_sampler_pairs[1].glsl_name == 0); - - sg_shutdown(); -} - -UTEST(sokol_gfx, query_pipeline_desc) { - setup(&(sg_desc){0}); - - sg_shader shd = sg_make_shader(&(sg_shader_desc){0}); - sg_pipeline p0 = sg_make_pipeline(&(sg_pipeline_desc){ - .shader = shd, - .layout = { - .attrs = { - [0] = { .format = SG_VERTEXFORMAT_FLOAT4 }, - [1] = { .format = SG_VERTEXFORMAT_FLOAT2 }, - } - }, - .label = "p0", - }); - - const sg_pipeline_desc p0_desc = sg_query_pipeline_desc(p0); - T(p0_desc.shader.id == shd.id); - T(p0_desc.layout.buffers[0].stride == 24); - T(p0_desc.layout.buffers[0].step_func == SG_VERTEXSTEP_PER_VERTEX); - T(p0_desc.layout.buffers[0].step_rate == 1); - T(p0_desc.layout.buffers[1].stride == 0); - T(p0_desc.layout.buffers[1].step_func == 0); - T(p0_desc.layout.buffers[1].step_rate == 0); - T(p0_desc.layout.attrs[0].format == SG_VERTEXFORMAT_FLOAT4); - T(p0_desc.layout.attrs[0].offset == 0); - T(p0_desc.layout.attrs[0].buffer_index == 0); - T(p0_desc.layout.attrs[1].format == SG_VERTEXFORMAT_FLOAT2); - T(p0_desc.layout.attrs[1].offset == 16); - T(p0_desc.layout.attrs[1].buffer_index == 0); - T(p0_desc.layout.attrs[2].format == 0); - T(p0_desc.layout.attrs[2].offset == 0); - T(p0_desc.layout.attrs[2].buffer_index == 0); - T(p0_desc.depth.pixel_format == SG_PIXELFORMAT_DEPTH_STENCIL); - T(p0_desc.depth.compare == SG_COMPAREFUNC_ALWAYS); - T(p0_desc.depth.write_enabled == false); - T(p0_desc.depth.bias == 0.0f); - T(p0_desc.depth.bias_slope_scale == 0.0f); - T(p0_desc.depth.bias_clamp == 0.0f); - T(p0_desc.stencil.enabled == false); - T(p0_desc.stencil.front.compare == SG_COMPAREFUNC_ALWAYS); - T(p0_desc.stencil.front.fail_op == SG_STENCILOP_KEEP); - T(p0_desc.stencil.front.depth_fail_op == SG_STENCILOP_KEEP); - T(p0_desc.stencil.front.pass_op == SG_STENCILOP_KEEP); - T(p0_desc.stencil.back.compare == SG_COMPAREFUNC_ALWAYS); - T(p0_desc.stencil.back.fail_op == SG_STENCILOP_KEEP); - T(p0_desc.stencil.back.depth_fail_op == SG_STENCILOP_KEEP); - T(p0_desc.stencil.back.pass_op == SG_STENCILOP_KEEP); - T(p0_desc.stencil.read_mask == 0); - T(p0_desc.stencil.write_mask == 0); - T(p0_desc.stencil.ref == 0); - T(p0_desc.color_count == 1); - T(p0_desc.colors[0].pixel_format == SG_PIXELFORMAT_RGBA8); - T(p0_desc.colors[0].write_mask == SG_COLORMASK_RGBA); - T(p0_desc.colors[0].blend.enabled == false); - T(p0_desc.colors[0].blend.src_factor_rgb == SG_BLENDFACTOR_ONE); - T(p0_desc.colors[0].blend.dst_factor_rgb == SG_BLENDFACTOR_ZERO); - T(p0_desc.colors[0].blend.op_rgb == SG_BLENDOP_ADD); - T(p0_desc.colors[0].blend.src_factor_alpha == SG_BLENDFACTOR_ONE); - T(p0_desc.colors[0].blend.dst_factor_alpha == SG_BLENDFACTOR_ZERO); - T(p0_desc.colors[0].blend.op_alpha == SG_BLENDOP_ADD); - T(p0_desc.primitive_type == SG_PRIMITIVETYPE_TRIANGLES); - T(p0_desc.index_type == SG_INDEXTYPE_NONE); - T(p0_desc.cull_mode == SG_CULLMODE_NONE); - T(p0_desc.face_winding == SG_FACEWINDING_CW); - T(p0_desc.sample_count == 1); - T(p0_desc.blend_color.r == 0.0f); - T(p0_desc.blend_color.g == 0.0f); - T(p0_desc.blend_color.b == 0.0f); - T(p0_desc.blend_color.a == 0.0f); - T(p0_desc.alpha_to_coverage_enabled == false); - T(p0_desc.label == 0); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_attachments_desc) { - setup(&(sg_desc){0}); - - const sg_image_desc color_img_desc = { - .render_target = true, - .width = 128, - .height = 128, - }; - const sg_image_desc depth_img_desc = { - .render_target = true, - .width = 128, - .height = 128, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }; - sg_image color_img_0 = sg_make_image(&color_img_desc); - sg_image color_img_1 = sg_make_image(&color_img_desc); - sg_image color_img_2 = sg_make_image(&color_img_desc); - sg_image depth_img = sg_make_image(&depth_img_desc); - - sg_attachments a0 = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = color_img_0, - [1].image = color_img_1, - [2].image = color_img_2, - }, - .depth_stencil.image = depth_img, - }); - const sg_attachments_desc a0_desc = sg_query_attachments_desc(a0); - T(a0_desc.colors[0].image.id == color_img_0.id); - T(a0_desc.colors[0].mip_level == 0); - T(a0_desc.colors[0].slice == 0); - T(a0_desc.colors[1].image.id == color_img_1.id); - T(a0_desc.colors[1].mip_level == 0); - T(a0_desc.colors[1].slice == 0); - T(a0_desc.colors[2].image.id == color_img_2.id); - T(a0_desc.colors[2].mip_level == 0); - T(a0_desc.colors[2].slice == 0); - T(a0_desc.depth_stencil.image.id == depth_img.id); - T(a0_desc.depth_stencil.mip_level == 0); - T(a0_desc.depth_stencil.slice == 0); - - sg_shutdown(); -} - -UTEST(sokol_gfx, buffer_resource_states) { - setup(&(sg_desc){0}); - sg_buffer buf = sg_alloc_buffer(); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_ALLOC); - sg_init_buffer(buf, &(sg_buffer_desc){ .usage = SG_USAGE_STREAM, .size = 128 }); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID); - sg_uninit_buffer(buf); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_ALLOC); - sg_dealloc_buffer(buf); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, image_resource_states) { - setup(&(sg_desc){0}); - sg_image img = sg_alloc_image(); - T(sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC); - sg_init_image(img, &(sg_image_desc){ .render_target = true, .width = 16, .height = 16 }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_VALID); - sg_uninit_image(img); - T(sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC); - sg_dealloc_image(img); - T(sg_query_image_state(img) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, sampler_resource_states) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_alloc_sampler(); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_ALLOC); - sg_init_sampler(smp, &(sg_sampler_desc){ .min_filter = SG_FILTER_LINEAR, .mag_filter = SG_FILTER_LINEAR }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_VALID); - sg_uninit_sampler(smp); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_ALLOC); - sg_dealloc_sampler(smp); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, shader_resource_states) { - setup(&(sg_desc){0}); - sg_shader shd = sg_alloc_shader(); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_ALLOC); - sg_init_shader(shd, &(sg_shader_desc){0}); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_VALID); - sg_uninit_shader(shd); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_ALLOC); - sg_dealloc_shader(shd); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, pipeline_resource_states) { - setup(&(sg_desc){0}); - sg_pipeline pip = sg_alloc_pipeline(); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_ALLOC); - sg_init_pipeline(pip, &(sg_pipeline_desc){ - .shader = sg_make_shader(&(sg_shader_desc){0}), - .layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT3 - }); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_VALID); - sg_uninit_pipeline(pip); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_ALLOC); - sg_dealloc_pipeline(pip); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, attachments_resource_states) { - setup(&(sg_desc){0}); - sg_attachments atts = sg_alloc_attachments(); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_ALLOC); - sg_init_attachments(atts, &(sg_attachments_desc){ - .colors[0].image = sg_make_image(&(sg_image_desc){ .render_target=true, .width=16, .height=16}) - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_VALID); - sg_uninit_attachments(atts); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_ALLOC); - sg_dealloc_attachments(atts); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_buffer_will_overflow) { - setup(&(sg_desc){0}); - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - .size = 64, - .usage = SG_USAGE_STREAM - }); - T(!sg_query_buffer_will_overflow(buf, 32)); - T(!sg_query_buffer_will_overflow(buf, 64)); - T(sg_query_buffer_will_overflow(buf, 65)); - static const uint8_t data[32] = {0}; - sg_append_buffer(buf, &SG_RANGE(data)); - T(!sg_query_buffer_will_overflow(buf, 32)); - T(sg_query_buffer_will_overflow(buf, 33)); - sg_shutdown(); -} - -static struct { - uintptr_t userdata; - int num_called; -} commit_listener; -static void reset_commit_listener(void) { - commit_listener.userdata = 0; - commit_listener.num_called = 0; -} -static void commit_listener_func(void* ud) { - commit_listener.userdata = (uintptr_t)ud; - commit_listener.num_called++; -} - -UTEST(sokol_gfx, commit_listener_called) { - reset_commit_listener(); - setup(&(sg_desc){0}); - const bool added = sg_add_commit_listener((sg_commit_listener){ - .func = commit_listener_func, - .user_data = (void*)23, - }); - T(added); - T(_sg.commit_listeners.upper == 1); - sg_commit(); - T(23 == commit_listener.userdata); - T(1 == commit_listener.num_called); - sg_shutdown(); -} - -UTEST(sokol_gfx, commit_listener_add_twice) { - reset_commit_listener(); - setup(&(sg_desc){0}); - const sg_commit_listener listener = { - .func = commit_listener_func, - .user_data = (void*)23, - }; - T(sg_add_commit_listener(listener)); - T(_sg.commit_listeners.upper == 1); - T(!sg_add_commit_listener(listener)); - T(_sg.commit_listeners.upper == 1); - sg_commit(); - T(23 == commit_listener.userdata); - T(1 == commit_listener.num_called); - sg_shutdown(); -} - -UTEST(sokol_gfx, commit_listener_same_func_diff_ud) { - reset_commit_listener(); - setup(&(sg_desc){0}); - T(sg_add_commit_listener((sg_commit_listener){ - .func = commit_listener_func, - .user_data = (void*)23, - })); - T(_sg.commit_listeners.upper == 1); - T(sg_add_commit_listener((sg_commit_listener){ - .func = commit_listener_func, - .user_data = (void*)25, - })); - T(_sg.commit_listeners.upper == 2); - sg_commit(); - T(2 == commit_listener.num_called); - sg_shutdown(); -} - -UTEST(sokol_gfx, commit_listener_add_remove_add) { - reset_commit_listener(); - setup(&(sg_desc){0}); - const sg_commit_listener listener = { - .func = commit_listener_func, - .user_data = (void*)23, - }; - T(sg_add_commit_listener(listener)); - T(_sg.commit_listeners.upper == 1); - T(sg_remove_commit_listener(listener)); - T(_sg.commit_listeners.upper == 1); - sg_commit(); - T(0 == commit_listener.num_called); - T(sg_add_commit_listener(listener)); - T(_sg.commit_listeners.upper == 1); - sg_commit(); - T(1 == commit_listener.num_called); - T(23 == commit_listener.userdata); - sg_shutdown(); -} - -UTEST(sokol_gfx, commit_listener_remove_non_existent) { - reset_commit_listener(); - setup(&(sg_desc){0}); - const sg_commit_listener l0 = { - .func = commit_listener_func, - .user_data = (void*)23, - }; - const sg_commit_listener l1 = { - .func = commit_listener_func, - .user_data = (void*)46, - }; - const sg_commit_listener l2 = { - .func = commit_listener_func, - .user_data = (void*)256, - }; - T(sg_add_commit_listener(l0)); - T(sg_add_commit_listener(l1)); - T(_sg.commit_listeners.upper == 2); - T(!sg_remove_commit_listener(l2)); - T(_sg.commit_listeners.upper == 2); - sg_shutdown(); -} - -UTEST(sokol_gfx, commit_listener_multi_add_remove) { - reset_commit_listener(); - setup(&(sg_desc){0}); - const sg_commit_listener l0 = { - .func = commit_listener_func, - .user_data = (void*)23, - }; - const sg_commit_listener l1 = { - .func = commit_listener_func, - .user_data = (void*)46, - }; - T(sg_add_commit_listener(l0)); - T(sg_add_commit_listener(l1)); - T(_sg.commit_listeners.upper == 2); - // removing the first listener will just clear its slot - T(sg_remove_commit_listener(l0)); - T(_sg.commit_listeners.upper == 2); - sg_commit(); - T(commit_listener.num_called == 1); - T(commit_listener.userdata == 46); - commit_listener.num_called = 0; - // adding the first listener back will fill that same slot again - T(sg_add_commit_listener(l0)); - T(_sg.commit_listeners.upper == 2); - sg_commit(); - T(commit_listener.num_called == 2); - T(commit_listener.userdata == 46); - commit_listener.num_called = 0; - // removing the second listener will decrement the upper bound - T(sg_remove_commit_listener(l1)); - T(_sg.commit_listeners.upper == 2); - sg_commit(); - T(commit_listener.num_called == 1); - T(commit_listener.userdata == 23); - commit_listener.num_called = 0; - // and finally remove the first listener too - T(sg_remove_commit_listener(l0)); - T(_sg.commit_listeners.upper == 2); - sg_commit(); - T(commit_listener.num_called == 0); - // removing the same listener twice just returns false - T(!sg_remove_commit_listener(l0)); - T(!sg_remove_commit_listener(l1)); - sg_shutdown(); -} - -UTEST(sokol_gfx, commit_listener_array_full) { - reset_commit_listener(); - setup(&(sg_desc){ - .max_commit_listeners = 3, - }); - const sg_commit_listener l0 = { - .func = commit_listener_func, - .user_data = (void*)23, - }; - const sg_commit_listener l1 = { - .func = commit_listener_func, - .user_data = (void*)46, - }; - const sg_commit_listener l2 = { - .func = commit_listener_func, - .user_data = (void*)128, - }; - const sg_commit_listener l3 = { - .func = commit_listener_func, - .user_data = (void*)256, - }; - T(sg_add_commit_listener(l0)); - T(sg_add_commit_listener(l1)); - T(sg_add_commit_listener(l2)); - T(_sg.commit_listeners.upper == 3); - // overflow! - T(!sg_add_commit_listener(l3)); - T(_sg.commit_listeners.upper == 3); - sg_commit(); - T(commit_listener.num_called == 3); - T(commit_listener.userdata == 128); - sg_shutdown(); -} - -UTEST(sokol_gfx, buffer_double_destroy_is_ok) { - setup(&(sg_desc){0}); - sg_buffer buf = create_buffer(); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID); - sg_destroy_buffer(buf); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID); - sg_destroy_buffer(buf); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, image_double_destroy_is_ok) { - setup(&(sg_desc){0}); - sg_image img = create_image(); - T(sg_query_image_state(img) == SG_RESOURCESTATE_VALID); - sg_destroy_image(img); - T(sg_query_image_state(img) == SG_RESOURCESTATE_INVALID); - sg_destroy_image(img); - T(sg_query_image_state(img) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, sampler_double_destroy_is_ok) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){0}); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_VALID); - sg_destroy_sampler(smp); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_INVALID); - sg_destroy_sampler(smp); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, shader_double_destroy_is_ok) { - setup(&(sg_desc){0}); - sg_shader shd = create_shader(); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_VALID); - sg_destroy_shader(shd); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_INVALID); - sg_destroy_shader(shd); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, pipeline_double_destroy_is_ok) { - setup(&(sg_desc){0}); - sg_pipeline pip = create_pipeline(); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_VALID); - sg_destroy_pipeline(pip); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_INVALID); - sg_destroy_pipeline(pip); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokoL_gfx, attachments_double_destroy_is_ok) { - setup(&(sg_desc){0}); - sg_attachments atts = create_attachments(); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_VALID); - sg_destroy_attachments(atts); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_INVALID); - sg_destroy_attachments(atts); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_dealloc_buffer_warns) { - setup(&(sg_desc){0}); - sg_buffer buf = create_buffer(); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID); - sg_dealloc_buffer(buf); - T(log_items[0] == SG_LOGITEM_DEALLOC_BUFFER_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID); - sg_destroy_buffer(buf); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_dealloc_image_warns) { - setup(&(sg_desc){0}); - sg_image img = create_image(); - T(sg_query_image_state(img) == SG_RESOURCESTATE_VALID); - sg_dealloc_image(img); - T(log_items[0] == SG_LOGITEM_DEALLOC_IMAGE_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_image_state(img) == SG_RESOURCESTATE_VALID); - sg_destroy_image(img); - T(sg_query_image_state(img) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_dealloc_sampler_warns) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){0}); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_VALID); - sg_dealloc_sampler(smp); - T(log_items[0] == SG_LOGITEM_DEALLOC_SAMPLER_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_VALID); - sg_destroy_sampler(smp); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_dealloc_shader_warns) { - setup(&(sg_desc){0}); - sg_shader shd = create_shader(); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_VALID); - sg_dealloc_shader(shd); - T(log_items[0] == SG_LOGITEM_DEALLOC_SHADER_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_VALID); - sg_destroy_shader(shd); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_dealloc_pipeline_warns) { - setup(&(sg_desc){0}); - sg_pipeline pip = create_pipeline(); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_VALID); - sg_dealloc_pipeline(pip); - T(log_items[0] == SG_LOGITEM_DEALLOC_PIPELINE_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_VALID); - sg_destroy_pipeline(pip); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_dealloc_attachments_warns) { - setup(&(sg_desc){0}); - sg_attachments atts = create_attachments(); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_VALID); - sg_dealloc_attachments(atts); - T(log_items[0] == SG_LOGITEM_DEALLOC_ATTACHMENTS_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_VALID); - sg_destroy_attachments(atts); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_uninit_buffer_warns) { - setup(&(sg_desc){0}); - sg_buffer buf = sg_alloc_buffer(); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_ALLOC); - sg_uninit_buffer(buf); - T(log_items[0] == SG_LOGITEM_UNINIT_BUFFER_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_ALLOC); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_uninit_image_warns) { - setup(&(sg_desc){0}); - sg_image img = sg_alloc_image(); - T(sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC); - sg_uninit_image(img); - T(log_items[0] == SG_LOGITEM_UNINIT_IMAGE_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_uninit_sampler_warns) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_alloc_sampler(); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_ALLOC); - sg_uninit_sampler(smp); - T(log_items[0] == SG_LOGITEM_UNINIT_SAMPLER_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_ALLOC); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_uninit_shader_warns) { - setup(&(sg_desc){0}); - sg_shader shd = sg_alloc_shader(); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_ALLOC); - sg_uninit_shader(shd); - T(log_items[0] == SG_LOGITEM_UNINIT_SHADER_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_ALLOC); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_uninit_pipeline_warns) { - setup(&(sg_desc){0}); - sg_pipeline pip = sg_alloc_pipeline(); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_ALLOC); - sg_uninit_pipeline(pip); - T(log_items[0] == SG_LOGITEM_UNINIT_PIPELINE_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_ALLOC); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_uninit_attachments_warns) { - setup(&(sg_desc){0}); - sg_attachments atts = sg_alloc_attachments(); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_ALLOC); - sg_uninit_attachments(atts); - T(log_items[0] == SG_LOGITEM_UNINIT_ATTACHMENTS_INVALID_STATE); - T(num_log_called == 1); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_ALLOC); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_destroy_buffer_is_ok) { - setup(&(sg_desc){0}); - sg_buffer buf = sg_alloc_buffer(); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_ALLOC); - sg_destroy_buffer(buf); - T(num_log_called == 0); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_destroy_image_is_ok) { - setup(&(sg_desc){0}); - sg_image img = sg_alloc_image(); - T(sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC); - sg_destroy_image(img); - T(num_log_called == 0); - T(sg_query_image_state(img) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_destroy_sampler_is_ok) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_alloc_sampler(); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_ALLOC); - sg_destroy_sampler(smp); - T(num_log_called == 0); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); - -} - -UTEST(sokol_gfx, alloc_destroy_shader_is_ok) { - setup(&(sg_desc){0}); - sg_shader shd = sg_alloc_shader(); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_ALLOC); - sg_destroy_shader(shd); - T(num_log_called == 0); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_destroy_pipeline_is_ok) { - setup(&(sg_desc){0}); - sg_pipeline pip = sg_alloc_pipeline(); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_ALLOC); - sg_destroy_pipeline(pip); - T(num_log_called == 0); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, alloc_destroy_attachments_is_ok) { - setup(&(sg_desc){0}); - sg_attachments atts = sg_alloc_attachments(); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_ALLOC); - sg_destroy_attachments(atts); - T(num_log_called == 0); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_pipeline_with_nonvalid_shader) { - setup(&(sg_desc){ - .disable_validation = true, - }); - sg_shader shd = sg_alloc_shader(); - T(sg_query_shader_state(shd) == SG_RESOURCESTATE_ALLOC); - sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .shader = shd, - .layout = { - .attrs[0].format = SG_VERTEXFORMAT_FLOAT3 - }, - }); - T(sg_query_pipeline_state(pip) == SG_RESOURCESTATE_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_with_nonvalid_color_images) { - setup(&(sg_desc){ - .disable_validation = true, - }); - sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = sg_alloc_image(), - [1].image = sg_alloc_image(), - }, - .depth_stencil = { - .image = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 128, - .height = 128 - }) - } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - sg_destroy_attachments(atts); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_INVALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_without_color_attachments) { - setup(&(sg_desc){0}); - sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .depth_stencil.image = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }) - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_VALID); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_buffer_validate_start_canary) { - setup(&(sg_desc){0}); - const uint32_t data[32] = {0}; - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - ._start_canary = 1234, - .data = SG_RANGE(data), - }); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_BUFFERDESC_CANARY); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_buffer_validate_end_canary) { - setup(&(sg_desc){0}); - const uint32_t data[32] = {0}; - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - .data = SG_RANGE(data), - ._end_canary = 1234, - }); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_BUFFERDESC_CANARY); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_buffer_validate_immutable_nodata) { - setup(&(sg_desc){0}); - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ 0 }); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_BUFFERDESC_SIZE); - T(log_items[1] == SG_LOGITEM_VALIDATE_BUFFERDESC_DATA); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_buffer_validate_size_mismatch) { - setup(&(sg_desc){0}); - const uint32_t data[16] = { 0 }; - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - .size = 15 * sizeof(uint32_t), - .data = SG_RANGE(data), - }); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_BUFFERDESC_DATA_SIZE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_buffer_validate_data_ptr_but_no_size) { - setup(&(sg_desc){0}); - const uint32_t data[16] = {0}; - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - .data.ptr = data, - }); - T(sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_BUFFERDESC_SIZE); - T(log_items[1] == SG_LOGITEM_VALIDATE_BUFFERDESC_DATA); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_start_canary) { - setup(&(sg_desc){0}); - const uint32_t pixels[8][8] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - ._start_canary = 1234, - .width = 8, - .height = 8, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_CANARY); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_end_canary) { - setup(&(sg_desc){0}); - const uint32_t pixels[8][8] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .data.subimage[0][0] = SG_RANGE(pixels), - ._end_canary = 1234, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_CANARY); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_zero_width_height) { - setup(&(sg_desc){0}); - const uint32_t pixels[8][8] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 0, - .height = 0, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_WIDTH); - T(log_items[1] == SG_LOGITEM_VALIDATE_IMAGEDESC_HEIGHT); - T(log_items[2] == SG_LOGITEM_VALIDATE_IMAGEDATA_DATA_SIZE); - T(log_items[3] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_msaa_no_rt) { - setup(&(sg_desc){0}); - const uint32_t pixels[8][8] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .sample_count = 4, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_msaa_num_mipmaps) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - .num_mipmaps = 2, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_MSAA_NUM_MIPMAPS); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_msaa_3d_image) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_3D, - .width = 32, - .height = 32, - .num_slices = 32, - .sample_count = 4, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_MSAA_3D_IMAGE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_depth_3d_image_with_depth_format) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_3D, - .width = 8, - .height = 8, - .num_slices = 8, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_DEPTH_3D_IMAGE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_rt_immutable) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .usage = SG_USAGE_DYNAMIC, - .width = 8, - .height = 8, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_RT_IMMUTABLE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_dynamic_no_data) { - setup(&(sg_desc){0}); - uint32_t pixels[8][8] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .usage = SG_USAGE_DYNAMIC, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_valiate_compressed_immutable) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .pixel_format = SG_PIXELFORMAT_BC1_RGBA, - .usage = SG_USAGE_DYNAMIC, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_nodata) { - setup(&(sg_desc){0}); - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDATA_NODATA); - T(log_items[1] == SG_LOGITEM_VALIDATE_IMAGEDATA_DATA_SIZE); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_data_size) { - setup(&(sg_desc){0}); - uint32_t pixels[4][4] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDATA_DATA_SIZE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_missing_mipdata) { - setup(&(sg_desc){0}); - uint32_t mip0[8][8] = {0}; - uint32_t mip1[4][4] = {0}; - uint32_t mip2[2][2] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .num_mipmaps = 4, - .data.subimage[0][0] = SG_RANGE(mip0), - .data.subimage[0][1] = SG_RANGE(mip1), - .data.subimage[0][2] = SG_RANGE(mip2), - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDATA_NODATA); - T(log_items[1] == SG_LOGITEM_VALIDATE_IMAGEDATA_DATA_SIZE); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_image_validate_wrong_mipsize) { - setup(&(sg_desc){0}); - uint32_t mip0[8][8] = {0}; - uint32_t mip1[4][4] = {0}; - uint32_t mip2[2][2] = {0}; - uint32_t mip3[1][1] = {0}; - sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .num_mipmaps = 4, - .data.subimage[0][0] = SG_RANGE(mip0), - .data.subimage[0][1] = SG_RANGE(mip2), - .data.subimage[0][2] = SG_RANGE(mip1), - .data.subimage[0][3] = SG_RANGE(mip3) - }); - T(sg_query_image_state(img) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_IMAGEDATA_DATA_SIZE); - T(log_items[1] == SG_LOGITEM_VALIDATE_IMAGEDATA_DATA_SIZE); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_sampler_validate_start_canary) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){ - ._start_canary = 1234, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_CANARY); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_sampler_validate_minfilter_none) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){ - .min_filter = SG_FILTER_NONE, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_MINFILTER_NONE); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_sampler_validate_magfilter_none) { - setup(&(sg_desc){0}); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){ - .mag_filter = SG_FILTER_NONE, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_MAGFILTER_NONE); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_sampler_validate_anistropic_requires_linear_filtering) { - setup(&(sg_desc){0}); - sg_sampler smp; - - smp = sg_make_sampler(&(sg_sampler_desc){ - .max_anisotropy = 2, - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .mipmap_filter = SG_FILTER_NONE, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING); - - reset_log_items(); - smp = sg_make_sampler(&(sg_sampler_desc){ - .max_anisotropy = 2, - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .mipmap_filter = SG_FILTER_NEAREST, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING); - - reset_log_items(); - smp = sg_make_sampler(&(sg_sampler_desc){ - .max_anisotropy = 2, - .min_filter = SG_FILTER_NEAREST, - .mag_filter = SG_FILTER_LINEAR, - .mipmap_filter = SG_FILTER_LINEAR, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING); - - reset_log_items(); - smp = sg_make_sampler(&(sg_sampler_desc){ - .max_anisotropy = 2, - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_NEAREST, - .mipmap_filter = SG_FILTER_LINEAR, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING); - - reset_log_items(); - smp = sg_make_sampler(&(sg_sampler_desc){ - .max_anisotropy = 2, - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .mipmap_filter = SG_FILTER_LINEAR, - }); - T(sg_query_sampler_state(smp) == SG_RESOURCESTATE_VALID); - - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_start_canary) { - setup(&(sg_desc){0}); - sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - ._start_canary = 1234, - .colors[0].image = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }), - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_CANARY); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_end_canary) { - setup(&(sg_desc){0}); - sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }), - ._end_canary = 1234, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_CANARY); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_no_cont_color_atts1) { - setup(&(sg_desc){0}); - const sg_image_desc img_desc = { .render_target = true, .width = 64, .height = 64 }; - sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = sg_make_image(&img_desc), - [2].image = sg_make_image(&img_desc), - } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_NO_CONT_COLOR_ATTS); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_image) { - setup(&(sg_desc){0}); - const sg_image_desc img_desc = { .render_target = true, .width = 64, .height = 64 }; - const sg_image img0 = sg_make_image(&img_desc); - const sg_image img1 = sg_make_image(&img_desc); - sg_destroy_image(img1); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = img0, - [1].image = img1, - } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_IMAGE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_miplevel) { - setup(&(sg_desc){0}); - const sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 16, - .height = 16, - .num_mipmaps = 4, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = img, .mip_level = 4 } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_MIPLEVEL); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_face) { - setup(&(sg_desc){0}); - const sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_CUBE, - .width = 64, - .height = 64, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = img, .slice = 6 } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_FACE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_layer) { - setup(&(sg_desc){0}); - const sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_ARRAY, - .width = 64, - .height = 64, - .num_slices = 4, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = img, .slice = 5 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_LAYER); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_slice) { - setup(&(sg_desc){0}); - const sg_image img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_3D, - .width = 64, - .height = 64, - .num_slices = 4, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = img, .slice = 5 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_SLICE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_image_no_rt) { - setup(&(sg_desc){0}); - const sg_image img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .usage = SG_USAGE_DYNAMIC, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = img, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_IMAGE_NO_RT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_color_inv_pixelformat) { - setup(&(sg_desc){0}); - const sg_image_desc img_desc = { - .render_target = true, - .width = 8, - .height = 8, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }; - reset_log_items(); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = sg_make_image(&img_desc), - .depth_stencil.image = sg_make_image(&img_desc), - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_COLOR_INV_PIXELFORMAT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_depth_inv_pixelformat) { - setup(&(sg_desc){0}); - const sg_image_desc img_desc = { - .render_target = true, - .width = 8, - .height = 8, - }; - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = sg_make_image(&img_desc), - .depth_stencil.image = sg_make_image(&img_desc), - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_INV_PIXELFORMAT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_image_sizes) { - setup(&(sg_desc){0}); - const sg_image img0 = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }); - const sg_image img1 = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 32, - .height = 32, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = img0, - [1].image = img1, - } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES); - T(log_items[1] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_image_sample_counts) { - setup(&(sg_desc){0}); - const sg_image img0 = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image img1 = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 2, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors = { - [0].image = img0, - [1].image = img1, - } - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_IMAGE_SAMPLE_COUNTS); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_color_image_msaa) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 1, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = color_img, - .resolves[0].image = resolve_img, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_COLOR_IMAGE_MSAA); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_image) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 1, - }); - sg_destroy_image(resolve_img); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = color_img, - .resolves[0].image = resolve_img, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_sample_count) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = color_img, - .resolves[0].image = resolve_img, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_SAMPLE_COUNT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_miplevel) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img, .mip_level = 1 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_MIPLEVEL); - // FIXME: these are confusing - T(log_items[1] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); - T(log_items[2] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); - T(log_items[3] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_face) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_CUBE, - .width = 64, - .height = 64, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img, .slice = 6 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_FACE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_layer) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_ARRAY, - .width = 64, - .height = 64, - .num_slices = 4, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img, .slice = 4 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_LAYER); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_slice) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_3D, - .width = 64, - .height = 64, - .num_slices = 4, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img, .slice = 4 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_SLICE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_image_no_rt) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .width = 64, - .height = 64, - .usage = SG_USAGE_DYNAMIC, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_NO_RT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_image_sizes) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 32, - .height = 32, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); - T(log_items[1] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_resolve_image_format) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .pixel_format = SG_PIXELFORMAT_R8, - .sample_count = 1, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .resolves[0] = { .image = resolve_img }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_FORMAT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_depth_image) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }); - sg_destroy_image(depth_img); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .depth_stencil.image = depth_img, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_depth_miplevel) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .depth_stencil = { .image = depth_img, .mip_level = 1 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_MIPLEVEL); - // FIXME: these additional validation errors are confusing - T(log_items[1] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); - T(log_items[2] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); - T(log_items[3] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_depth_face) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_CUBE, - .width = 64, - .height = 64, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .depth_stencil = { .image = depth_img, .slice = 6 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_FACE); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_depth_layer) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .type = SG_IMAGETYPE_ARRAY, - .width = 64, - .height = 64, - .num_slices = 4, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .depth_stencil = { .image = depth_img, .slice = 4 }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_LAYER); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -// NOTE: VALIDATE_PASSDESC_DEPTH_SLICE can't actually happen because VALIDATE_IMAGEDESC_DEPTH_3D_IMAGE - -// NOTE: VALIDATE_DEPTH_IMAGE_NO_RT can't actually happen because VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT - -UTEST(sokol_gfx, make_attachments_validate_depth_image_sizes) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 32, - .height = 32, - .pixel_format = SG_PIXELFORMAT_DEPTH, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .depth_stencil = { .image = depth_img }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); - T(log_items[1] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); - T(log_items[2] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, make_attachments_validate_depth_image_sample_count) { - setup(&(sg_desc){0}); - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .sample_count = 4, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 64, - .height = 64, - .pixel_format = SG_PIXELFORMAT_DEPTH, - .sample_count = 2, - }); - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { .image = color_img }, - .depth_stencil = { .image = depth_img }, - }); - T(sg_query_attachments_state(atts) == SG_RESOURCESTATE_FAILED); - T(log_items[0] == SG_LOGITEM_VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT); - T(log_items[1] == SG_LOGITEM_VALIDATION_FAILED); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_pixelformat_bytesperpixel) { - setup(&(sg_desc){0}); - T(sg_query_pixelformat(SG_PIXELFORMAT_R8).bytes_per_pixel == 1); - T(sg_query_pixelformat(SG_PIXELFORMAT_R8SN).bytes_per_pixel == 1); - T(sg_query_pixelformat(SG_PIXELFORMAT_R8UI).bytes_per_pixel == 1); - T(sg_query_pixelformat(SG_PIXELFORMAT_R8SI).bytes_per_pixel == 1); - T(sg_query_pixelformat(SG_PIXELFORMAT_R16).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_R16SN).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_R16UI).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_R16SI).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_R16F).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG8).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG8SN).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG8UI).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG8SI).bytes_per_pixel == 2); - T(sg_query_pixelformat(SG_PIXELFORMAT_R32UI).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_R32SI).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_R32F).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG16).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG16SN).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG16UI).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG16SI).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG16F).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA8).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_SRGB8A8).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA8SN).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA8UI).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA8SI).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_BGRA8).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGB10A2).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG11B10F).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGB9E5).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG32UI).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG32SI).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RG32F).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA16).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA16SN).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA16UI).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA16SI).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA16F).bytes_per_pixel == 8); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA32UI).bytes_per_pixel == 16); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA32SI).bytes_per_pixel == 16); - T(sg_query_pixelformat(SG_PIXELFORMAT_RGBA32F).bytes_per_pixel == 16); - T(sg_query_pixelformat(SG_PIXELFORMAT_DEPTH).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_DEPTH_STENCIL).bytes_per_pixel == 4); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC1_RGBA).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC2_RGBA).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC3_RGBA).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC4_R).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC4_RSN).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC5_RG).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC5_RGSN).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC6H_RGBF).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC6H_RGBUF).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_BC7_RGBA).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_PVRTC_RGB_2BPP).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_PVRTC_RGB_4BPP).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_PVRTC_RGBA_2BPP).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_PVRTC_RGBA_4BPP).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_ETC2_RGB8).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_ETC2_RGB8A1).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_ETC2_RGBA8).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_ETC2_RG11).bytes_per_pixel == 0); - T(sg_query_pixelformat(SG_PIXELFORMAT_ETC2_RG11SN).bytes_per_pixel == 0); - sg_shutdown(); -} - -UTEST(sokol_gfx, query_pixelformat_compressed) { - setup(&(sg_desc){0}); - int i = SG_PIXELFORMAT_NONE + 1; - for (; i < SG_PIXELFORMAT_BC1_RGBA; i++) { - T(sg_query_pixelformat((sg_pixel_format)i).compressed == false); - } - for (; i < _SG_PIXELFORMAT_NUM; i++) { - T(sg_query_pixelformat((sg_pixel_format)i).compressed == true); - } - sg_shutdown(); -} - -UTEST(sokol_gfx, query_row_pitch) { - setup(&(sg_desc){0}); - T(sg_query_row_pitch(SG_PIXELFORMAT_R8, 13, 1) == 13); - T(sg_query_row_pitch(SG_PIXELFORMAT_R8, 13, 32) == 32); - T(sg_query_row_pitch(SG_PIXELFORMAT_RG8SN, 256, 16) == 512); - T(sg_query_row_pitch(SG_PIXELFORMAT_RGBA8, 256, 16) == 1024); - T(sg_query_row_pitch(SG_PIXELFORMAT_BC1_RGBA, 1024, 1) == 2048); - T(sg_query_row_pitch(SG_PIXELFORMAT_BC1_RGBA, 1, 1) == 8); - T(sg_query_row_pitch(SG_PIXELFORMAT_DEPTH, 256, 4) == 1024); - T(sg_query_row_pitch(SG_PIXELFORMAT_DEPTH_STENCIL, 256, 4) == 1024); - sg_shutdown(); -} - -UTEST(sokol_gfx, sg_query_surface_pitch) { - setup(&(sg_desc){0}); - T(sg_query_surface_pitch(SG_PIXELFORMAT_R8, 256, 256, 1) == (256 * 256)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_R8, 256, 256, 1024) == (256 * 1024)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_RG8, 1, 1, 1) == 2); - T(sg_query_surface_pitch(SG_PIXELFORMAT_RG8, 256, 256, 4) == (256 * 256 * 2)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_RGBA32F, 256, 256, 1) == (256 * 256 * 16)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_BC1_RGBA, 256, 256, 1) == (256 * 2 * 64)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_BC1_RGBA, 256, 1, 1) == (256 * 2)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_BC1_RGBA, 256, 2, 1) == (256 * 2)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_BC1_RGBA, 256, 3, 1) == (256 * 2)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_BC1_RGBA, 256, 4, 1) == (256 * 2)); - T(sg_query_surface_pitch(SG_PIXELFORMAT_BC1_RGBA, 256, 5, 1) == (256 * 2 * 2)); - sg_shutdown(); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_gl_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_gl_test.c deleted file mode 100644 index 4fe4f45..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_gl_test.c +++ /dev/null @@ -1,323 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-gl-test.c -//------------------------------------------------------------------------------ -#include "sokol_gfx.h" -#define SOKOL_GL_IMPL -#include "sokol_gl.h" -#include "utest.h" -#include - -#define T(b) EXPECT_TRUE(b) -#define TFLT(f0,f1,epsilon) {T(fabs((f0)-(f1))<=(epsilon));} - -static void init(void) { - sg_setup(&(sg_desc){0}); - sgl_setup(&(sgl_desc_t){0}); -} - -static void shutdown(void) { - sgl_shutdown(); - sg_shutdown(); -} - -UTEST(sokol_gl, default_init_shutdown) { - init(); - T(_sgl.init_cookie == _SGL_INIT_COOKIE); - T(_sgl.def_ctx_id.id == SGL_DEFAULT_CONTEXT.id); - T(_sgl.cur_ctx_id.id == _sgl.def_ctx_id.id); - T(_sgl.cur_ctx); - T(_sgl.cur_ctx->vertices.cap == 65536); - T(_sgl.cur_ctx->commands.cap == 16384); - T(_sgl.cur_ctx->uniforms.cap == 16384); - T(_sgl.cur_ctx->vertices.next == 0); - T(_sgl.cur_ctx->commands.next == 0); - T(_sgl.cur_ctx->uniforms.next == 0); - T(_sgl.cur_ctx->vertices.ptr != 0); - T(_sgl.cur_ctx->uniforms.ptr != 0); - T(_sgl.cur_ctx->commands.ptr != 0); - T(_sgl.cur_ctx->error == SGL_NO_ERROR); - T(!_sgl.cur_ctx->in_begin); - T(_sgl.cur_ctx->def_pip.id != SG_INVALID_ID); - T(_sgl.pip_pool.pool.size == (_SGL_DEFAULT_PIPELINE_POOL_SIZE + 1)); - TFLT(_sgl.cur_ctx->u, 0.0f, FLT_MIN); - TFLT(_sgl.cur_ctx->v, 0.0f, FLT_MIN); - T(_sgl.cur_ctx->rgba == 0xFFFFFFFF); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - shutdown(); -} - -UTEST(sokol_gl, viewport) { - init(); - sgl_viewport(1, 2, 3, 4, true); - T(_sgl.cur_ctx->commands.next == 1); - T(_sgl.cur_ctx->commands.ptr[0].cmd == SGL_COMMAND_VIEWPORT); - T(_sgl.cur_ctx->commands.ptr[0].args.viewport.x == 1); - T(_sgl.cur_ctx->commands.ptr[0].args.viewport.y == 2); - T(_sgl.cur_ctx->commands.ptr[0].args.viewport.w == 3); - T(_sgl.cur_ctx->commands.ptr[0].args.viewport.h == 4); - T(_sgl.cur_ctx->commands.ptr[0].args.viewport.origin_top_left); - sgl_viewport(5, 6, 7, 8, false); - T(_sgl.cur_ctx->commands.next == 2); - T(_sgl.cur_ctx->commands.ptr[1].cmd == SGL_COMMAND_VIEWPORT); - T(_sgl.cur_ctx->commands.ptr[1].args.viewport.x == 5); - T(_sgl.cur_ctx->commands.ptr[1].args.viewport.y == 6); - T(_sgl.cur_ctx->commands.ptr[1].args.viewport.w == 7); - T(_sgl.cur_ctx->commands.ptr[1].args.viewport.h == 8); - T(!_sgl.cur_ctx->commands.ptr[1].args.viewport.origin_top_left); - shutdown(); -} - -UTEST(sokol_gl, scissor_rect) { - init(); - sgl_scissor_rect(10, 20, 30, 40, true); - T(_sgl.cur_ctx->commands.next == 1); - T(_sgl.cur_ctx->commands.ptr[0].cmd == SGL_COMMAND_SCISSOR_RECT); - T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.x == 10); - T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.y == 20); - T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.w == 30); - T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.h == 40); - T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.origin_top_left); - sgl_scissor_rect(50, 60, 70, 80, false); - T(_sgl.cur_ctx->commands.next == 2); - T(_sgl.cur_ctx->commands.ptr[1].cmd == SGL_COMMAND_SCISSOR_RECT); - T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.x == 50); - T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.y == 60); - T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.w == 70); - T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.h == 80); - T(!_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.origin_top_left); - shutdown(); -} - -UTEST(sokol_gl, texture) { - init(); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - uint32_t pixels[64] = { 0 }; - sg_image img = sg_make_image(&(sg_image_desc){ - .type = SG_IMAGETYPE_2D, - .width = 8, - .height = 8, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){0}); - sgl_texture(img, smp); - T(_sgl.cur_ctx->cur_img.id == img.id); - T(_sgl.cur_ctx->cur_smp.id == smp.id); - shutdown(); -} - -UTEST(sokol_gl, texture_image_nosampler) { - init(); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - uint32_t pixels[64] = { 0 }; - sg_image img = sg_make_image(&(sg_image_desc){ - .type = SG_IMAGETYPE_2D, - .width = 8, - .height = 8, - .data.subimage[0][0] = SG_RANGE(pixels), - }); - sgl_texture(img, (sg_sampler){0}); - T(_sgl.cur_ctx->cur_img.id == img.id); - T(_sgl.cur_ctx->cur_smp.id == _sgl.def_smp.id); - shutdown(); -} - -UTEST(sokol_gl, texture_noimage_sampler) { - init(); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){0}); - sgl_texture((sg_image){0}, smp); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - T(_sgl.cur_ctx->cur_smp.id == smp.id); - shutdown(); -} - -UTEST(sokol_gl, texture_noimage_nosampler) { - init(); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - sgl_texture((sg_image){0}, (sg_sampler){0}); - T(_sgl.cur_ctx->cur_img.id == _sgl.def_img.id); - T(_sgl.cur_ctx->cur_smp.id == _sgl.def_smp.id); - shutdown(); -} -UTEST(sokol_gl, begin_end) { - init(); - sgl_begin_triangles(); - sgl_v3f(1.0f, 2.0f, 3.0f); - sgl_v3f(4.0f, 5.0f, 6.0f); - sgl_v3f(7.0f, 8.0f, 9.0f); - sgl_end(); - T(_sgl.cur_ctx->base_vertex == 0); - T(_sgl.cur_ctx->vertices.next == 3); - T(_sgl.cur_ctx->commands.next == 1); - T(_sgl.cur_ctx->uniforms.next == 1); - T(_sgl.cur_ctx->commands.ptr[0].cmd == SGL_COMMAND_DRAW); - T(_sgl.cur_ctx->commands.ptr[0].args.draw.pip.id == _sgl_pipeline_at(_sgl.cur_ctx->def_pip.id)->pip[SGL_PRIMITIVETYPE_TRIANGLES].id); - T(_sgl.cur_ctx->commands.ptr[0].args.draw.base_vertex == 0); - T(_sgl.cur_ctx->commands.ptr[0].args.draw.num_vertices == 3); - T(_sgl.cur_ctx->commands.ptr[0].args.draw.uniform_index == 0); - shutdown(); -} - -UTEST(sokol_gl, matrix_mode) { - init(); - sgl_matrix_mode_modelview(); T(_sgl.cur_ctx->cur_matrix_mode == SGL_MATRIXMODE_MODELVIEW); - sgl_matrix_mode_projection(); T(_sgl.cur_ctx->cur_matrix_mode == SGL_MATRIXMODE_PROJECTION); - sgl_matrix_mode_texture(); T(_sgl.cur_ctx->cur_matrix_mode == SGL_MATRIXMODE_TEXTURE); - shutdown(); -} - -UTEST(sokol_gl, load_identity) { - init(); - sgl_load_identity(); - const _sgl_matrix_t* m = _sgl_matrix_modelview(_sgl.cur_ctx); - TFLT(m->v[0][0], 1.0f, FLT_MIN); TFLT(m->v[0][1], 0.0f, FLT_MIN); TFLT(m->v[0][2], 0.0f, FLT_MIN); TFLT(m->v[0][3], 0.0f, FLT_MIN); - TFLT(m->v[1][0], 0.0f, FLT_MIN); TFLT(m->v[1][1], 1.0f, FLT_MIN); TFLT(m->v[1][2], 0.0f, FLT_MIN); TFLT(m->v[1][3], 0.0f, FLT_MIN); - TFLT(m->v[2][0], 0.0f, FLT_MIN); TFLT(m->v[2][1], 0.0f, FLT_MIN); TFLT(m->v[2][2], 1.0f, FLT_MIN); TFLT(m->v[2][3], 0.0f, FLT_MIN); - TFLT(m->v[3][0], 0.0f, FLT_MIN); TFLT(m->v[3][1], 0.0f, FLT_MIN); TFLT(m->v[3][2], 0.0f, FLT_MIN); TFLT(m->v[3][3], 1.0f, FLT_MIN); - shutdown(); -} - -UTEST(sokol_gl, load_matrix) { - init(); - const float m[16] = { - 0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - 2.0f, 3.0f, 4.0f, 1.0f - }; - sgl_load_matrix(m); - const _sgl_matrix_t* m0 = _sgl_matrix_modelview(_sgl.cur_ctx); - TFLT(m0->v[0][0], 0.5f, FLT_MIN); - TFLT(m0->v[1][1], 0.5f, FLT_MIN); - TFLT(m0->v[2][2], 0.5f, FLT_MIN); - TFLT(m0->v[3][0], 2.0f, FLT_MIN); - TFLT(m0->v[3][1], 3.0f, FLT_MIN); - TFLT(m0->v[3][2], 4.0f, FLT_MIN); - TFLT(m0->v[3][3], 1.0f, FLT_MIN); - sgl_load_transpose_matrix(m); - const _sgl_matrix_t* m1 = _sgl_matrix_modelview(_sgl.cur_ctx); - TFLT(m1->v[0][0], 0.5f, FLT_MIN); - TFLT(m1->v[1][1], 0.5f, FLT_MIN); - TFLT(m1->v[2][2], 0.5f, FLT_MIN); - TFLT(m1->v[0][3], 2.0f, FLT_MIN); - TFLT(m1->v[1][3], 3.0f, FLT_MIN); - TFLT(m1->v[2][3], 4.0f, FLT_MIN); - TFLT(m1->v[3][3], 1.0f, FLT_MIN); - shutdown(); -} - -UTEST(sokol_gl, make_destroy_pipelines) { - sg_setup(&(sg_desc){0}); - sgl_setup(&(sgl_desc_t){ - /* one pool slot is used by soko-gl itself */ - .pipeline_pool_size = 4 - }); - - sgl_pipeline pip[3] = { {0} }; - sg_pipeline_desc desc = { - .depth = { - .write_enabled = true, - .compare = SG_COMPAREFUNC_LESS_EQUAL - } - }; - for (int i = 0; i < 3; i++) { - pip[i] = sgl_make_pipeline(&desc); - T(pip[i].id != SG_INVALID_ID); - T((2-i) == _sgl.pip_pool.pool.queue_top); - const _sgl_pipeline_t* pip_ptr = _sgl_lookup_pipeline(pip[i].id); - T(pip_ptr); - T(pip_ptr->slot.id == pip[i].id); - T(pip_ptr->slot.state == SG_RESOURCESTATE_VALID); - } - /* trying to create another one fails because buffer is exhausted */ - T(sgl_make_pipeline(&desc).id == SG_INVALID_ID); - - for (int i = 0; i < 3; i++) { - sgl_destroy_pipeline(pip[i]); - T(0 == _sgl_lookup_pipeline(pip[i].id)); - const _sgl_pipeline_t* pip_ptr = _sgl_pipeline_at(pip[i].id); - T(pip_ptr); - T(pip_ptr->slot.id == SG_INVALID_ID); - T(pip_ptr->slot.state == SG_RESOURCESTATE_INITIAL); - T((i+1) == _sgl.pip_pool.pool.queue_top); - } - sgl_shutdown(); - sg_shutdown(); -} - -UTEST(sokol_gl, make_destroy_contexts) { - init(); - sgl_context ctx = sgl_make_context(&(sgl_context_desc_t){ - .max_vertices = 1024, - .max_commands = 256, - .color_format = SG_PIXELFORMAT_RG8, - .depth_format = SG_PIXELFORMAT_NONE, - .sample_count = 4, - }); - T(ctx.id != SG_INVALID_ID); - T(ctx.id != SGL_DEFAULT_CONTEXT.id); - // creating a context should not change the current context - T(ctx.id != _sgl.cur_ctx_id.id); - sgl_set_context(ctx); - T(_sgl.cur_ctx->vertices.cap == 1024); - T(_sgl.cur_ctx->commands.cap == 256); - T(_sgl.cur_ctx->uniforms.cap == 256); - T(ctx.id == _sgl.cur_ctx_id.id); - T(sgl_get_context().id == ctx.id); - sgl_set_context(SGL_DEFAULT_CONTEXT); - T(sgl_get_context().id == SGL_DEFAULT_CONTEXT.id); - sgl_destroy_context(ctx); - shutdown(); -} - -UTEST(sokol_gl, destroy_active_context) { - init(); - sgl_context ctx = sgl_make_context(&(sgl_context_desc_t){ - .max_vertices = 1024, - .max_commands = 256, - .color_format = SG_PIXELFORMAT_RG8, - .depth_format = SG_PIXELFORMAT_NONE, - .sample_count = 4, - }); - sgl_set_context(ctx); - sgl_destroy_context(ctx); - T(_sgl.cur_ctx == 0); - T(sgl_error() == SGL_ERROR_NO_CONTEXT); - shutdown(); -} - -UTEST(sokol_gl, context_pipeline) { - init(); - sgl_context ctx1 = sgl_make_context(&(sgl_context_desc_t){ - .max_vertices = 1024, - .max_commands = 256, - .color_format = SG_PIXELFORMAT_R8, - .depth_format = SG_PIXELFORMAT_NONE, - .sample_count = 4, - }); - sgl_context ctx2 = sgl_make_context(&(sgl_context_desc_t){ - .max_vertices = 1024, - .max_commands = 256, - .color_format = SG_PIXELFORMAT_RG8, - .depth_format = SG_PIXELFORMAT_NONE, - .sample_count = 2, - }); - sgl_set_context(ctx1); - sgl_pipeline pip1 = sgl_make_pipeline(&(sg_pipeline_desc){ - .colors[0].blend.enabled = true, - }); - T(pip1.id != SG_INVALID_ID); - // FIXME: currently sg_query_pipeline_info() doesn't provide enough information - - sgl_pipeline pip2 = sgl_context_make_pipeline(ctx2, &(sg_pipeline_desc){ - .alpha_to_coverage_enabled = true, - }); - T(pip2.id != SG_INVALID_ID); - shutdown(); -} - -UTEST(sokol_gl, default_context) { - init(); - T(sgl_default_context().id == SGL_DEFAULT_CONTEXT.id); - shutdown(); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_log_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_log_test.c deleted file mode 100644 index 1ed21ef..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_log_test.c +++ /dev/null @@ -1,2 +0,0 @@ -#define SOKOL_LOG_IMPL -#include "sokol_log.h" diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_shape_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_shape_test.c deleted file mode 100644 index 8fc84b1..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_shape_test.c +++ /dev/null @@ -1,421 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-shape-test.c -//------------------------------------------------------------------------------ -#include "sokol_gfx.h" -#define SOKOL_SHAPE_IMPL -#include "sokol_shape.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) -#define TFLT(f0,f1,epsilon) {T(fabs((f0)-(f1))<=(epsilon));} - -UTEST(sokol_shape, color4f) { - T(sshape_color_4f(1.0f, 0.0f, 0.0f, 0.0f) == 0x000000FF); - T(sshape_color_4f(0.0f, 1.0f, 0.0f, 0.0f) == 0x0000FF00); - T(sshape_color_4f(0.0f, 0.0f, 1.0f, 0.0f) == 0x00FF0000); - T(sshape_color_4f(0.0f, 0.0f, 0.0f, 1.0f) == 0xFF000000); -} - -UTEST(sokol_shape, color3f) { - T(sshape_color_3f(1.0f, 0.0f, 0.0f) == 0xFF0000FF); - T(sshape_color_3f(0.0f, 1.0f, 0.0f) == 0xFF00FF00); - T(sshape_color_3f(0.0f, 0.0f, 1.0f) == 0xFFFF0000); -} - -UTEST(sokol_shape, color4b) { - T(sshape_color_4b(255, 0, 0, 0) == 0x000000FF); - T(sshape_color_4b(0, 255, 0, 0) == 0x0000FF00); - T(sshape_color_4b(0, 0, 255, 0) == 0x00FF0000); - T(sshape_color_4b(0, 0, 0, 255) == 0xFF000000); -} - -UTEST(sokol_shape, color3b) { - T(sshape_color_3b(255, 0, 0) == 0xFF0000FF); - T(sshape_color_3b(0, 255, 0) == 0xFF00FF00); - T(sshape_color_3b(0, 0, 255) == 0xFFFF0000); -} - -UTEST(sokol_shape, mat4) { - float values[16] = { - 1.0f, 2.0f, 3.0f, 4.0f, - 5.0f, 6.0f, 7.0f, 8.0f, - 9.0f, 10.0f, 11.0f, 12.0f, - 13.0f, 14.0f, 15.0f, 16.0f - }; - sshape_mat4_t m = sshape_mat4(values); - T(m.m[0][0] == 1.0f); - T(m.m[0][1] == 2.0f); - T(m.m[0][2] == 3.0f); - T(m.m[0][3] == 4.0f); - T(m.m[1][0] == 5.0f); - T(m.m[1][1] == 6.0f); - T(m.m[1][2] == 7.0f); - T(m.m[1][3] == 8.0f); - T(m.m[2][0] == 9.0f); - T(m.m[2][1] == 10.0f); - T(m.m[2][2] == 11.0f); - T(m.m[2][3] == 12.0f); - T(m.m[3][0] == 13.0f); - T(m.m[3][1] == 14.0f); - T(m.m[3][2] == 15.0f); - T(m.m[3][3] == 16.0f); -} - -UTEST(sokol_shape, mat4_transpose) { - float values[16] = { - 1.0f, 2.0f, 3.0f, 4.0f, - 5.0f, 6.0f, 7.0f, 8.0f, - 9.0f, 10.0f, 11.0f, 12.0f, - 13.0f, 14.0f, 15.0f, 16.0f - }; - sshape_mat4_t m = sshape_mat4_transpose(values); - T(m.m[0][0] == 1.0f); - T(m.m[1][0] == 2.0f); - T(m.m[2][0] == 3.0f); - T(m.m[3][0] == 4.0f); - T(m.m[0][1] == 5.0f); - T(m.m[1][1] == 6.0f); - T(m.m[2][1] == 7.0f); - T(m.m[3][1] == 8.0f); - T(m.m[0][2] == 9.0f); - T(m.m[1][2] == 10.0f); - T(m.m[2][2] == 11.0f); - T(m.m[3][2] == 12.0f); - T(m.m[0][3] == 13.0f); - T(m.m[1][3] == 14.0f); - T(m.m[2][3] == 15.0f); - T(m.m[3][3] == 16.0f); -} - -UTEST(sokol_shape, plane_buffer_sizes) { - sshape_sizes_t res; - - res = sshape_plane_sizes(1); - T(4 == res.vertices.num); - T(6 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); - - res = sshape_plane_sizes(2); - T(9 == res.vertices.num); - T(24 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); -} - -UTEST(sokol_shape, box_buffer_sizes) { - sshape_sizes_t res; - - res = sshape_box_sizes(1); - T(24 == res.vertices.num); - T(36 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); - - res = sshape_box_sizes(2); - T(54 == res.vertices.num); - T(144 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); -} - -UTEST(sokol_shape, sphere_buffer_sizes) { - sshape_sizes_t res; - - res = sshape_sphere_sizes(3, 2); - T(12 == res.vertices.num); - T(18 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); - - res = sshape_sphere_sizes(36, 12); - T(481 == res.vertices.num); - T(2376 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); -} - -UTEST(sokol_shape, cylinder_buffer_sizes) { - sshape_sizes_t res; - - res = sshape_cylinder_sizes(3, 1); - T(24 == res.vertices.num); - T(36 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); - - res = sshape_cylinder_sizes(5, 2); - T(42 == res.vertices.num); - T(90 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); -} - -UTEST(sokol_shape, torus_buffer_sizes) { - sshape_sizes_t res; - - res = sshape_torus_sizes(3, 3); - T(16 == res.vertices.num); - T(54 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); - - res = sshape_torus_sizes(4, 5); - T(30 == res.vertices.num); - T(120 == res.indices.num); - T(res.vertices.num * sizeof(sshape_vertex_t) == res.vertices.size); - T(res.indices.num * sizeof(uint16_t) == res.indices.size); -} - -UTEST(sokol_shape, buffer_layout_desc) { - const sg_vertex_buffer_layout_state l_state = sshape_vertex_buffer_layout_state(); - T(sizeof(sshape_vertex_t) == l_state.stride); - T(0 == l_state.step_func); - T(0 == l_state.step_rate); -} - -UTEST(sokol_shape, attr_descs) { - { - const sg_vertex_attr_state a_state = sshape_position_vertex_attr_state(); - T(offsetof(sshape_vertex_t, x) == a_state.offset); - T(SG_VERTEXFORMAT_FLOAT3 == a_state.format); - T(0 == a_state.buffer_index); - } - { - const sg_vertex_attr_state a_state = sshape_normal_vertex_attr_state(); - T(offsetof(sshape_vertex_t, normal) == a_state.offset); - T(SG_VERTEXFORMAT_BYTE4N == a_state.format); - T(0 == a_state.buffer_index); - } - { - const sg_vertex_attr_state a_state = sshape_texcoord_vertex_attr_state(); - T(offsetof(sshape_vertex_t, u) == a_state.offset); - T(SG_VERTEXFORMAT_USHORT2N == a_state.format); - T(0 == a_state.buffer_index); - } - { - const sg_vertex_attr_state a_state = sshape_color_vertex_attr_state(); - T(offsetof(sshape_vertex_t, color) == a_state.offset); - T(SG_VERTEXFORMAT_UBYTE4N == a_state.format); - T(0 == a_state.buffer_index); - } -} - -UTEST(sokol_shape, buffer_descs_elm_range) { - sshape_vertex_t vx[128] = { 0 }; - uint16_t ix[128] = { 0 }; - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = SSHAPE_RANGE(ix), - }; - - // build a box... - { - buf = sshape_build_box(&buf, &(sshape_box_t) {0}); - const sg_buffer_desc vbuf_desc = sshape_vertex_buffer_desc(&buf); - const sg_buffer_desc ibuf_desc = sshape_index_buffer_desc(&buf); - const sshape_element_range_t elm_range = sshape_element_range(&buf); - T(vbuf_desc.size == 0); - T(vbuf_desc.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(vbuf_desc.usage == SG_USAGE_IMMUTABLE); - T(vbuf_desc.data.ptr == vx); - T(vbuf_desc.data.size == 24 * sizeof(sshape_vertex_t)); - T(ibuf_desc.size == 0); - T(ibuf_desc.type == SG_BUFFERTYPE_INDEXBUFFER); - T(ibuf_desc.usage == SG_USAGE_IMMUTABLE); - T(ibuf_desc.data.ptr == ix); - T(ibuf_desc.data.size == 36 * sizeof(uint16_t)); - T(elm_range.base_element == 0); - T(elm_range.num_elements == 36); - } - - // append a plane... - { - buf = sshape_build_plane(&buf, &(sshape_plane_t) {0}); - const sg_buffer_desc vbuf_desc = sshape_vertex_buffer_desc(&buf); - const sg_buffer_desc ibuf_desc = sshape_index_buffer_desc(&buf); - const sshape_element_range_t elm_range = sshape_element_range(&buf); - T(vbuf_desc.size == 0); - T(vbuf_desc.type == SG_BUFFERTYPE_VERTEXBUFFER); - T(vbuf_desc.usage == SG_USAGE_IMMUTABLE); - T(vbuf_desc.data.ptr == vx); - T(vbuf_desc.data.size == 28 * sizeof(sshape_vertex_t)); - T(ibuf_desc.size == 0); - T(ibuf_desc.type == SG_BUFFERTYPE_INDEXBUFFER); - T(ibuf_desc.usage == SG_USAGE_IMMUTABLE); - T(ibuf_desc.data.ptr == ix); - T(ibuf_desc.data.size == 42 * sizeof(uint16_t)); - T(elm_range.base_element == 36); - T(elm_range.num_elements == 6); - } -} - -UTEST(sokol_shape, build_plane_defaults) { - sshape_vertex_t vx[64] = { 0 }; - uint16_t ix[64] = { 0 }; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = SSHAPE_RANGE(ix), - }; - buf = sshape_build_plane(&buf, &(sshape_plane_t) { 0 }); - - T(buf.valid); - T(0 == buf.vertices.shape_offset); - T(4 * sizeof(sshape_vertex_t) == buf.vertices.data_size); - T(0 == buf.indices.shape_offset); - T(6 * sizeof(uint16_t) == buf.indices.data_size); - for (int i = 0; i < 4; i++) { - T(vx[i].color == 0xFFFFFFFF); - } - T(ix[0] == 0); - T(ix[1] == 1); - T(ix[2] == 3); - T(ix[3] == 0); - T(ix[4] == 3); - T(ix[5] == 2); -} - -UTEST(sokol_shape, build_plane_validate) { - sshape_vertex_t vx[64] = { 0 }; - uint16_t ix[64] = { 0 }; - const sshape_plane_t params = { 0 }; - - // vertex buffer too small - { - sshape_buffer_t buf = { - .vertices.buffer = { .ptr = vx, .size = 3 * sizeof(sshape_vertex_t) }, - .indices.buffer = SSHAPE_RANGE(ix), - }; - T(!sshape_build_plane(&buf, ¶ms).valid); - } - - // index buffer too small - { - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = { .ptr = ix, .size = 5 * sizeof(uint16_t) } - }; - T(!sshape_build_plane(&buf, ¶ms).valid); - } - // just the right size - { - sshape_buffer_t buf = { - .vertices.buffer = { .ptr = vx, .size = 4 * sizeof(sshape_vertex_t) }, - .indices.buffer = { .ptr = ix, .size = 6 * sizeof(uint16_t) } - }; - T(sshape_build_plane(&buf, ¶ms).valid); - } - - // too small for two planes - { - sshape_buffer_t buf = { - .vertices.buffer = { .ptr = vx, .size = 5 * sizeof(sshape_vertex_t) }, - .indices.buffer = { .ptr = ix, .size = 7 * sizeof(uint16_t) } - }; - buf = sshape_build_plane(&buf, ¶ms); - T(buf.valid); - buf = sshape_build_plane(&buf, ¶ms); - T(!buf.valid); - } - - // just the right size for two planes - { - sshape_buffer_t buf = { - .vertices.buffer = { .ptr = vx, .size = 8 * sizeof(sshape_vertex_t) }, - .indices.buffer = { .ptr = ix, .size = 12 * sizeof(uint16_t) } - }; - buf = sshape_build_plane(&buf, ¶ms); - T(buf.valid); - T(buf.vertices.shape_offset == 0); - T(buf.vertices.data_size == 4 * sizeof(sshape_vertex_t)); - T(buf.indices.shape_offset == 0); - T(buf.indices.data_size == 6 * sizeof(uint16_t)); - buf = sshape_build_plane(&buf, ¶ms); - T(buf.valid); - T(buf.vertices.shape_offset == 4 * sizeof(sshape_vertex_t)); - T(buf.vertices.data_size == 8 * sizeof(sshape_vertex_t)); - T(buf.indices.shape_offset == 6 * sizeof(uint16_t)); - T(buf.indices.data_size == 12 * sizeof(uint16_t)); - } -} - -UTEST(sokol_shape, build_box_defaults) { - sshape_vertex_t vx[128] = { 0 }; - uint16_t ix[128] = { 0 }; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = SSHAPE_RANGE(ix), - }; - buf = sshape_build_box(&buf, &(sshape_box_t) { .color = 0xFF0000FF }); - T(buf.valid); - T(buf.vertices.buffer.ptr == vx); - T(buf.vertices.buffer.size == sizeof(vx)); - T(buf.indices.buffer.ptr == ix); - T(buf.indices.buffer.size == sizeof(ix)); - T(buf.vertices.shape_offset == 0); - T(buf.vertices.data_size == 24 * sizeof(sshape_vertex_t)); - T(buf.indices.shape_offset == 0); - T(buf.indices.data_size == 36 * sizeof(uint16_t)); -} - -UTEST(sokol_shape, build_sphere_defaults) { - sshape_vertex_t vx[128] = { 0 }; - uint16_t ix[128] = { 0 }; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = SSHAPE_RANGE(ix), - }; - buf = sshape_build_sphere(&buf, &(sshape_sphere_t) { .color = 0xFF0000FF }); - T(buf.valid); - T(buf.vertices.buffer.ptr == vx); - T(buf.vertices.buffer.size == sizeof(vx)); - T(buf.indices.buffer.ptr == ix); - T(buf.indices.buffer.size == sizeof(ix)); - T(buf.vertices.shape_offset == 0); - T(buf.vertices.data_size == 30 * sizeof(sshape_vertex_t)); - T(buf.indices.shape_offset == 0); - T(buf.indices.data_size == 90 * sizeof(uint16_t)); -} - -UTEST(sokol_shape, build_cylinder_defaults) { - sshape_vertex_t vx[128] = { 0 }; - uint16_t ix[128] = { 0 }; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = SSHAPE_RANGE(ix) - }; - buf = sshape_build_cylinder(&buf, &(sshape_cylinder_t) { .color = 0xFF0000FF }); - T(buf.valid); - T(buf.vertices.buffer.ptr == vx); - T(buf.vertices.buffer.size == sizeof(vx)); - T(buf.indices.buffer.ptr == ix); - T(buf.indices.buffer.size == sizeof(ix)); - T(buf.vertices.shape_offset == 0); - T(buf.vertices.data_size == 36 * sizeof(sshape_vertex_t)); - T(buf.indices.shape_offset == 0); - T(buf.indices.data_size == 60 * sizeof(uint16_t)); -} - -UTEST(sokol_shape, build_torus_defaults) { - sshape_vertex_t vx[128] = { 0 }; - uint16_t ix[256] = { 0 }; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vx), - .indices.buffer = SSHAPE_RANGE(ix), - }; - buf = sshape_build_torus(&buf, &(sshape_torus_t) { .color = 0xFF0000FF }); - T(buf.valid); - T(buf.vertices.buffer.ptr == vx); - T(buf.vertices.buffer.size == sizeof(vx)); - T(buf.indices.buffer.ptr == ix); - T(buf.indices.buffer.size == sizeof(ix)); - T(buf.vertices.shape_offset == 0); - T(buf.vertices.data_size == 36 * sizeof(sshape_vertex_t)); - T(buf.indices.shape_offset == 0); - T(buf.indices.data_size == 150 * sizeof(uint16_t)); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_spine_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_spine_test.c deleted file mode 100644 index 435b32b..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_spine_test.c +++ /dev/null @@ -1,1197 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol_spine_test.c -//------------------------------------------------------------------------------ -#include "sokol_gfx.h" -#define SOKOL_SPINE_IMPL -#include "spine/spine.h" -#include "sokol_spine.h" -#include "utest.h" - -#define T(b) EXPECT_TRUE(b) - -static sspine_log_item last_logitem = SSPINE_LOGITEM_OK; -static void log_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) { - (void)tag; (void)log_level; (void)message; (void)line_nr; (void)filename; (void)user_data; - last_logitem = log_item; -} - -static void init(void) { - last_logitem = SSPINE_LOGITEM_OK; - sg_setup(&(sg_desc){0}); - sspine_setup(&(sspine_desc){ .logger = { .func = log_func } }); -} - -static void init_with_desc(const sspine_desc* desc) { - last_logitem = SSPINE_LOGITEM_OK; - sspine_desc desc1 = *desc; - desc1.logger.func = log_func; - sg_setup(&(sg_desc){0}); - sspine_setup(&desc1); -} - -static void shutdown(void) { - sspine_shutdown(); - sg_shutdown(); -} - -// NOTE: this guarantees that the data is zero terminated because the loaded data -// might either be binary or text (the zero sentinel is NOT counted in the returned size) -static sspine_range load_data(const char* path) { - assert(path); - FILE* fp = fopen(path, "rb"); - assert(fp); - fseek(fp, 0, SEEK_END); - const size_t size = (size_t)ftell(fp); - fseek(fp, 0, SEEK_SET); - // room for terminating zero - const size_t alloc_size = size + 1; - uint8_t* ptr = (uint8_t*)malloc(alloc_size); - memset(ptr, 0, alloc_size); - // NOTE: GCC warns if result of fread() is ignored - size_t num_bytes = fread(ptr, size, 1, fp); - (void)num_bytes; - fclose(fp); - return (sspine_range) { .ptr = ptr, .size = size }; -} - -static void free_data(sspine_range r) { - free((void*)r.ptr); -} - -static sspine_atlas create_atlas(void) { - sspine_range atlas_data = load_data("spineboy.atlas"); - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = atlas_data - }); - free_data(atlas_data); - return atlas; -} - -static sspine_skeleton create_skeleton_json(sspine_atlas atlas) { - sspine_range skeleton_json_data = load_data("spineboy-pro.json"); - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .json_data = (const char*)skeleton_json_data.ptr - }); - free_data(skeleton_json_data); - return skeleton; -} - -static sspine_skeleton create_skeleton_binary(sspine_atlas atlas) { - sspine_range skeleton_binary_data = load_data("spineboy-pro.skel"); - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .binary_data = skeleton_binary_data - }); - free_data(skeleton_binary_data); - return skeleton; -} - -static sspine_skeleton create_skeleton(void) { - return create_skeleton_json(create_atlas()); -} - -static sspine_instance create_instance(void) { - return sspine_make_instance(&(sspine_instance_desc){ - .skeleton = create_skeleton(), - }); -} - -UTEST(sokol_spine, default_init_shutdown) { - // FIXME! - T(true); -} - -UTEST(sokol_spine, atlas_pool_exhausted) { - init_with_desc(&(sspine_desc){ - .atlas_pool_size = 4, - }); - for (int i = 0; i < 4; i++) { - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){0}); - T(sspine_get_atlas_resource_state(atlas) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_ATLAS_DESC_NO_DATA); - } - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){0}); - T(SSPINE_INVALID_ID == atlas.id); - T(sspine_get_atlas_resource_state(atlas) == SSPINE_RESOURCESTATE_INVALID); - T(last_logitem == SSPINE_LOGITEM_ATLAS_POOL_EXHAUSTED); - shutdown(); -} - -UTEST(sokol_spine, make_destroy_atlas_ok) { - init(); - sspine_atlas atlas = create_atlas(); - T(sspine_get_atlas_resource_state(atlas) == SSPINE_RESOURCESTATE_VALID); - T(sspine_atlas_valid(atlas)); - sspine_destroy_atlas(atlas); - T(sspine_get_atlas_resource_state(atlas) == SSPINE_RESOURCESTATE_INVALID); - T(!sspine_atlas_valid(atlas)) - shutdown(); -} - -UTEST(sokol_spine, make_atlas_fail_no_data) { - init(); - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){0}); - T(atlas.id != SSPINE_INVALID_ID); - T(last_logitem == SSPINE_LOGITEM_ATLAS_DESC_NO_DATA); - T(sspine_get_atlas_resource_state(atlas) == SSPINE_RESOURCESTATE_FAILED); - T(!sspine_atlas_valid(atlas)); - shutdown(); -} - -// an invalid atlas must return zero number of images -UTEST(sokol_spine, failed_atlas_no_images) { - init(); - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){0}); - T(last_logitem == SSPINE_LOGITEM_ATLAS_DESC_NO_DATA); - T(atlas.id != SSPINE_INVALID_ID); - T(!sspine_atlas_valid(atlas)); - T(sspine_num_images(atlas) == 0); - shutdown(); - -} - -// NOTE: spine-c doesn't detect wrong/corrupt atlas file data, so we can't test for that - -UTEST(sokol_spine, image_valid) { - init(); - sspine_atlas atlas = create_atlas(); - T(sspine_image_valid(sspine_image_by_index(atlas, 0))); - T(!sspine_image_valid(sspine_image_by_index(atlas, 1))); - T(!sspine_image_valid(sspine_image_by_index(atlas, -1))); - sspine_destroy_atlas(atlas); - T(!sspine_image_valid(sspine_image_by_index(atlas, 0))); - shutdown(); -} - -UTEST(sokol_spine, atlas_image_info) { - init(); - sspine_atlas atlas = create_atlas(); - T(sspine_atlas_valid(atlas)); - T(sspine_num_images(atlas) == 1); - const sspine_image_info img_info = sspine_get_image_info(sspine_image_by_index(atlas, 0)); - T(img_info.valid); - T(img_info.sgimage.id != SG_INVALID_ID); - T(sg_query_image_state(img_info.sgimage) == SG_RESOURCESTATE_ALLOC); - T(strcmp(img_info.filename.cstr, "spineboy.png") == 0); - T(img_info.min_filter == SG_FILTER_LINEAR); - T(img_info.mag_filter == SG_FILTER_LINEAR); - T(img_info.wrap_u == SG_WRAP_CLAMP_TO_EDGE); - T(img_info.wrap_v == SG_WRAP_CLAMP_TO_EDGE); - T(img_info.width == 1024); - T(img_info.height == 256); - T(img_info.premul_alpha == false); - shutdown(); -} - -UTEST(sokol_spine, atlas_with_overrides) { - init(); - sspine_range atlas_data = load_data("spineboy.atlas"); - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = atlas_data, - .override = { - .min_filter = SG_FILTER_NEAREST, - .mag_filter = SG_FILTER_NEAREST, - .mipmap_filter = SG_FILTER_LINEAR, - .wrap_u = SG_WRAP_REPEAT, - .wrap_v = SG_WRAP_CLAMP_TO_EDGE, - .premul_alpha_enabled = true, - } - }); - T(sspine_atlas_valid(atlas)); - T(sspine_num_images(atlas) == 1); - const sspine_image_info img_info = sspine_get_image_info(sspine_image_by_index(atlas, 0)); - T(img_info.valid); - T(img_info.sgimage.id != SG_INVALID_ID); - T(sg_query_image_state(img_info.sgimage) == SG_RESOURCESTATE_ALLOC); - T(strcmp(img_info.filename.cstr, "spineboy.png") == 0); - T(img_info.min_filter == SG_FILTER_NEAREST); - T(img_info.mag_filter == SG_FILTER_NEAREST); - T(img_info.mipmap_filter == SG_FILTER_LINEAR); - T(img_info.wrap_u == SG_WRAP_REPEAT); - T(img_info.wrap_v == SG_WRAP_CLAMP_TO_EDGE); - T(img_info.width == 1024); - T(img_info.height == 256); - T(img_info.premul_alpha == true); - shutdown(); -} - -UTEST(sokol_spine, skeleton_pool_exhausted) { - init_with_desc(&(sspine_desc){ - .skeleton_pool_size = 4 - }); - for (int i = 0; i < 4; i++) { - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){0}); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_SKELETON_DESC_NO_DATA); - } - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){0}); - T(SSPINE_INVALID_ID == skeleton.id); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_INVALID); - T(last_logitem == SSPINE_LOGITEM_SKELETON_POOL_EXHAUSTED); - shutdown(); -} - -UTEST(sokol_spine, make_destroy_skeleton_json_ok) { - init(); - sspine_skeleton skeleton = create_skeleton_json(create_atlas()); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_VALID); - T(sspine_skeleton_valid(skeleton)); - sspine_destroy_skeleton(skeleton); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_INVALID); - T(!sspine_skeleton_valid(skeleton)); - shutdown(); -} - -UTEST(sokol_spine, make_destroy_skeleton_binary_ok) { - init(); - sspine_skeleton skeleton = create_skeleton_binary(create_atlas()); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_VALID); - T(sspine_skeleton_valid(skeleton)); - sspine_destroy_skeleton(skeleton); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_INVALID); - T(!sspine_skeleton_valid(skeleton)); - shutdown(); -} - -UTEST(sokol_spine, make_skeleton_fail_no_data) { - init(); - sspine_atlas atlas = create_atlas(); - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas - }); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_FAILED); - T(!sspine_skeleton_valid(skeleton)); - T(last_logitem == SSPINE_LOGITEM_SKELETON_DESC_NO_DATA); - shutdown(); -} - -UTEST(sokol_spine, make_skeleton_fail_no_atlas) { - init(); - sspine_range skeleton_json_data = load_data("spineboy-pro.json"); - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .json_data = (const char*)skeleton_json_data.ptr - }); - free_data(skeleton_json_data); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_FAILED); - T(!sspine_skeleton_valid(skeleton)); - T(last_logitem == SSPINE_LOGITEM_SKELETON_DESC_NO_ATLAS); - shutdown(); -} - -UTEST(sokol_spine, make_skeleton_fail_with_failed_atlas) { - init(); - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){0}); - T(last_logitem == SSPINE_LOGITEM_ATLAS_DESC_NO_DATA); - T(sspine_get_atlas_resource_state(atlas) == SSPINE_RESOURCESTATE_FAILED); - sspine_skeleton skeleton = create_skeleton_json(atlas); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_FAILED); - T(!sspine_skeleton_valid(skeleton)); - T(last_logitem == SSPINE_LOGITEM_SKELETON_ATLAS_NOT_VALID); - shutdown(); -} - -UTEST(sokol_spine, make_skeleton_json_fail_corrupt_data) { - init(); - sspine_atlas atlas = create_atlas(); - const char* invalid_json_data = "This is not valid JSON!"; - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .json_data = (const char*)invalid_json_data, - }); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_CREATE_SKELETON_DATA_FROM_JSON_FAILED); - sspine_destroy_skeleton(skeleton); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_INVALID); - shutdown(); -} - -// FIXME: this crashes the spine-c runtime -/* -UTEST(sokol_spine, make_skeleton_binary_fail_corrupt_data) { - init(); - sspine_atlas atlas = create_atlas(); - uint8_t invalid_binary_data[] = { 0x23, 0x63, 0x11, 0xFF }; - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .binary_data = { .ptr = invalid_binary_data, .size = sizeof(invalid_binary_data) } - }); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_FAILED); - sspine_destroy_skeleton(skeleton); - T(sspine_get_skeleton_resource_state(skeleton) == SSPINE_RESOURCESTATE_INVALID); - shutdown(); -} -*/ - -UTEST(sokol_spine, instance_pool_exhausted) { - init_with_desc(&(sspine_desc){ - .instance_pool_size = 4 - }); - for (int i = 0; i < 4; i++) { - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){0}); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_INSTANCE_DESC_NO_SKELETON); - } - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){0}); - T(SSPINE_INVALID_ID == instance.id); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_INVALID); - T(last_logitem == SSPINE_LOGITEM_INSTANCE_POOL_EXHAUSTED); - shutdown(); -} - -UTEST(sokol_spine, make_destroy_instance_ok) { - init(); - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = create_skeleton_json(create_atlas()) - }); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_VALID); - T(sspine_instance_valid(instance)); - sspine_destroy_instance(instance); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_INVALID); - T(!sspine_instance_valid(instance)); - shutdown(); -} - -UTEST(sokol_spine, make_instance_fail_no_skeleton) { - init(); - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){0}); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_INSTANCE_DESC_NO_SKELETON); - sspine_destroy_instance(instance); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_INVALID); - shutdown(); -} - -UTEST(sokol_spine, make_instance_fail_with_failed_skeleton) { - init(); - sspine_skeleton failed_skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){0}); - T(last_logitem == SSPINE_LOGITEM_SKELETON_DESC_NO_DATA); - T(sspine_get_skeleton_resource_state(failed_skeleton) == SSPINE_RESOURCESTATE_FAILED); - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = failed_skeleton - }); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_INSTANCE_SKELETON_NOT_VALID); - shutdown(); -} - -UTEST(sokol_spine, make_instance_fail_with_destroyed_atlas) { - init(); - sspine_atlas atlas = create_atlas(); - T(sspine_atlas_valid(atlas)); - sspine_skeleton skeleton = create_skeleton_json(atlas); - T(sspine_skeleton_valid(skeleton)); - sspine_destroy_atlas(atlas); - T(!sspine_atlas_valid(atlas)); - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = skeleton - }); - T(sspine_get_instance_resource_state(instance) == SSPINE_RESOURCESTATE_FAILED); - T(last_logitem == SSPINE_LOGITEM_INSTANCE_ATLAS_NOT_VALID); - shutdown(); -} - -UTEST(sokol_spine, get_skeleton_atlas) { - init(); - sspine_atlas atlas = create_atlas(); - sspine_skeleton skeleton = create_skeleton_json(atlas); - T(sspine_get_skeleton_atlas(skeleton).id == atlas.id); - sspine_destroy_skeleton(skeleton); - T(sspine_get_skeleton_atlas(skeleton).id == SSPINE_INVALID_ID); - shutdown(); -} - -UTEST(sokol_spine, get_instance_skeleton) { - init(); - sspine_atlas atlas = create_atlas(); - sspine_skeleton skeleton = create_skeleton_json(atlas); - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = skeleton - }); - T(sspine_get_instance_skeleton(instance).id == skeleton.id); - sspine_destroy_instance(instance); - T(sspine_get_instance_skeleton(instance).id == SSPINE_INVALID_ID); - shutdown(); -} - -UTEST(sokol_spine, set_get_position) { - init(); - sspine_instance instance = create_instance(); - sspine_set_position(instance, (sspine_vec2){ .x=1.0f, .y=2.0f }); - const sspine_vec2 pos = sspine_get_position(instance); - T(pos.x == 1.0f); - T(pos.y == 2.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_position_destroyed_instance) { - init(); - sspine_instance instance = create_instance(); - sspine_set_position(instance, (sspine_vec2){ .x=1.0f, .y=2.0f }); - sspine_destroy_instance(instance); - const sspine_vec2 pos = sspine_get_position(instance); - T(pos.x == 0.0f); - T(pos.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_scale) { - init(); - sspine_instance instance = create_instance(); - sspine_set_scale(instance, (sspine_vec2){ .x=2.0f, .y=3.0f }); - const sspine_vec2 scale = sspine_get_scale(instance); - T(scale.x == 2.0f); - T(scale.y == 3.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_scale_destroyed_instance) { - init(); - sspine_instance instance = create_instance(); - sspine_set_scale(instance, (sspine_vec2){ .x=2.0f, .y=3.0f }); - sspine_destroy_instance(instance); - const sspine_vec2 scale = sspine_get_scale(instance); - T(scale.x == 0.0f); - T(scale.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_color) { - init(); - sspine_instance instance = create_instance(); - sspine_set_color(instance, (sspine_color) { .r=1.0f, .g=2.0f, .b=3.0f, .a=4.0f }); - const sspine_color color = sspine_get_color(instance); - T(color.r == 1.0f); - T(color.g == 2.0f); - T(color.b == 3.0f); - T(color.a == 4.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_color_destroyed_instance) { - init(); - sspine_instance instance = create_instance(); - sspine_set_color(instance, (sspine_color) { .r=1.0f, .g=2.0f, .b=3.0f, .a=4.0f }); - sspine_destroy_instance(instance); - const sspine_color color = sspine_get_color(instance); - T(color.r == 0.0f); - T(color.g == 0.0f); - T(color.b == 0.0f); - T(color.a == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, anim_by_name) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_anim a0 = sspine_anim_by_name(skeleton, "hoverboard"); - T((a0.skeleton_id == skeleton.id) && (a0.index == 2)); - sspine_anim a1 = sspine_anim_by_name(skeleton, "bla"); - T((a1.skeleton_id == 0) && (a1.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, anim_by_name_destroyed_instance) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - sspine_anim a0 = sspine_anim_by_name(skeleton, "hoverboard"); - T((a0.skeleton_id == 0) && (a0.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, anim_valid) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_anim_valid(sspine_anim_by_index(skeleton, 0))); - T(sspine_anim_valid(sspine_anim_by_index(skeleton, 10))); - T(!sspine_anim_valid(sspine_anim_by_index(skeleton, -1))); - T(!sspine_anim_valid(sspine_anim_by_index(skeleton, 11))); - sspine_destroy_skeleton(skeleton); - T(!sspine_anim_valid(sspine_anim_by_index(skeleton, 0))); - shutdown(); -} - -UTEST(sokol_spine, anim_equal) { - init(); - T(sspine_anim_equal((sspine_anim){ 1, 2 }, (sspine_anim){ 1, 2 })); - T(!sspine_anim_equal((sspine_anim){ 2, 2 }, (sspine_anim){ 1, 2 })); - T(!sspine_anim_equal((sspine_anim){ 1, 3 }, (sspine_anim){ 1, 2 })); - shutdown(); -} - -UTEST(sokol_spine, num_anims) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_num_anims(skeleton) == 11); - sspine_destroy_skeleton(skeleton); - T(sspine_num_anims(skeleton) == 0); - shutdown(); -} - -UTEST(sokol_spine, get_anim_info) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_anim anim = sspine_anim_by_name(skeleton, "hoverboard"); - const sspine_anim_info info = sspine_get_anim_info(anim); - T(info.valid); - T(info.index == 2); - T(strcmp(info.name.cstr, "hoverboard") == 0); - T(info.duration == 1.0f); - shutdown(); -} - -UTEST(sokol_spine, get_anim_info_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_anim anim = sspine_anim_by_name(skeleton, "hoverboard"); - sspine_destroy_skeleton(skeleton); - const sspine_anim_info info = sspine_get_anim_info(anim); - T(!info.valid); - shutdown(); -} - -UTEST(sokol_spine, get_anim_info_invalid_index) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_anim_info i0 = sspine_get_anim_info(sspine_anim_by_index(skeleton, -1)); - T(!i0.valid); - T(!i0.name.valid); - const sspine_anim_info i1 = sspine_get_anim_info(sspine_anim_by_index(skeleton, 1234)); - T(!i1.valid); - T(!i1.name.valid); - shutdown(); -} - -UTEST(sokol_spine, atlas_page_valid) { - init(); - sspine_atlas atlas = create_atlas(); - T(sspine_atlas_page_valid(sspine_atlas_page_by_index(atlas, 0))); - T(!sspine_atlas_page_valid(sspine_atlas_page_by_index(atlas, -1))); - T(!sspine_atlas_page_valid(sspine_atlas_page_by_index(atlas, 1))); - sspine_destroy_atlas(atlas); - T(!sspine_atlas_page_valid(sspine_atlas_page_by_index(atlas, 0))); - shutdown(); -} - -UTEST(sokol_spine, num_atlas_pages) { - init(); - sspine_atlas atlas = create_atlas(); - T(sspine_num_atlas_pages(atlas) == 1); - sspine_destroy_atlas(atlas); - T(sspine_num_atlas_pages(atlas) == 0); - shutdown(); -} - -UTEST(sokol_spine, get_atlas_page_info) { - init(); - sspine_atlas atlas = create_atlas(); - const sspine_atlas_page_info info = sspine_get_atlas_page_info(sspine_atlas_page_by_index(atlas, 0)); - T(info.valid); - T(info.atlas.id == atlas.id); - T(info.image.valid); - T(info.image.sgimage.id != SG_INVALID_ID); - T(sg_query_image_state(info.image.sgimage) == SG_RESOURCESTATE_ALLOC); - T(strcmp(info.image.filename.cstr, "spineboy.png") == 0); - T(info.image.min_filter == SG_FILTER_LINEAR); - T(info.image.mag_filter == SG_FILTER_LINEAR); - T(info.image.wrap_u == SG_WRAP_CLAMP_TO_EDGE); - T(info.image.wrap_v == SG_WRAP_CLAMP_TO_EDGE); - T(info.image.width == 1024); - T(info.image.height == 256); - T(info.image.premul_alpha == false); - T(info.overrides.min_filter == _SG_FILTER_DEFAULT); - T(info.overrides.mag_filter == _SG_FILTER_DEFAULT); - T(info.overrides.wrap_u == _SG_WRAP_DEFAULT); - T(info.overrides.wrap_v == _SG_WRAP_DEFAULT); - T(!info.overrides.premul_alpha_enabled); - T(!info.overrides.premul_alpha_disabled); - shutdown(); -} - -UTEST(sokol_spine, get_atlas_page_info_destroyed_atlas) { - init(); - sspine_atlas atlas = create_atlas(); - sspine_destroy_atlas(atlas); - const sspine_atlas_page_info info = sspine_get_atlas_page_info(sspine_atlas_page_by_index(atlas, 0)); - T(!info.valid); - T(info.atlas.id == SSPINE_INVALID_ID); - shutdown(); -} - -UTEST(sokol_spine, get_atlas_page_info_invalid_index) { - init(); - sspine_atlas atlas = create_atlas(); - sspine_destroy_atlas(atlas); - const sspine_atlas_page_info i0 = sspine_get_atlas_page_info(sspine_atlas_page_by_index(atlas, -1)); - T(!i0.valid); - T(i0.atlas.id == SSPINE_INVALID_ID); - const sspine_atlas_page_info i1 = sspine_get_atlas_page_info(sspine_atlas_page_by_index(atlas, 1234)); - T(!i0.valid); - T(i1.atlas.id == SSPINE_INVALID_ID); - shutdown(); -} - -UTEST(sokol_spine, atlas_get_atlas_page_info_with_overrides) { - init(); - sspine_range atlas_data = load_data("spineboy.atlas"); - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = atlas_data, - .override = { - .min_filter = SG_FILTER_NEAREST, - .mag_filter = SG_FILTER_NEAREST, - .mipmap_filter = SG_FILTER_NEAREST, - .wrap_u = SG_WRAP_REPEAT, - .wrap_v = SG_WRAP_CLAMP_TO_EDGE, - .premul_alpha_enabled = true, - } - }); - const sspine_atlas_page_info info = sspine_get_atlas_page_info(sspine_atlas_page_by_index(atlas, 0)); - T(info.valid); - T(info.atlas.id == atlas.id); - T(info.image.valid); - T(info.image.sgimage.id != SG_INVALID_ID); - T(sg_query_image_state(info.image.sgimage) == SG_RESOURCESTATE_ALLOC); - T(strcmp(info.image.filename.cstr, "spineboy.png") == 0); - T(info.image.min_filter == SG_FILTER_LINEAR); - T(info.image.mag_filter == SG_FILTER_LINEAR); - T(info.image.mipmap_filter == SG_FILTER_NONE); - T(info.image.wrap_u == SG_WRAP_CLAMP_TO_EDGE); - T(info.image.wrap_v == SG_WRAP_CLAMP_TO_EDGE); - T(info.image.width == 1024); - T(info.image.height == 256); - T(info.image.premul_alpha == true); // FIXME: hmm, this is actually inconsistent - T(info.overrides.min_filter == SG_FILTER_NEAREST); - T(info.overrides.mag_filter == SG_FILTER_NEAREST); - T(info.overrides.mipmap_filter == SG_FILTER_NEAREST); - T(info.overrides.wrap_u == SG_WRAP_REPEAT); - T(info.overrides.wrap_v == SG_WRAP_CLAMP_TO_EDGE); - T(info.overrides.premul_alpha_enabled); - T(!info.overrides.premul_alpha_disabled); - shutdown(); -} - -UTEST(sokol_spine, bone_by_name) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_bone b0 = sspine_bone_by_name(skeleton, "crosshair"); - T((b0.skeleton_id == skeleton.id) && (b0.index == 2)); - sspine_bone b1 = sspine_bone_by_name(skeleton, "blablub"); - T((b1.skeleton_id == 0) && (b1.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, bone_by_name_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - sspine_bone b0 = sspine_bone_by_name(skeleton, "crosshair"); - T((b0.skeleton_id == 0) && (b0.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, bone_valid) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_bone_valid(sspine_bone_by_index(skeleton, 0))); - T(sspine_bone_valid(sspine_bone_by_index(skeleton, 66))); - T(!sspine_bone_valid(sspine_bone_by_index(skeleton, -1))); - T(!sspine_bone_valid(sspine_bone_by_index(skeleton, 67))); - sspine_destroy_skeleton(skeleton); - T(!sspine_bone_valid(sspine_bone_by_index(skeleton, 0))); - shutdown(); -} - -UTEST(sokol_spine, bone_equal) { - init(); - T(sspine_bone_equal((sspine_bone){ 1, 2 }, (sspine_bone){ 1, 2 })); - T(!sspine_bone_equal((sspine_bone){ 2, 2 }, (sspine_bone){ 1, 2 })); - T(!sspine_bone_equal((sspine_bone){ 1, 3 }, (sspine_bone){ 1, 2 })); - shutdown(); -} - -UTEST(sokol_spine, num_bones) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_num_bones(skeleton) == 67); - sspine_destroy_skeleton(skeleton); - T(sspine_num_bones(skeleton) == 0); - shutdown(); -} - -UTEST(sokol_spine, get_bone_info_root) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_bone_info info = sspine_get_bone_info(sspine_bone_by_name(skeleton, "root")); - T(info.valid); - T(info.index == 0); - T((info.parent_bone.skeleton_id == 0) && (info.parent_bone.index == 0)); - T(strcmp(info.name.cstr, "root") == 0); - T(info.length == 0.0f); - T(info.pose.position.x == 0.0f); - T(info.pose.position.y == 0.0f); - T(info.pose.rotation == 0.05f); - T(info.pose.scale.x == 1.0f); - T(info.pose.scale.y == 1.0f); - T(info.pose.shear.x == 0.0f); - T(info.pose.shear.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, get_bone_info_parent_bone) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_bone_info info = sspine_get_bone_info(sspine_bone_by_name(skeleton, "rear-shin")); - T(info.valid); - T(info.index == 7); - T((info.parent_bone.skeleton_id == skeleton.id) && (info.parent_bone.index == 6)); - shutdown(); -} - -UTEST(sokol_spine, get_bone_info_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_destroy_skeleton(skeleton); - const sspine_bone_info info = sspine_get_bone_info(bone); - T(!info.valid); - T(!info.name.valid); - shutdown(); -} - -UTEST(sokol_spine, get_bone_info_invalid_index) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_bone_info i0 = sspine_get_bone_info(sspine_bone_by_index(skeleton, -1)); - T(!i0.valid); - T(!i0.name.valid); - const sspine_bone_info i1 = sspine_get_bone_info(sspine_bone_by_index(skeleton, 1234)); - T(!i1.valid); - T(!i1.name.valid); - shutdown(); -} - -UTEST(sokol_spine, set_get_bone_transform) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_set_bone_transform(instance, bone, &(sspine_bone_transform){ - .position = { 1.0f, 2.0f }, - .rotation = 3.0f, - .scale = { 4.0f, 5.0f }, - .shear = { 6.0f, 7.0f } - }); - const sspine_bone_transform tform = sspine_get_bone_transform(instance, bone); - T(tform.position.x == 1.0f); - T(tform.position.y == 2.0f); - T(tform.rotation == 3.0f); - T(tform.scale.x == 4.0f); - T(tform.scale.y == 5.0f); - T(tform.shear.x == 6.0f); - T(tform.shear.y == 7.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_bone_transform_destroyed_instance) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_destroy_instance(instance); - sspine_set_bone_transform(instance, bone, &(sspine_bone_transform){ - .position = { 1.0f, 2.0f }, - .rotation = 3.0f, - .scale = { 4.0f, 5.0f }, - .shear = { 6.0f, 7.0f } - }); - const sspine_bone_transform tform = sspine_get_bone_transform(instance, bone); - T(tform.position.x == 0.0f); - T(tform.position.y == 0.0f); - T(tform.rotation == 0.0f); - T(tform.scale.x == 0.0f); - T(tform.scale.y == 0.0f); - T(tform.shear.x == 0.0f); - T(tform.shear.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_bone_position) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_set_bone_position(instance, bone, (sspine_vec2){ 1.0f, 2.0f }); - const sspine_vec2 p0 = sspine_get_bone_position(instance, bone); - T(p0.x == 1.0f); - T(p0.y == 2.0f); - sspine_destroy_instance(instance); - const sspine_vec2 p1 = sspine_get_bone_position(instance, bone); - T(p1.x == 0.0f); - T(p1.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_bone_rotation) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_set_bone_rotation(instance, bone, 5.0f); - T(sspine_get_bone_rotation(instance, bone) == 5.0f); - sspine_destroy_instance(instance); - T(sspine_get_bone_rotation(instance, bone) == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_bone_scale) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_set_bone_scale(instance, bone, (sspine_vec2){ 1.0f, 2.0f }); - const sspine_vec2 s0 = sspine_get_bone_scale(instance, bone); - T(s0.x == 1.0f); - T(s0.y == 2.0f); - sspine_destroy_instance(instance); - const sspine_vec2 s1 = sspine_get_bone_scale(instance, bone); - T(s1.x == 0.0f); - T(s1.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, set_get_bone_shear) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - sspine_set_bone_shear(instance, bone, (sspine_vec2){ 1.0f, 2.0f }); - const sspine_vec2 s0 = sspine_get_bone_shear(instance, bone); - T(s0.x == 1.0f); - T(s0.y == 2.0f); - sspine_destroy_instance(instance); - const sspine_vec2 s1 = sspine_get_bone_shear(instance, bone); - T(s1.x == 0.0f); - T(s1.y == 0.0f); - shutdown(); -} - -UTEST(sokol_spine, slot_by_name) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_slot s0 = sspine_slot_by_name(skeleton, "portal-streaks1"); - T((s0.skeleton_id == skeleton.id) && (s0.index == 3)); - sspine_slot s1 = sspine_slot_by_name(skeleton, "blablub"); - T((s1.skeleton_id == 0) && (s1.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, slot_by_name_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - sspine_slot s0 = sspine_slot_by_name(skeleton, "portal-streaks1"); - T((s0.skeleton_id == 0) && (s0.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, num_slots) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_num_slots(skeleton) == 52); - sspine_destroy_skeleton(skeleton); - T(sspine_num_slots(skeleton) == 0); - shutdown(); -} - -UTEST(sokol_spine, slot_valid) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_slot_valid(sspine_slot_by_index(skeleton, 0))); - T(sspine_slot_valid(sspine_slot_by_index(skeleton, 51))); - T(!sspine_slot_valid(sspine_slot_by_index(skeleton, -1))); - T(!sspine_slot_valid(sspine_slot_by_index(skeleton, 52))); - sspine_destroy_skeleton(skeleton); - T(!sspine_slot_valid(sspine_slot_by_index(skeleton, 0))); - shutdown(); -} - -UTEST(sokol_spine, slot_equal) { - init(); - T(sspine_slot_equal((sspine_slot){ 1, 2 }, (sspine_slot){ 1, 2 })); - T(!sspine_slot_equal((sspine_slot){ 2, 2 }, (sspine_slot){ 1, 2 })); - T(!sspine_slot_equal((sspine_slot){ 1, 3 }, (sspine_slot){ 1, 2 })); - shutdown(); -} - -UTEST(sokol_spine, get_slot_info) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_slot_info info = sspine_get_slot_info(sspine_slot_by_name(skeleton, "portal-streaks1")); - T(info.valid); - T(info.index == 3); - T(strcmp(info.name.cstr, "portal-streaks1") == 0); - T(!info.attachment_name.valid); - T((info.bone.skeleton_id == skeleton.id) && (info.bone.index == 62)); - T(info.color.r == 1.0f); - T(info.color.g == 1.0f); - T(info.color.b == 1.0f); - T(info.color.a == 1.0f); - shutdown(); -} - -UTEST(sokol_spine, get_slot_info_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_slot slot = sspine_slot_by_name(skeleton, "portal-streaks1"); - sspine_destroy_skeleton(skeleton); - const sspine_slot_info info = sspine_get_slot_info(slot); - T(!info.valid); - T(!info.name.valid); - shutdown(); -} - -UTEST(sokol_spine, get_slot_info_invalid_index) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_slot_info i0 = sspine_get_slot_info(sspine_slot_by_index(skeleton, -1)); - T(!i0.valid); - T(!i0.name.valid); - const sspine_slot_info i1 = sspine_get_slot_info(sspine_slot_by_index(skeleton, 1234)); - T(!i1.valid); - T(!i1.name.valid); - shutdown(); -} - -UTEST(sokol_spine, set_get_slot_color) { - init(); - sspine_instance instance = create_instance(); - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - sspine_slot slot = sspine_slot_by_name(skeleton, "portal-streaks1"); - sspine_set_slot_color(instance, slot, (sspine_color){ 1.0f, 2.0f, 3.0f, 4.0f }); - const sspine_color color = sspine_get_slot_color(instance, slot); - T(color.r == 1.0f); - T(color.g == 2.0f); - T(color.b == 3.0f); - T(color.a == 4.0f); - const sspine_slot_info info = sspine_get_slot_info(slot); - T(info.color.r == 1.0f); - T(info.color.g == 1.0f); - T(info.color.b == 1.0f); - T(info.color.a == 1.0f); - shutdown(); -} - -UTEST(sokol_spine, event_by_name) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_event e0 = sspine_event_by_name(skeleton, "footstep"); - T((e0.skeleton_id == skeleton.id) && (e0.index == 0)); - sspine_event e1 = sspine_event_by_name(skeleton, "bla"); - T((e1.skeleton_id == 0) && (e1.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, event_by_name_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - sspine_event e0 = sspine_event_by_name(skeleton, "footstep"); - T((e0.skeleton_id == 0) && (e0.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, event_valid) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_event_valid(sspine_event_by_index(skeleton, 0))); - T(!sspine_event_valid(sspine_event_by_index(skeleton, 1))); - T(!sspine_event_valid(sspine_event_by_index(skeleton, -1))); - sspine_destroy_skeleton(skeleton); - T(!sspine_event_valid(sspine_event_by_index(skeleton, 0))); - shutdown(); -} - -UTEST(sokol_spine, event_equal) { - init(); - T(sspine_event_equal((sspine_event){ 1, 2 }, (sspine_event){ 1, 2 })); - T(!sspine_event_equal((sspine_event){ 2, 2 }, (sspine_event){ 1, 2 })); - T(!sspine_event_equal((sspine_event){ 1, 3 }, (sspine_event){ 1, 2 })); - shutdown(); -} - -UTEST(sokol_spine, num_events) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_num_events(skeleton) == 1); - sspine_destroy_skeleton(skeleton); - T(sspine_num_events(skeleton) == 0); - shutdown(); -} - -UTEST(sokol_spine, get_event_info) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_event_info info = sspine_get_event_info(sspine_event_by_index(skeleton, 0)); - T(info.valid); - T(0 == strcmp(info.name.cstr, "footstep")); - T(0 == info.index); - T(0 == info.int_value); - T(0.0f == info.float_value); - T(!info.string_value.valid); - T(!info.audio_path.valid); - T(0.0f == info.volume); - T(0.0f == info.balance); - shutdown(); -} - -UTEST(sokol_spine, get_event_info_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - const sspine_event_info info = sspine_get_event_info(sspine_event_by_index(skeleton, 0)); - T(!info.valid); - T(!info.name.valid); - shutdown(); -} - -UTEST(sokol_spine, iktarget_by_name) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_iktarget ik0 = sspine_iktarget_by_name(skeleton, "board-ik"); - T((ik0.skeleton_id == skeleton.id) && (ik0.index == 2)); - sspine_iktarget ik1 = sspine_iktarget_by_name(skeleton, "bla"); - T((ik1.skeleton_id == 0) && (ik1.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, iktarget_by_name_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - sspine_iktarget ik0 = sspine_iktarget_by_name(skeleton, "board-ik"); - T((ik0.skeleton_id == 0) && (ik0.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, iktarget_valid) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_iktarget_valid(sspine_iktarget_by_index(skeleton, 0))); - T(sspine_iktarget_valid(sspine_iktarget_by_index(skeleton, 6))); - T(!sspine_iktarget_valid(sspine_iktarget_by_index(skeleton, -1))); - T(!sspine_iktarget_valid(sspine_iktarget_by_index(skeleton, 7))); - sspine_destroy_skeleton(skeleton); - T(!sspine_iktarget_valid(sspine_iktarget_by_index(skeleton, 0))); - shutdown(); -} - -UTEST(sokol_spine, iktarget_equal) { - init(); - T(sspine_iktarget_equal((sspine_iktarget){ 1, 2 }, (sspine_iktarget){ 1, 2 })); - T(!sspine_iktarget_equal((sspine_iktarget){ 2, 2 }, (sspine_iktarget){ 1, 2 })); - T(!sspine_iktarget_equal((sspine_iktarget){ 1, 3 }, (sspine_iktarget){ 1, 2 })); - shutdown(); -} - -UTEST(sokol_spine, num_iktargets) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_num_iktargets(skeleton) == 7); - sspine_destroy_skeleton(skeleton); - T(sspine_num_iktargets(skeleton) == 0); - shutdown(); -} - -UTEST(sokol_spine, get_iktarget_info) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_iktarget_info info = sspine_get_iktarget_info(sspine_iktarget_by_index(skeleton, 1)); - T(info.valid); - T(1 == info.index); - T(0 == strcmp(info.name.cstr, "aim-torso-ik")); - T((info.target_bone.skeleton_id == skeleton.id) && (info.target_bone.index == 2)); - shutdown(); -} - -UTEST(sokol_spine, get_iktarget_info_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - const sspine_iktarget_info info = sspine_get_iktarget_info(sspine_iktarget_by_index(skeleton, 1)); - T(!info.valid); - T(!info.name.valid); - shutdown(); -} - -UTEST(sokol_spine, get_iktarget_info_out_of_bounds) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - const sspine_iktarget_info info0 = sspine_get_iktarget_info(sspine_iktarget_by_index(skeleton, -1)); - T(!info0.name.valid); - const sspine_iktarget_info info1 = sspine_get_iktarget_info(sspine_iktarget_by_index(skeleton, 7)); - T(!info1.name.valid); - shutdown(); -} - -UTEST(sokol_spine, skin_by_name) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_skin s0 = sspine_skin_by_name(skeleton, "default"); - T((s0.skeleton_id == skeleton.id) && (s0.index == 0)); - sspine_skin s1 = sspine_skin_by_name(skeleton, "bla"); - T((s1.skeleton_id == 0) && (s1.index == 0)); - sspine_destroy_skeleton(skeleton); - sspine_skin s2 = sspine_skin_by_name(skeleton, "default"); - T((s2.skeleton_id == 0) && (s2.index == 0)); - shutdown(); -} - -UTEST(sokol_spine, skin_valid) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_skin_valid(sspine_skin_by_index(skeleton, 0))); - T(!sspine_skin_valid(sspine_skin_by_index(skeleton, -1))); - T(!sspine_skin_valid(sspine_skin_by_index(skeleton, 1))); - sspine_destroy_skeleton(skeleton); - T(!sspine_skin_valid(sspine_skin_by_index(skeleton, 0))); - shutdown(); -} - -UTEST(sokol_spine, skin_equal) { - init(); - T(sspine_skin_equal((sspine_skin){ 1, 2 }, (sspine_skin){ 1, 2 })); - T(!sspine_skin_equal((sspine_skin){ 2, 2 }, (sspine_skin){ 1, 2 })); - T(!sspine_skin_equal((sspine_skin){ 1, 3 }, (sspine_skin){ 1, 2 })); - shutdown(); -} - -UTEST(sokol_spine, num_skins) { - init(); - sspine_skeleton skeleton = create_skeleton(); - T(sspine_num_skins(skeleton) == 1); - sspine_destroy_skeleton(skeleton); - T(sspine_num_skins(skeleton) == 0); - shutdown(); -} - -UTEST(sokol_spine, get_skin_info) { - init(); - sspine_skeleton skeleton = create_skeleton(); - const sspine_skin_info info = sspine_get_skin_info(sspine_skin_by_index(skeleton, 0)); - T(info.valid); - T(0 == info.index); - T(0 == strcmp(info.name.cstr, "default")); - shutdown(); -} - -UTEST(sokol_spine, get_skin_info_destroyed_skeleton) { - init(); - sspine_skeleton skeleton = create_skeleton(); - sspine_destroy_skeleton(skeleton); - const sspine_skin_info info = sspine_get_skin_info(sspine_skin_by_index(skeleton, 0)); - T(!info.valid); - T(!info.name.valid); - shutdown(); -} diff --git a/source/engine/thirdparty/sokol/tests/functional/sokol_test.c b/source/engine/thirdparty/sokol/tests/functional/sokol_test.c deleted file mode 100644 index 29528b6..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/sokol_test.c +++ /dev/null @@ -1,7 +0,0 @@ -//------------------------------------------------------------------------------ -// sokol-test.c -// Sokol headers main test source. -//------------------------------------------------------------------------------ -#include "utest.h" - -UTEST_MAIN(); diff --git a/source/engine/thirdparty/sokol/tests/functional/utest.h b/source/engine/thirdparty/sokol/tests/functional/utest.h deleted file mode 100644 index 0fe3023..0000000 --- a/source/engine/thirdparty/sokol/tests/functional/utest.h +++ /dev/null @@ -1,859 +0,0 @@ -/* - The latest version of this library is available on GitHub; - https://github.com/sheredom/utest.h -*/ - -/* - 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. - - For more information, please refer to -*/ - -#ifndef SHEREDOM_UTEST_H_INCLUDED -#define SHEREDOM_UTEST_H_INCLUDED - -#ifdef _MSC_VER -/* - Disable warning about not inlining 'inline' functions. - TODO: We'll fix this later by not using fprintf within our macros, and - instead use snprintf to a realloc'ed buffer. -*/ -#pragma warning(disable : 4710) - -/* - Disable warning about inlining functions that are not marked 'inline'. - TODO: add a UTEST_NOINLINE onto the macro generated functions to fix this. -*/ -#pragma warning(disable : 4711) -#pragma warning(push, 1) -#endif - -#if defined(_MSC_VER) -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif - -#include -#include -#include -#include - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#if defined(_MSC_VER) -#if defined(_M_IX86) -#define _X86_ -#endif - -#if defined(_M_AMD64) -#define _AMD64_ -#endif - -#pragma warning(push, 1) -#include -#include -#pragma warning(pop) - -#elif defined(__linux__) - -/* - slightly obscure include here - we need to include glibc's features.h, but - we don't want to just include a header that might not be defined for other - c libraries like musl. Instead we include limits.h, which we know on all - glibc distributions includes features.h -*/ -#include - -#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) -#include - -#if ((2 < __GLIBC__) || ((2 == __GLIBC__) && (17 <= __GLIBC_MINOR__))) -/* glibc is version 2.17 or above, so we can just use clock_gettime */ -#define UTEST_USE_CLOCKGETTIME -#else -#include -#include -#endif -#endif - -#elif defined(__APPLE__) -#include -#endif - -#if defined(_MSC_VER) -#define UTEST_PRId64 "I64d" -#define UTEST_PRIu64 "I64u" -#define UTEST_INLINE __forceinline - -#pragma section(".CRT$XCU", read) -#define UTEST_INITIALIZER(f) \ - static void __cdecl f(void); \ - __declspec(allocate(".CRT$XCU")) void(__cdecl * f##_)(void) = f; \ - static void __cdecl f(void) -#else -#if defined(__linux__) -#if defined(__clang__) -#if __has_warning("-Wreserved-id-macro") -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-id-macro" -#endif -#endif - -#define __STDC_FORMAT_MACROS 1 - -#if defined(__clang__) -#if __has_warning("-Wreserved-id-macro") -#pragma clang diagnostic pop -#endif -#endif -#endif - -#include - -#define UTEST_PRId64 PRId64 -#define UTEST_PRIu64 PRIu64 -#define UTEST_INLINE inline - -#define UTEST_INITIALIZER(f) \ - static void f(void) __attribute__((constructor)); \ - static void f(void) -#endif - -#if defined(__cplusplus) -#define UTEST_CAST(type, x) static_cast(x) -#define UTEST_PTR_CAST(type, x) reinterpret_cast(x) -#define UTEST_EXTERN extern "C" -#else -#define UTEST_CAST(type, x) ((type)x) -#define UTEST_PTR_CAST(type, x) ((type)x) -#define UTEST_EXTERN extern -#endif - -#ifdef _MSC_VER -/* - io.h contains definitions for some structures with natural padding. This is - uninteresting, but for some reason MSVC's behaviour is to warn about - including this system header. That *is* interesting -*/ -#pragma warning(disable : 4820) -#pragma warning(push, 1) -#include -#pragma warning(pop) -#define UTEST_COLOUR_OUTPUT() (_isatty(_fileno(stdout))) -#else -#include -#define UTEST_COLOUR_OUTPUT() (isatty(STDOUT_FILENO)) -#endif - -static UTEST_INLINE int64_t utest_ns(void) { -#ifdef _MSC_VER - LARGE_INTEGER counter; - LARGE_INTEGER frequency; - QueryPerformanceCounter(&counter); - QueryPerformanceFrequency(&frequency); - return UTEST_CAST(int64_t, - (counter.QuadPart * 1000000000) / frequency.QuadPart); -#elif defined(__linux) - struct timespec ts; - const clockid_t cid = CLOCK_REALTIME; -#if defined(UTEST_USE_CLOCKGETTIME) - clock_gettime(cid, &ts); -#else - syscall(SYS_clock_gettime, cid, &ts); -#endif - return UTEST_CAST(int64_t, ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec; -#elif __APPLE__ - return UTEST_CAST(int64_t, mach_absolute_time()); -#else - /* hack to prevent warning on unsupported platforms */ - return 1; -#endif -} - -typedef void (*utest_testcase_t)(int *, size_t); - -struct utest_test_state_s { - utest_testcase_t func; - size_t index; - char *name; -}; - -struct utest_state_s { - struct utest_test_state_s *tests; - size_t tests_length; - FILE *output; -}; - -/* extern to the global state utest needs to execute */ -UTEST_EXTERN struct utest_state_s utest_state; - -#if defined(_MSC_VER) -#define UTEST_WEAK __forceinline -#else -#define UTEST_WEAK __attribute__((weak)) -#endif - -#if defined(_MSC_VER) -#define UTEST_UNUSED -#else -#define UTEST_UNUSED __attribute__((unused)) -#endif - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wvariadic-macros" -#endif -#define UTEST_PRINTF(...) \ - if (utest_state.output) { \ - fprintf(utest_state.output, __VA_ARGS__); \ - } \ - printf(__VA_ARGS__) -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#ifdef _MSC_VER -#define UTEST_SNPRINTF(BUFFER, N, ...) _snprintf_s(BUFFER, N, N, __VA_ARGS__) -#else -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wvariadic-macros" -#endif -#define UTEST_SNPRINTF(...) snprintf(__VA_ARGS__) -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -#endif - -#if defined(__cplusplus) -/* if we are using c++ we can use overloaded methods (its in the language) */ -#define UTEST_OVERLOADABLE -#elif defined(__clang__) -/* otherwise, if we are using clang with c - use the overloadable attribute */ -#define UTEST_OVERLOADABLE __attribute__((overloadable)) -#endif - -#if defined(UTEST_OVERLOADABLE) -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) { - UTEST_PRINTF("%f", UTEST_CAST(double, f)); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) { - UTEST_PRINTF("%f", d); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) { - UTEST_PRINTF("%Lf", d); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) { - UTEST_PRINTF("%d", i); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) { - UTEST_PRINTF("%u", i); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) { - UTEST_PRINTF("%ld", i); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) { - UTEST_PRINTF("%lu", i); -} - -/* - long long is a c++11 extension - TODO: grok for c++11 version here -*/ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i); -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) { - UTEST_PRINTF("%lld", i); -} - -UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i); -UTEST_WEAK UTEST_OVERLOADABLE void -utest_type_printer(long long unsigned int i) { - UTEST_PRINTF("%llu", i); -} -#endif -#else -/* - we don't have the ability to print the values we got, so we create a macro - to tell our users we can't do anything fancy -*/ -#define utest_type_printer(...) UTEST_PRINTF("undef") -#endif - -#if defined(__clang__) -#define UTEST_EXPECT(x, y, cond) \ - { \ - _Pragma("clang diagnostic push") _Pragma( \ - "clang diagnostic ignored \"-Wlanguage-extension-token\"") typeof(y) \ - xEval = (x); \ - typeof(y) yEval = (y); \ - _Pragma("clang diagnostic pop") if (!((xEval)cond(yEval))) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : "); \ - utest_type_printer(xEval); \ - UTEST_PRINTF("\n"); \ - UTEST_PRINTF(" Actual : "); \ - utest_type_printer(yEval); \ - UTEST_PRINTF("\n"); \ - *utest_result = 1; \ - } \ - } -#elif defined(__GNUC__) -#define UTEST_EXPECT(x, y, cond) \ - { \ - typeof(y) xEval = (x); \ - typeof(y) yEval = (y); \ - if (!((xEval)cond(yEval))) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : "); \ - utest_type_printer(xEval); \ - UTEST_PRINTF("\n"); \ - UTEST_PRINTF(" Actual : "); \ - utest_type_printer(yEval); \ - UTEST_PRINTF("\n"); \ - *utest_result = 1; \ - } \ - } -#else -#define UTEST_EXPECT(x, y, cond) \ - { \ - if (!((x)cond(y))) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - *utest_result = 1; \ - } \ - } -#endif - -#define EXPECT_TRUE(x) \ - if (!(x)) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : true\n"); \ - UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ - *utest_result = 1; \ - } - -#define EXPECT_FALSE(x) \ - if (x) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : false\n"); \ - UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ - *utest_result = 1; \ - } - -#define EXPECT_EQ(x, y) UTEST_EXPECT(x, y, ==) -#define EXPECT_NE(x, y) UTEST_EXPECT(x, y, !=) -#define EXPECT_LT(x, y) UTEST_EXPECT(x, y, <) -#define EXPECT_LE(x, y) UTEST_EXPECT(x, y, <=) -#define EXPECT_GT(x, y) UTEST_EXPECT(x, y, >) -#define EXPECT_GE(x, y) UTEST_EXPECT(x, y, >=) - -#define EXPECT_STREQ(x, y) \ - if (0 != strcmp(x, y)) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : \"%s\"\n", x); \ - UTEST_PRINTF(" Actual : \"%s\"\n", y); \ - *utest_result = 1; \ - } - -#define EXPECT_STRNE(x, y) \ - if (0 == strcmp(x, y)) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : \"%s\"\n", x); \ - UTEST_PRINTF(" Actual : \"%s\"\n", y); \ - *utest_result = 1; \ - } - -#if defined(__clang__) -#define UTEST_ASSERT(x, y, cond) \ - { \ - _Pragma("clang diagnostic push") _Pragma( \ - "clang diagnostic ignored \"-Wlanguage-extension-token\"") typeof(y) \ - xEval = (x); \ - typeof(y) yEval = (y); \ - _Pragma("clang diagnostic pop") if (!((xEval)cond(yEval))) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : "); \ - utest_type_printer(xEval); \ - UTEST_PRINTF("\n"); \ - UTEST_PRINTF(" Actual : "); \ - utest_type_printer(yEval); \ - UTEST_PRINTF("\n"); \ - *utest_result = 1; \ - return; \ - } \ - } -#elif defined(__GNUC__) -#define UTEST_ASSERT(x, y, cond) \ - { \ - typeof(y) xEval = (x); \ - typeof(y) yEval = (y); \ - if (!((xEval)cond(yEval))) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : "); \ - utest_type_printer(xEval); \ - UTEST_PRINTF("\n"); \ - UTEST_PRINTF(" Actual : "); \ - utest_type_printer(yEval); \ - UTEST_PRINTF("\n"); \ - *utest_result = 1; \ - return; \ - } \ - } -#else -#define UTEST_ASSERT(x, y, cond) \ - { \ - if (!((x)cond(y))) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - *utest_result = 1; \ - return; \ - } \ - } -#endif - -#define ASSERT_TRUE(x) \ - if (!(x)) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : true\n"); \ - UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ - *utest_result = 1; \ - return; \ - } - -#define ASSERT_FALSE(x) \ - if (x) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : false\n"); \ - UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ - *utest_result = 1; \ - return; \ - } - -#define ASSERT_EQ(x, y) UTEST_ASSERT(x, y, ==) -#define ASSERT_NE(x, y) UTEST_ASSERT(x, y, !=) -#define ASSERT_LT(x, y) UTEST_ASSERT(x, y, <) -#define ASSERT_LE(x, y) UTEST_ASSERT(x, y, <=) -#define ASSERT_GT(x, y) UTEST_ASSERT(x, y, >) -#define ASSERT_GE(x, y) UTEST_ASSERT(x, y, >=) - -#define ASSERT_STREQ(x, y) \ - EXPECT_STREQ(x, y); \ - if (0 != strcmp(x, y)) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : \"%s\"\n", x); \ - UTEST_PRINTF(" Actual : \"%s\"\n", y); \ - *utest_result = 1; \ - return; \ - } - -#define ASSERT_STRNE(x, y) \ - EXPECT_STRNE(x, y); \ - if (0 == strcmp(x, y)) { \ - UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ - UTEST_PRINTF(" Expected : \"%s\"\n", x); \ - UTEST_PRINTF(" Actual : \"%s\"\n", y); \ - *utest_result = 1; \ - return; \ - } - -#define UTEST(SET, NAME) \ - UTEST_EXTERN struct utest_state_s utest_state; \ - static void utest_run_##SET##_##NAME(int *utest_result); \ - static void utest_##SET##_##NAME(int *utest_result, size_t utest_index) { \ - (void)utest_index; \ - utest_run_##SET##_##NAME(utest_result); \ - } \ - UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \ - const size_t index = utest_state.tests_length++; \ - const char *name_part = #SET "." #NAME; \ - const size_t name_size = strlen(name_part) + 1; \ - char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ - utest_state.tests = \ - UTEST_PTR_CAST(struct utest_test_state_s *, \ - realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ - sizeof(struct utest_test_state_s) * \ - utest_state.tests_length)); \ - utest_state.tests[index].func = &utest_##SET##_##NAME; \ - utest_state.tests[index].name = name; \ - UTEST_SNPRINTF(name, name_size, "%s", name_part); \ - } \ - void utest_run_##SET##_##NAME(int *utest_result) - -#define UTEST_F_SETUP(FIXTURE) \ - static void utest_f_setup_##FIXTURE(int *utest_result, \ - struct FIXTURE *utest_fixture) - -#define UTEST_F_TEARDOWN(FIXTURE) \ - static void utest_f_teardown_##FIXTURE(int *utest_result, \ - struct FIXTURE *utest_fixture) - -#define UTEST_F(FIXTURE, NAME) \ - UTEST_EXTERN struct utest_state_s utest_state; \ - static void utest_f_setup_##FIXTURE(int *, struct FIXTURE *); \ - static void utest_f_teardown_##FIXTURE(int *, struct FIXTURE *); \ - static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \ - static void utest_f_##FIXTURE##_##NAME(int *utest_result, \ - size_t utest_index) { \ - struct FIXTURE fixture; \ - (void)utest_index; \ - memset(&fixture, 0, sizeof(fixture)); \ - utest_f_setup_##FIXTURE(utest_result, &fixture); \ - if (0 != *utest_result) { \ - return; \ - } \ - utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \ - utest_f_teardown_##FIXTURE(utest_result, &fixture); \ - } \ - UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \ - const size_t index = utest_state.tests_length++; \ - const char *name_part = #FIXTURE "." #NAME; \ - const size_t name_size = strlen(name_part) + 1; \ - char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ - utest_state.tests = \ - UTEST_PTR_CAST(struct utest_test_state_s *, \ - realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ - sizeof(struct utest_test_state_s) * \ - utest_state.tests_length)); \ - utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \ - utest_state.tests[index].name = name; \ - UTEST_SNPRINTF(name, name_size, "%s", name_part); \ - } \ - void utest_run_##FIXTURE##_##NAME(int *utest_result, \ - struct FIXTURE *utest_fixture) - -#define UTEST_I_SETUP(FIXTURE) \ - static void utest_i_setup_##FIXTURE( \ - int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) - -#define UTEST_I_TEARDOWN(FIXTURE) \ - static void utest_i_teardown_##FIXTURE( \ - int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) - -#define UTEST_I(FIXTURE, NAME, INDEX) \ - UTEST_EXTERN struct utest_state_s utest_state; \ - static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \ - static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ - size_t index) { \ - struct FIXTURE fixture; \ - memset(&fixture, 0, sizeof(fixture)); \ - utest_i_setup_##FIXTURE(utest_result, &fixture, index); \ - if (0 != *utest_result) { \ - return; \ - } \ - utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \ - utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \ - } \ - UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \ - size_t i; \ - uint64_t iUp; \ - for (i = 0; i < (INDEX); i++) { \ - const size_t index = utest_state.tests_length++; \ - const char *name_part = #FIXTURE "." #NAME; \ - const size_t name_size = strlen(name_part) + 32; \ - char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ - utest_state.tests = \ - UTEST_PTR_CAST(struct utest_test_state_s *, \ - realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ - sizeof(struct utest_test_state_s) * \ - utest_state.tests_length)); \ - utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \ - utest_state.tests[index].index = i; \ - utest_state.tests[index].name = name; \ - iUp = UTEST_CAST(uint64_t, i); \ - UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \ - } \ - } \ - void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ - struct FIXTURE *utest_fixture) - -UTEST_WEAK -int utest_should_filter_test(const char *filter, const char *testcase); -UTEST_WEAK int utest_should_filter_test(const char *filter, - const char *testcase) { - if (filter) { - const char *filter_cur = filter; - const char *testcase_cur = testcase; - const char *filter_wildcard = 0; - - while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) { - if ('*' == *filter_cur) { - /* store the position of the wildcard */ - filter_wildcard = filter_cur; - - /* skip the wildcard character */ - filter_cur++; - - while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) { - if ('*' == *filter_cur) { - /* - we found another wildcard (filter is something like *foo*) so we - exit the current loop, and return to the parent loop to handle - the wildcard case - */ - break; - } else if (*filter_cur != *testcase_cur) { - /* otherwise our filter didn't match, so reset it */ - filter_cur = filter_wildcard; - } - - /* move testcase along */ - testcase_cur++; - - /* move filter along */ - filter_cur++; - } - - if (('\0' == *filter_cur) && ('\0' == *testcase_cur)) { - return 0; - } - - /* if the testcase has been exhausted, we don't have a match! */ - if ('\0' == *testcase_cur) { - return 1; - } - } else { - if (*testcase_cur != *filter_cur) { - /* test case doesn't match filter */ - return 1; - } else { - /* move our filter and testcase forward */ - testcase_cur++; - filter_cur++; - } - } - } - - if (('\0' != *filter_cur) || - (('\0' != *testcase_cur) && - ((filter == filter_cur) || ('*' != filter_cur[-1])))) { - /* we have a mismatch! */ - return 1; - } - } - - return 0; -} - -static UTEST_INLINE int utest_strncmp(const char *a, const char *b, size_t n) { - /* strncmp breaks on Wall / Werror on gcc/clang, so we avoid using it */ - unsigned i; - - for (i = 0; i < n; i++) { - if (a[i] < b[i]) { - return -1; - } else if (a[i] > b[i]) { - return 1; - } - } - - return 0; -} - -static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) { -#ifdef _MSC_VER - FILE *file; - if (0 == fopen_s(&file, filename, mode)) { - return file; - } else { - return 0; - } -#else - return fopen(filename, mode); -#endif -} - -UTEST_WEAK int utest_main(int argc, const char *const argv[]); -UTEST_WEAK int utest_main(int argc, const char *const argv[]) { - uint64_t failed = 0; - size_t index = 0; - size_t *failed_testcases = 0; - size_t failed_testcases_length = 0; - const char *filter = 0; - uint64_t ran_tests = 0; - - enum colours { RESET, GREEN, RED }; - - const int use_colours = UTEST_COLOUR_OUTPUT(); - const char *colours[] = {"\033[0m", "\033[32m", "\033[31m"}; - if (!use_colours) { - for (index = 0; index < sizeof colours / sizeof colours[0]; index++) { - colours[index] = ""; - } - } - /* loop through all arguments looking for our options */ - for (index = 1; index < UTEST_CAST(size_t, argc); index++) { - const char help_str[] = "--help"; - const char filter_str[] = "--filter="; - const char output_str[] = "--output="; - - if (0 == utest_strncmp(argv[index], help_str, strlen(help_str))) { - printf("utest.h - the single file unit testing solution for C/C++!\n" - "Command line Options:\n" - " --help Show this message and exit.\n" - " --filter= Filter the test cases to run (EG. MyTest*.a " - "would run MyTestCase.a but not MyTestCase.b).\n" - " --output= Output an xunit XML file to the file " - "specified in .\n"); - goto cleanup; - } else if (0 == - utest_strncmp(argv[index], filter_str, strlen(filter_str))) { - /* user wants to filter what test cases run! */ - filter = argv[index] + strlen(filter_str); - } else if (0 == - utest_strncmp(argv[index], output_str, strlen(output_str))) { - utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+"); - } - } - - for (index = 0; index < utest_state.tests_length; index++) { - if (utest_should_filter_test(filter, utest_state.tests[index].name)) { - continue; - } - - ran_tests++; - } - - printf("%s[==========]%s Running %" UTEST_PRIu64 " test cases.\n", - colours[GREEN], colours[RESET], UTEST_CAST(uint64_t, ran_tests)); - - if (utest_state.output) { - fprintf(utest_state.output, "\n"); - fprintf(utest_state.output, - "\n", - UTEST_CAST(uint64_t, ran_tests)); - fprintf(utest_state.output, - "\n", - UTEST_CAST(uint64_t, ran_tests)); - } - - for (index = 0; index < utest_state.tests_length; index++) { - int result = 0; - int64_t ns = 0; - - if (utest_should_filter_test(filter, utest_state.tests[index].name)) { - continue; - } - - printf("%s[ RUN ]%s %s\n", colours[GREEN], colours[RESET], - utest_state.tests[index].name); - - if (utest_state.output) { - fprintf(utest_state.output, "", - utest_state.tests[index].name); - } - - ns = utest_ns(); - utest_state.tests[index].func(&result, utest_state.tests[index].index); - ns = utest_ns() - ns; - - if (utest_state.output) { - fprintf(utest_state.output, "\n"); - } - - if (0 != result) { - const size_t failed_testcase_index = failed_testcases_length++; - failed_testcases = UTEST_PTR_CAST( - size_t *, realloc(UTEST_PTR_CAST(void *, failed_testcases), - sizeof(size_t) * failed_testcases_length)); - failed_testcases[failed_testcase_index] = index; - failed++; - printf("%s[ FAILED ]%s %s (%" UTEST_PRId64 "ns)\n", colours[RED], - colours[RESET], utest_state.tests[index].name, ns); - } else { - printf("%s[ OK ]%s %s (%" UTEST_PRId64 "ns)\n", colours[GREEN], - colours[RESET], utest_state.tests[index].name, ns); - } - } - - printf("%s[==========]%s %" UTEST_PRIu64 " test cases ran.\n", colours[GREEN], - colours[RESET], ran_tests); - printf("%s[ PASSED ]%s %" UTEST_PRIu64 " tests.\n", colours[GREEN], - colours[RESET], ran_tests - failed); - - if (0 != failed) { - printf("%s[ FAILED ]%s %" UTEST_PRIu64 " tests, listed below:\n", - colours[RED], colours[RESET], failed); - for (index = 0; index < failed_testcases_length; index++) { - printf("%s[ FAILED ]%s %s\n", colours[RED], colours[RESET], - utest_state.tests[failed_testcases[index]].name); - } - } - - if (utest_state.output) { - fprintf(utest_state.output, "\n\n"); - } - -cleanup: - for (index = 0; index < utest_state.tests_length; index++) { - free(UTEST_PTR_CAST(void *, utest_state.tests[index].name)); - } - - free(UTEST_PTR_CAST(void *, failed_testcases)); - free(UTEST_PTR_CAST(void *, utest_state.tests)); - - if (utest_state.output) { - fclose(utest_state.output); - } - - return UTEST_CAST(int, failed); -} - -/* - we need, in exactly one source file, define the global struct that will hold - the data we need to run utest. This macro allows the user to declare the - data without having to use the UTEST_MAIN macro, thus allowing them to write - their own main() function. -*/ -#define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0} - -/* - define a main() function to call into utest.h and start executing tests! A - user can optionally not use this macro, and instead define their own main() - function and manually call utest_main. The user must, in exactly one source - file, use the UTEST_STATE macro to declare a global struct variable that - utest requires. -*/ -#define UTEST_MAIN() \ - UTEST_STATE(); \ - int main(int argc, const char *const argv[]) { \ - return utest_main(argc, argv); \ - } - -#endif /* SHEREDOM_UTEST_H_INCLUDED */ diff --git a/source/engine/thirdparty/sokol/tests/test_android.sh b/source/engine/thirdparty/sokol/tests/test_android.sh deleted file mode 100755 index 88fb1c9..0000000 --- a/source/engine/thirdparty/sokol/tests/test_android.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -e -source test_common.sh -setup_android -build android_debug android_debug -build android_release android_release -build android_sles_debug android_sles_debug -build android_sles_release android_sles_release diff --git a/source/engine/thirdparty/sokol/tests/test_common.sh b/source/engine/thirdparty/sokol/tests/test_common.sh deleted file mode 100644 index 43f056b..0000000 --- a/source/engine/thirdparty/sokol/tests/test_common.sh +++ /dev/null @@ -1,50 +0,0 @@ -setup_emsdk() { - if [ ! -d "build/emsdk" ] ; then - mkdir -p build && cd build - git clone https://github.com/emscripten-core/emsdk.git - cd emsdk - ./emsdk install latest - ./emsdk activate latest - cd ../.. - fi - source build/emsdk/emsdk_env.sh -} - -setup_android() { - if [ ! -d "build/android_sdk" ] ; then - mkdir -p build/android_sdk && cd build/android_sdk - sdk_file="sdk-tools-linux-3859397.zip" - wget --no-verbose https://dl.google.com/android/repository/$sdk_file - unzip -q $sdk_file - cd tools/bin - yes | ./sdkmanager "platforms;android-28" >/dev/null - yes | ./sdkmanager "build-tools;29.0.3" >/dev/null - yes | ./sdkmanager "platform-tools" >/dev/null - yes | ./sdkmanager "ndk-bundle" >/dev/null - cd ../../../.. - fi -} - -build() { - gen_preset=$1 - build_preset=$2 - cmake --preset $gen_preset - cmake --build --preset $build_preset -} - -analyze() { - cfg=$1 - backend=$2 - mode=$3 - mkdir -p build/$cfg && cd build/$cfg - cmake -GNinja -DSOKOL_BACKEND=$backend -DCMAKE_BUILD_TYPE=$mode -DUSE_ANALYZER=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ../.. - cmake --build . - cd ../.. -} - -runtest() { - cfg=$1 - cd build/$cfg - ./sokol-test - cd ../../.. -} diff --git a/source/engine/thirdparty/sokol/tests/test_emscripten.sh b/source/engine/thirdparty/sokol/tests/test_emscripten.sh deleted file mode 100755 index aff4b08..0000000 --- a/source/engine/thirdparty/sokol/tests/test_emscripten.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -e -source test_common.sh -setup_emsdk -build emsc_webgl2_debug emsc_webgl2_debug -build emsc_webgl2_release emsc_webgl2_release -build emsc_wgpu_debug emsc_wgpu_debug -build emsc_wgpu_release emsc_wgpu_release diff --git a/source/engine/thirdparty/sokol/tests/test_ios.sh b/source/engine/thirdparty/sokol/tests/test_ios.sh deleted file mode 100755 index 39e8868..0000000 --- a/source/engine/thirdparty/sokol/tests/test_ios.sh +++ /dev/null @@ -1,10 +0,0 @@ -set -e -source test_common.sh -build ios_gl ios_gl_debug -build ios_gl ios_gl_release -build ios_metal ios_metal_debug -build ios_metal ios_metal_release -build ios_arc_gl ios_arc_gl_debug -build ios_arc_gl ios_arc_gl_release -build ios_arc_metal ios_arc_metal_debug -build ios_arc_metal ios_arc_metal_release diff --git a/source/engine/thirdparty/sokol/tests/test_linux.sh b/source/engine/thirdparty/sokol/tests/test_linux.sh deleted file mode 100755 index ae35e8d..0000000 --- a/source/engine/thirdparty/sokol/tests/test_linux.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e -source test_common.sh -build linux_gl_debug linux_gl_debug -build linux_gl_release linux_gl_release -build linux_gles3_debug linux_gles3_debug -build linux_gles3_release linux_gles3_release -build linux_gl_egl_debug linux_gl_egl_debug -build linux_gl_egl_release linux_gl_egl_release -runtest linux_gl_debug diff --git a/source/engine/thirdparty/sokol/tests/test_macos.sh b/source/engine/thirdparty/sokol/tests/test_macos.sh deleted file mode 100755 index 0c0299a..0000000 --- a/source/engine/thirdparty/sokol/tests/test_macos.sh +++ /dev/null @@ -1,11 +0,0 @@ -set -e -source test_common.sh -build macos_gl_debug macos_gl_debug -build macos_gl_release macos_gl_release -build macos_metal_debug macos_metal_debug -build macos_metal_release macos_metal_release -build macos_arc_gl_debug macos_arc_gl_debug -build macos_arc_gl_release macos_arc_gl_release -build macos_arc_metal_debug macos_arc_metal_debug -build macos_arc_metal_release macos_arc_metal_release -runtest macos_gl_debug diff --git a/source/engine/thirdparty/sokol/tests/test_win.cmd b/source/engine/thirdparty/sokol/tests/test_win.cmd deleted file mode 100644 index d4c16a7..0000000 --- a/source/engine/thirdparty/sokol/tests/test_win.cmd +++ /dev/null @@ -1,11 +0,0 @@ -cmake --preset win_gl || exit /b 10 -cmake --build --preset win_gl_debug || exit /b 10 -cmake --build --preset win_gl_release || exit /b 10 - -cmake --preset win_d3d11 || exit /b 10 -cmake --build --preset win_d3d11_debug || exit /b 10 -cmake --build --preset win_d3d11_release || exit /b 10 - -cd build\win_d3d11\Debug -sokol-test.exe || exit /b 10 -cd ..\..\.. diff --git a/source/engine/thirdparty/sokol/util/gen_sokol_color.py b/source/engine/thirdparty/sokol/util/gen_sokol_color.py deleted file mode 100644 index f19a2ba..0000000 --- a/source/engine/thirdparty/sokol/util/gen_sokol_color.py +++ /dev/null @@ -1,500 +0,0 @@ -#------------------------------------------------------------------------------- -# Generate the sokol_color.h header from a predefined palette -#------------------------------------------------------------------------------- -# LICENSE -# ======= -# -# zlib/libpng license -# -# Copyright (c) 2020 Stuart Adams -# -# This software is provided 'as-is', without any express or implied warranty. -# In no event will the authors be held liable for any damages arising from the -# use of this software. -# -# Permission is granted to anyone to use this software for any purpose, -# including commercial applications, and to alter it and redistribute it -# freely, subject to the following restrictions: -# -# 1. The origin of this software must not be misrepresented; you must not -# claim that you wrote the original software. If you use this software in a -# product, an acknowledgment in the product documentation would be -# appreciated but is not required. -# -# 2. Altered source versions must be plainly marked as such, and must not -# be misrepresented as being the original software. -# -# 3. This notice may not be removed or altered from any source -# distribution. - -colors = [ -("Alice Blue", 0xF0F8FFFF), -("Antique White", 0xFAEBD7FF), -("Aqua", 0x00FFFFFF), -("Aquamarine", 0x7FFFD4FF), -("Azure", 0xF0FFFFFF), -("Beige", 0xF5F5DCFF), -("Bisque", 0xFFE4C4FF), -("Black", 0x000000FF), -("Blanched Almond", 0xFFEBCDFF), -("Blue", 0x0000FFFF), -("Blue Violet", 0x8A2BE2FF), -("Brown", 0xA52A2AFF), -("Burlywood", 0xDEB887FF), -("Cadet Blue", 0x5F9EA0FF), -("Chartreuse", 0x7FFF00FF), -("Chocolate", 0xD2691EFF), -("Coral", 0xFF7F50FF), -("Cornflower Blue", 0x6495EDFF), -("Cornsilk", 0xFFF8DCFF), -("Crimson", 0xDC143CFF), -("Cyan", 0x00FFFFFF), -("Dark Blue", 0x00008BFF), -("Dark Cyan", 0x008B8BFF), -("Dark Goldenrod", 0xB8860BFF), -("Dark Gray", 0xA9A9A9FF), -("Dark Green", 0x006400FF), -("Dark Khaki", 0xBDB76BFF), -("Dark Magenta", 0x8B008BFF), -("Dark Olive Green", 0x556B2FFF), -("Dark Orange", 0xFF8C00FF), -("Dark Orchid", 0x9932CCFF), -("Dark Red", 0x8B0000FF), -("Dark Salmon", 0xE9967AFF), -("Dark Sea Green", 0x8FBC8FFF), -("Dark Slate Blue", 0x483D8BFF), -("Dark Slate Gray", 0x2F4F4FFF), -("Dark Turquoise", 0x00CED1FF), -("Dark Violet", 0x9400D3FF), -("Deep Pink", 0xFF1493FF), -("Deep Sky Blue", 0x00BFFFFF), -("Dim Gray", 0x696969FF), -("Dodger Blue", 0x1E90FFFF), -("Firebrick", 0xB22222FF), -("Floral White", 0xFFFAF0FF), -("Forest Green", 0x228B22FF), -("Fuchsia", 0xFF00FFFF), -("Gainsboro", 0xDCDCDCFF), -("Ghost White", 0xF8F8FFFF), -("Gold", 0xFFD700FF), -("Goldenrod", 0xDAA520FF), -("Gray", 0xBEBEBEFF), -("Web Gray", 0x808080FF), -("Green", 0x00FF00FF), -("Web Green", 0x008000FF), -("Green Yellow", 0xADFF2FFF), -("Honeydew", 0xF0FFF0FF), -("Hot Pink", 0xFF69B4FF), -("Indian Red", 0xCD5C5CFF), -("Indigo", 0x4B0082FF), -("Ivory", 0xFFFFF0FF), -("Khaki", 0xF0E68CFF), -("Lavender", 0xE6E6FAFF), -("Lavender Blush", 0xFFF0F5FF), -("Lawn Green", 0x7CFC00FF), -("Lemon Chiffon", 0xFFFACDFF), -("Light Blue", 0xADD8E6FF), -("Light Coral", 0xF08080FF), -("Light Cyan", 0xE0FFFFFF), -("Light Goldenrod", 0xFAFAD2FF), -("Light Gray", 0xD3D3D3FF), -("Light Green", 0x90EE90FF), -("Light Pink", 0xFFB6C1FF), -("Light Salmon", 0xFFA07AFF), -("Light Sea Green", 0x20B2AAFF), -("Light Sky Blue", 0x87CEFAFF), -("Light Slate Gray", 0x778899FF), -("Light Steel Blue", 0xB0C4DEFF), -("Light Yellow", 0xFFFFE0FF), -("Lime", 0x00FF00FF), -("Lime Green", 0x32CD32FF), -("Linen", 0xFAF0E6FF), -("Magenta", 0xFF00FFFF), -("Maroon", 0xB03060FF), -("Web Maroon", 0x800000FF), -("Medium Aquamarine", 0x66CDAAFF), -("Medium Blue", 0x0000CDFF), -("Medium Orchid", 0xBA55D3FF), -("Medium Purple", 0x9370DBFF), -("Medium Sea Green", 0x3CB371FF), -("Medium Slate Blue", 0x7B68EEFF), -("Medium Spring Green", 0x00FA9AFF), -("Medium Turquoise", 0x48D1CCFF), -("Medium Violet Red", 0xC71585FF), -("Midnight Blue", 0x191970FF), -("Mint Cream", 0xF5FFFAFF), -("Misty Rose", 0xFFE4E1FF), -("Moccasin", 0xFFE4B5FF), -("Navajo White", 0xFFDEADFF), -("Navy Blue", 0x000080FF), -("Old Lace", 0xFDF5E6FF), -("Olive", 0x808000FF), -("Olive Drab", 0x6B8E23FF), -("Orange", 0xFFA500FF), -("Orange Red", 0xFF4500FF), -("Orchid", 0xDA70D6FF), -("Pale Goldenrod", 0xEEE8AAFF), -("Pale Green", 0x98FB98FF), -("Pale Turquoise", 0xAFEEEEFF), -("Pale Violet Red", 0xDB7093FF), -("Papaya Whip", 0xFFEFD5FF), -("Peach Puff", 0xFFDAB9FF), -("Peru", 0xCD853FFF), -("Pink", 0xFFC0CBFF), -("Plum", 0xDDA0DDFF), -("Powder Blue", 0xB0E0E6FF), -("Purple", 0xA020F0FF), -("Web Purple", 0x800080FF), -("Rebecca Purple", 0x663399FF), -("Red", 0xFF0000FF), -("Rosy Brown", 0xBC8F8FFF), -("Royal Blue", 0x4169E1FF), -("Saddle Brown", 0x8B4513FF), -("Salmon", 0xFA8072FF), -("Sandy Brown", 0xF4A460FF), -("Sea Green", 0x2E8B57FF), -("Seashell", 0xFFF5EEFF), -("Sienna", 0xA0522DFF), -("Silver", 0xC0C0C0FF), -("Sky Blue", 0x87CEEBFF), -("Slate Blue", 0x6A5ACDFF), -("Slate Gray", 0x708090FF), -("Snow", 0xFFFAFAFF), -("Spring Green", 0x00FF7FFF), -("Steel Blue", 0x4682B4FF), -("Tan", 0xD2B48CFF), -("Teal", 0x008080FF), -("Thistle", 0xD8BFD8FF), -("Tomato", 0xFF6347FF), -("Transparent", 0x00000000), -("Turquoise", 0x40E0D0FF), -("Violet", 0xEE82EEFF), -("Wheat", 0xF5DEB3FF), -("White", 0xFFFFFFFF), -("White Smoke", 0xF5F5F5FF), -("Yellow", 0xFFFF00FF), -("Yellow Green", 0x9ACD32FF) -] - -header = open("sokol_color.h", "w") - -header.write("""#if defined(SOKOL_IMPL) && !defined(SOKOL_COLOR_IMPL) -#define SOKOL_COLOR_IMPL -#endif -#ifndef SOKOL_COLOR_INCLUDED -/* - sokol_color.h -- sg_color utilities - - This header was generated by gen_sokol_color.py. Do not modify it. - - Project URL: https://github.com/floooh/sokol - - Include the following headers before including sokol_color.h: - - sokol_gfx.h - - FEATURE OVERVIEW - ================ - sokol_color.h defines preset colors based on the X11 color names, - alongside utility functions to create and modify sg_color objects. - - The predefined colors are based on the X11 color names: - - https://en.wikipedia.org/wiki/X11_color_names - - This palette is useful for prototyping - lots of programmers are familiar with - these colours due to their use in X11, web development and XNA / MonoGame. They - are also handy when you want to reference a familiar color, but don't want to - write it out by hand. - - COLORS - ====== - The palette is defined using static const (or constexpr if you are using a - C++ compiler) objects. These objects use lowercase names: - - static SOKOL_COLOR_CONSTEXPR sg_color sg_red = SG_RED; - static SOKOL_COLOR_CONSTEXPR sg_color sg_green = SG_GREEN; - static SOKOL_COLOR_CONSTEXPR sg_color sg_blue = SG_BLUE; - - An sg_color preset object like sg_red can be used to initialize - an sg_pass_action: - - sg_pass_action pass_action = { - .colors[0] = { .action=SG_ACTION_CLEAR, .value = sg_red } - }; - - Initializing an object with static storage duration is more complicated - because of C language rules. Technically, a static const is not a - compile-time constant in C. To work around this, the palette is also - defined as a series of brace-enclosed list macro definitions. These - definitions use uppercase names: - - #define SG_RED { 1.0f, 0.0f, 0.0f, 1.0f } - #define SG_GREEN { 0.0f, 1.0f, 0.0f, 1.0f } - #define SG_BLUE { 0.0f, 0.0f, 1.0f, 1.0f } - - A preset macro like SG_RED can be used to initialize objects with static - storage duration: - - static struct { - sg_pass_action pass_action; - } state = { - .pass_action = { - .colors[0] = { .action = SG_ACTION_CLEAR, .value = SG_RED } - } - }; - - A second set of macro definitions exists for colors packed as 32 bit integer - values. These definitions are also uppercase, but use the _RGBA32 suffix: - - #define SG_RED_RGBA32 0xFF0000FF - #define SG_GREEN_RGBA32 0x00FF00FF - #define SG_BLUE_RGBA32 0x0000FFFF - - This is useful if your code makes use of packed colors, as sokol_gl.h does for its - internal vertex format: - - sgl_begin_triangles(); - sgl_v2f_c1i( 0.0f, 0.5f, SG_RED_RGBA32); - sgl_v2f_c1i( 0.5f, -0.5f, SG_GREEN_RGBA32); - sgl_v2f_c1i(-0.5f, -0.5f, SG_BLUE_RGBA32); - sgl_end(); - - UTILITY FUNCTIONS - ================= - - Utility functions for creating colours are provided: - - - sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - Create a sg_color object from separate R, G, B, A bytes. - - - sg_make_color_1i(uint32_t rgba) - Create a sg_color object from RGBA bytes packed into a 32-bit unsigned integer. - - - sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) - Linearly interpolate a color. - - - sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) - Linearly interpolate a color. Less efficient but more precise than sg_color_lerp. - - - sg_color_multiply(const sg_color* color, float scale) - Multiply each color component by the scale factor. - - LICENSE - ======= - - zlib/libpng license - - Copyright (c) 2020 Stuart Adams - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_COLOR_INCLUDED (1) - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_color.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL) -#define SOKOL_COLOR_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_COLOR_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_COLOR_IMPL) -#define SOKOL_COLOR_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_COLOR_API_DECL __declspec(dllimport) -#else -#define SOKOL_COLOR_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -#define SOKOL_COLOR_CONSTEXPR constexpr -extern "C" { -#else -#define SOKOL_COLOR_CONSTEXPR const -#endif - -SOKOL_COLOR_API_DECL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_COLOR_API_DECL sg_color sg_make_color_1i(uint32_t rgba); -SOKOL_COLOR_API_DECL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount); -SOKOL_COLOR_API_DECL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount); -SOKOL_COLOR_API_DECL sg_color sg_color_multiply(const sg_color* color, float scale); - -""") - -def unpack_rgba(color): - red = (color & 0xFF000000) >> 24 - green = (color & 0xFF0000) >> 16 - blue = (color & 0xFF00) >> 8 - alpha = (color & 0xFF) - return (red, green, blue, alpha) - -def add_documentation(color): - documentation = "/* {name} color {{ R:{r}, G:{g}, B:{b}, A:{a} }} */\n" - rgba = unpack_rgba(color[1]) - header.write(documentation.format( - name = color[0], r = rgba[0], g = rgba[1], b = rgba[2], a = rgba[3])) - -for color in colors: - add_documentation(color) - init_color = "SG_" + color[0].upper().replace(" ", "_") - init_color_definition = "#define {name} {{ {r}f, {g}f, {b}f, {a}f }}\n" - rgba = unpack_rgba(color[1]) - r = rgba[0] / 255 - g = rgba[1] / 255 - b = rgba[2] / 255 - a = rgba[3] / 255 - r_text = "{:.1f}".format(r) if r.is_integer() else "{:.9g}".format(r) - g_text = "{:.1f}".format(g) if g.is_integer() else "{:.9g}".format(g) - b_text = "{:.1f}".format(b) if b.is_integer() else "{:.9g}".format(b) - a_text = "{:.1f}".format(a) if a.is_integer() else "{:.9g}".format(a) - header.write(init_color_definition.format( - name = init_color, r = r_text, g = g_text, b = b_text, a = a_text)) - -header.write("\n") - -for color in colors: - add_documentation(color) - init_color = "sg_" + color[0].lower().replace(" ", "_") - init_color_definition = "static SOKOL_COLOR_CONSTEXPR sg_color {name} = {init};\n" - init_color_name = "SG_" + color[0].upper().replace(" ", "_") - header.write(init_color_definition.format(name = init_color, init = init_color_name)) - -header.write("\n") - -for color in colors: - add_documentation(color) - hex_color = "0x{0:08X}".format(color[1]) - packed_color = "SG_" + color[0].upper().replace(" ", "_") + "_RGBA32" - packed_color_definition = "#define {name} {rgba}\n" - header.write(packed_color_definition.format(name = packed_color, rgba = hex_color)) - -header.write(""" -#ifdef __cplusplus -} /* extern "C" */ - -inline sg_color sg_make_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return sg_make_color_4b(r, g, b, a); -} - -inline sg_color sg_make_color(uint32_t rgba) { - return sg_make_color_1i(rgba); -} - -inline sg_color sg_color_lerp(const sg_color& color_a, const sg_color& color_b, float amount) { - return sg_color_lerp(&color_a, &color_b, amount); -} - -inline sg_color sg_color_lerp_precise(const sg_color& color_a, const sg_color& color_b, float amount) { - return sg_color_lerp_precise(&color_a, &color_b, amount); -} - -inline sg_color sg_color_multiply(const sg_color& color, float scale) { - return sg_color_multiply(&color, scale); -} - -#endif /* __cplusplus */ - -#endif /* SOKOL_COLOR_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_COLOR_IMPL -#define SOKOL_COLOR_IMPL_INCLUDED (1) - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -static inline float _sg_color_clamp(float v, float low, float high) { - if (v < low) { - return low; - } else if (v > high) { - return high; - } - return v; -} - -static inline float _sg_color_lerp(float a, float b, float amount) { - return a + (b - a) * amount; -} - -static inline float _sg_color_lerp_precise(float a, float b, float amount) { - return ((1.0f - amount) * a) + (b * amount); -} - -SOKOL_API_IMPL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - sg_color result; - result.r = r / 255.0f; - result.g = g / 255.0f; - result.b = b / 255.0f; - result.a = a / 255.0f; - return result; -} - -SOKOL_API_IMPL sg_color sg_make_color_1i(uint32_t rgba) { - return sg_make_color_4b( - (uint8_t)(rgba >> 24), - (uint8_t)(rgba >> 16), - (uint8_t)(rgba >> 8), - (uint8_t)(rgba >> 0) - ); -} - -SOKOL_API_IMPL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) { - SOKOL_ASSERT(color_a); - SOKOL_ASSERT(color_b); - amount = _sg_color_clamp(amount, 0.0f, 1.0f); - sg_color result; - result.r = _sg_color_lerp(color_a->r, color_b->r, amount); - result.g = _sg_color_lerp(color_a->g, color_b->g, amount); - result.b = _sg_color_lerp(color_a->b, color_b->b, amount); - result.a = _sg_color_lerp(color_a->a, color_b->a, amount); - return result; -} - -SOKOL_API_IMPL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) { - SOKOL_ASSERT(color_a); - SOKOL_ASSERT(color_b); - amount = _sg_color_clamp(amount, 0.0f, 1.0f); - sg_color result; - result.r = _sg_color_lerp_precise(color_a->r, color_b->r, amount); - result.g = _sg_color_lerp_precise(color_a->g, color_b->g, amount); - result.b = _sg_color_lerp_precise(color_a->b, color_b->b, amount); - result.a = _sg_color_lerp_precise(color_a->a, color_b->a, amount); - return result; -} - -SOKOL_API_IMPL sg_color sg_color_multiply(const sg_color* color, float scale) { - SOKOL_ASSERT(color); - sg_color result; - result.r = color->r * scale; - result.g = color->g * scale; - result.b = color->b * scale; - result.a = color->a * scale; - return result; -} - -#endif /* SOKOL_COLOR_IMPL */ -""") diff --git a/source/engine/thirdparty/sokol/util/sokol_color.h b/source/engine/thirdparty/sokol/util/sokol_color.h deleted file mode 100644 index cc31b44..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_color.h +++ /dev/null @@ -1,1148 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_COLOR_IMPL) -#define SOKOL_COLOR_IMPL -#endif -#ifndef SOKOL_COLOR_INCLUDED -/* - sokol_color.h -- sg_color utilities - - This header was generated by gen_sokol_color.py. Do not modify it. - - Project URL: https://github.com/floooh/sokol - - Include the following headers before including sokol_color.h: - - sokol_gfx.h - - FEATURE OVERVIEW - ================ - sokol_color.h defines preset colors based on the X11 color names, - alongside utility functions to create and modify sg_color objects. - - The predefined colors are based on the X11 color names: - - https://en.wikipedia.org/wiki/X11_color_names - - This palette is useful for prototyping - lots of programmers are familiar with - these colours due to their use in X11, web development and XNA / MonoGame. They - are also handy when you want to reference a familiar color, but don't want to - write it out by hand. - - COLORS - ====== - The palette is defined using static const (or constexpr if you are using a - C++ compiler) objects. These objects use lowercase names: - - static SOKOL_COLOR_CONSTEXPR sg_color sg_red = SG_RED; - static SOKOL_COLOR_CONSTEXPR sg_color sg_green = SG_GREEN; - static SOKOL_COLOR_CONSTEXPR sg_color sg_blue = SG_BLUE; - - An sg_color preset object like sg_red can be used to initialize - an sg_pass_action: - - sg_pass_action pass_action = { - .colors[0] = { .action=SG_ACTION_CLEAR, .value = sg_red } - }; - - Initializing an object with static storage duration is more complicated - because of C language rules. Technically, a static const is not a - compile-time constant in C. To work around this, the palette is also - defined as a series of brace-enclosed list macro definitions. These - definitions use uppercase names: - - #define SG_RED { 1.0f, 0.0f, 0.0f, 1.0f } - #define SG_GREEN { 0.0f, 1.0f, 0.0f, 1.0f } - #define SG_BLUE { 0.0f, 0.0f, 1.0f, 1.0f } - - A preset macro like SG_RED can be used to initialize objects with static - storage duration: - - static struct { - sg_pass_action pass_action; - } state = { - .pass_action = { - .colors[0] = { .action = SG_ACTION_CLEAR, .value = SG_RED } - } - }; - - A second set of macro definitions exists for colors packed as 32 bit integer - values. These definitions are also uppercase, but use the _RGBA32 suffix: - - #define SG_RED_RGBA32 0xFF0000FF - #define SG_GREEN_RGBA32 0x00FF00FF - #define SG_BLUE_RGBA32 0x0000FFFF - - This is useful if your code makes use of packed colors, as sokol_gl.h does for its - internal vertex format: - - sgl_begin_triangles(); - sgl_v2f_c1i( 0.0f, 0.5f, SG_RED_RGBA32); - sgl_v2f_c1i( 0.5f, -0.5f, SG_GREEN_RGBA32); - sgl_v2f_c1i(-0.5f, -0.5f, SG_BLUE_RGBA32); - sgl_end(); - - UTILITY FUNCTIONS - ================= - - Utility functions for creating colours are provided: - - - sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - Create a sg_color object from separate R, G, B, A bytes. - - - sg_make_color_1i(uint32_t rgba) - Create a sg_color object from RGBA bytes packed into a 32-bit unsigned integer. - - - sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) - Linearly interpolate a color. - - - sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) - Linearly interpolate a color. Less efficient but more precise than sg_color_lerp. - - - sg_color_multiply(const sg_color* color, float scale) - Multiply each color component by the scale factor. - - LICENSE - ======= - - zlib/libpng license - - Copyright (c) 2020 Stuart Adams - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_COLOR_INCLUDED (1) - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_color.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL) -#define SOKOL_COLOR_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_COLOR_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_COLOR_IMPL) -#define SOKOL_COLOR_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_COLOR_API_DECL __declspec(dllimport) -#else -#define SOKOL_COLOR_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -#define SOKOL_COLOR_CONSTEXPR constexpr -extern "C" { -#else -#define SOKOL_COLOR_CONSTEXPR const -#endif - -SOKOL_COLOR_API_DECL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_COLOR_API_DECL sg_color sg_make_color_1i(uint32_t rgba); -SOKOL_COLOR_API_DECL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount); -SOKOL_COLOR_API_DECL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount); -SOKOL_COLOR_API_DECL sg_color sg_color_multiply(const sg_color* color, float scale); - -/* Alice Blue color { R:240, G:248, B:255, A:255 } */ -#define SG_ALICE_BLUE { 0.941176471f, 0.97254902f, 1.0f, 1.0f } -/* Antique White color { R:250, G:235, B:215, A:255 } */ -#define SG_ANTIQUE_WHITE { 0.980392157f, 0.921568627f, 0.843137255f, 1.0f } -/* Aqua color { R:0, G:255, B:255, A:255 } */ -#define SG_AQUA { 0.0f, 1.0f, 1.0f, 1.0f } -/* Aquamarine color { R:127, G:255, B:212, A:255 } */ -#define SG_AQUAMARINE { 0.498039216f, 1.0f, 0.831372549f, 1.0f } -/* Azure color { R:240, G:255, B:255, A:255 } */ -#define SG_AZURE { 0.941176471f, 1.0f, 1.0f, 1.0f } -/* Beige color { R:245, G:245, B:220, A:255 } */ -#define SG_BEIGE { 0.960784314f, 0.960784314f, 0.862745098f, 1.0f } -/* Bisque color { R:255, G:228, B:196, A:255 } */ -#define SG_BISQUE { 1.0f, 0.894117647f, 0.768627451f, 1.0f } -/* Black color { R:0, G:0, B:0, A:255 } */ -#define SG_BLACK { 0.0f, 0.0f, 0.0f, 1.0f } -/* Blanched Almond color { R:255, G:235, B:205, A:255 } */ -#define SG_BLANCHED_ALMOND { 1.0f, 0.921568627f, 0.803921569f, 1.0f } -/* Blue color { R:0, G:0, B:255, A:255 } */ -#define SG_BLUE { 0.0f, 0.0f, 1.0f, 1.0f } -/* Blue Violet color { R:138, G:43, B:226, A:255 } */ -#define SG_BLUE_VIOLET { 0.541176471f, 0.168627451f, 0.88627451f, 1.0f } -/* Brown color { R:165, G:42, B:42, A:255 } */ -#define SG_BROWN { 0.647058824f, 0.164705882f, 0.164705882f, 1.0f } -/* Burlywood color { R:222, G:184, B:135, A:255 } */ -#define SG_BURLYWOOD { 0.870588235f, 0.721568627f, 0.529411765f, 1.0f } -/* Cadet Blue color { R:95, G:158, B:160, A:255 } */ -#define SG_CADET_BLUE { 0.37254902f, 0.619607843f, 0.62745098f, 1.0f } -/* Chartreuse color { R:127, G:255, B:0, A:255 } */ -#define SG_CHARTREUSE { 0.498039216f, 1.0f, 0.0f, 1.0f } -/* Chocolate color { R:210, G:105, B:30, A:255 } */ -#define SG_CHOCOLATE { 0.823529412f, 0.411764706f, 0.117647059f, 1.0f } -/* Coral color { R:255, G:127, B:80, A:255 } */ -#define SG_CORAL { 1.0f, 0.498039216f, 0.31372549f, 1.0f } -/* Cornflower Blue color { R:100, G:149, B:237, A:255 } */ -#define SG_CORNFLOWER_BLUE { 0.392156863f, 0.584313725f, 0.929411765f, 1.0f } -/* Cornsilk color { R:255, G:248, B:220, A:255 } */ -#define SG_CORNSILK { 1.0f, 0.97254902f, 0.862745098f, 1.0f } -/* Crimson color { R:220, G:20, B:60, A:255 } */ -#define SG_CRIMSON { 0.862745098f, 0.0784313725f, 0.235294118f, 1.0f } -/* Cyan color { R:0, G:255, B:255, A:255 } */ -#define SG_CYAN { 0.0f, 1.0f, 1.0f, 1.0f } -/* Dark Blue color { R:0, G:0, B:139, A:255 } */ -#define SG_DARK_BLUE { 0.0f, 0.0f, 0.545098039f, 1.0f } -/* Dark Cyan color { R:0, G:139, B:139, A:255 } */ -#define SG_DARK_CYAN { 0.0f, 0.545098039f, 0.545098039f, 1.0f } -/* Dark Goldenrod color { R:184, G:134, B:11, A:255 } */ -#define SG_DARK_GOLDENROD { 0.721568627f, 0.525490196f, 0.0431372549f, 1.0f } -/* Dark Gray color { R:169, G:169, B:169, A:255 } */ -#define SG_DARK_GRAY { 0.662745098f, 0.662745098f, 0.662745098f, 1.0f } -/* Dark Green color { R:0, G:100, B:0, A:255 } */ -#define SG_DARK_GREEN { 0.0f, 0.392156863f, 0.0f, 1.0f } -/* Dark Khaki color { R:189, G:183, B:107, A:255 } */ -#define SG_DARK_KHAKI { 0.741176471f, 0.717647059f, 0.419607843f, 1.0f } -/* Dark Magenta color { R:139, G:0, B:139, A:255 } */ -#define SG_DARK_MAGENTA { 0.545098039f, 0.0f, 0.545098039f, 1.0f } -/* Dark Olive Green color { R:85, G:107, B:47, A:255 } */ -#define SG_DARK_OLIVE_GREEN { 0.333333333f, 0.419607843f, 0.184313725f, 1.0f } -/* Dark Orange color { R:255, G:140, B:0, A:255 } */ -#define SG_DARK_ORANGE { 1.0f, 0.549019608f, 0.0f, 1.0f } -/* Dark Orchid color { R:153, G:50, B:204, A:255 } */ -#define SG_DARK_ORCHID { 0.6f, 0.196078431f, 0.8f, 1.0f } -/* Dark Red color { R:139, G:0, B:0, A:255 } */ -#define SG_DARK_RED { 0.545098039f, 0.0f, 0.0f, 1.0f } -/* Dark Salmon color { R:233, G:150, B:122, A:255 } */ -#define SG_DARK_SALMON { 0.91372549f, 0.588235294f, 0.478431373f, 1.0f } -/* Dark Sea Green color { R:143, G:188, B:143, A:255 } */ -#define SG_DARK_SEA_GREEN { 0.560784314f, 0.737254902f, 0.560784314f, 1.0f } -/* Dark Slate Blue color { R:72, G:61, B:139, A:255 } */ -#define SG_DARK_SLATE_BLUE { 0.282352941f, 0.239215686f, 0.545098039f, 1.0f } -/* Dark Slate Gray color { R:47, G:79, B:79, A:255 } */ -#define SG_DARK_SLATE_GRAY { 0.184313725f, 0.309803922f, 0.309803922f, 1.0f } -/* Dark Turquoise color { R:0, G:206, B:209, A:255 } */ -#define SG_DARK_TURQUOISE { 0.0f, 0.807843137f, 0.819607843f, 1.0f } -/* Dark Violet color { R:148, G:0, B:211, A:255 } */ -#define SG_DARK_VIOLET { 0.580392157f, 0.0f, 0.82745098f, 1.0f } -/* Deep Pink color { R:255, G:20, B:147, A:255 } */ -#define SG_DEEP_PINK { 1.0f, 0.0784313725f, 0.576470588f, 1.0f } -/* Deep Sky Blue color { R:0, G:191, B:255, A:255 } */ -#define SG_DEEP_SKY_BLUE { 0.0f, 0.749019608f, 1.0f, 1.0f } -/* Dim Gray color { R:105, G:105, B:105, A:255 } */ -#define SG_DIM_GRAY { 0.411764706f, 0.411764706f, 0.411764706f, 1.0f } -/* Dodger Blue color { R:30, G:144, B:255, A:255 } */ -#define SG_DODGER_BLUE { 0.117647059f, 0.564705882f, 1.0f, 1.0f } -/* Firebrick color { R:178, G:34, B:34, A:255 } */ -#define SG_FIREBRICK { 0.698039216f, 0.133333333f, 0.133333333f, 1.0f } -/* Floral White color { R:255, G:250, B:240, A:255 } */ -#define SG_FLORAL_WHITE { 1.0f, 0.980392157f, 0.941176471f, 1.0f } -/* Forest Green color { R:34, G:139, B:34, A:255 } */ -#define SG_FOREST_GREEN { 0.133333333f, 0.545098039f, 0.133333333f, 1.0f } -/* Fuchsia color { R:255, G:0, B:255, A:255 } */ -#define SG_FUCHSIA { 1.0f, 0.0f, 1.0f, 1.0f } -/* Gainsboro color { R:220, G:220, B:220, A:255 } */ -#define SG_GAINSBORO { 0.862745098f, 0.862745098f, 0.862745098f, 1.0f } -/* Ghost White color { R:248, G:248, B:255, A:255 } */ -#define SG_GHOST_WHITE { 0.97254902f, 0.97254902f, 1.0f, 1.0f } -/* Gold color { R:255, G:215, B:0, A:255 } */ -#define SG_GOLD { 1.0f, 0.843137255f, 0.0f, 1.0f } -/* Goldenrod color { R:218, G:165, B:32, A:255 } */ -#define SG_GOLDENROD { 0.854901961f, 0.647058824f, 0.125490196f, 1.0f } -/* Gray color { R:190, G:190, B:190, A:255 } */ -#define SG_GRAY { 0.745098039f, 0.745098039f, 0.745098039f, 1.0f } -/* Web Gray color { R:128, G:128, B:128, A:255 } */ -#define SG_WEB_GRAY { 0.501960784f, 0.501960784f, 0.501960784f, 1.0f } -/* Green color { R:0, G:255, B:0, A:255 } */ -#define SG_GREEN { 0.0f, 1.0f, 0.0f, 1.0f } -/* Web Green color { R:0, G:128, B:0, A:255 } */ -#define SG_WEB_GREEN { 0.0f, 0.501960784f, 0.0f, 1.0f } -/* Green Yellow color { R:173, G:255, B:47, A:255 } */ -#define SG_GREEN_YELLOW { 0.678431373f, 1.0f, 0.184313725f, 1.0f } -/* Honeydew color { R:240, G:255, B:240, A:255 } */ -#define SG_HONEYDEW { 0.941176471f, 1.0f, 0.941176471f, 1.0f } -/* Hot Pink color { R:255, G:105, B:180, A:255 } */ -#define SG_HOT_PINK { 1.0f, 0.411764706f, 0.705882353f, 1.0f } -/* Indian Red color { R:205, G:92, B:92, A:255 } */ -#define SG_INDIAN_RED { 0.803921569f, 0.360784314f, 0.360784314f, 1.0f } -/* Indigo color { R:75, G:0, B:130, A:255 } */ -#define SG_INDIGO { 0.294117647f, 0.0f, 0.509803922f, 1.0f } -/* Ivory color { R:255, G:255, B:240, A:255 } */ -#define SG_IVORY { 1.0f, 1.0f, 0.941176471f, 1.0f } -/* Khaki color { R:240, G:230, B:140, A:255 } */ -#define SG_KHAKI { 0.941176471f, 0.901960784f, 0.549019608f, 1.0f } -/* Lavender color { R:230, G:230, B:250, A:255 } */ -#define SG_LAVENDER { 0.901960784f, 0.901960784f, 0.980392157f, 1.0f } -/* Lavender Blush color { R:255, G:240, B:245, A:255 } */ -#define SG_LAVENDER_BLUSH { 1.0f, 0.941176471f, 0.960784314f, 1.0f } -/* Lawn Green color { R:124, G:252, B:0, A:255 } */ -#define SG_LAWN_GREEN { 0.48627451f, 0.988235294f, 0.0f, 1.0f } -/* Lemon Chiffon color { R:255, G:250, B:205, A:255 } */ -#define SG_LEMON_CHIFFON { 1.0f, 0.980392157f, 0.803921569f, 1.0f } -/* Light Blue color { R:173, G:216, B:230, A:255 } */ -#define SG_LIGHT_BLUE { 0.678431373f, 0.847058824f, 0.901960784f, 1.0f } -/* Light Coral color { R:240, G:128, B:128, A:255 } */ -#define SG_LIGHT_CORAL { 0.941176471f, 0.501960784f, 0.501960784f, 1.0f } -/* Light Cyan color { R:224, G:255, B:255, A:255 } */ -#define SG_LIGHT_CYAN { 0.878431373f, 1.0f, 1.0f, 1.0f } -/* Light Goldenrod color { R:250, G:250, B:210, A:255 } */ -#define SG_LIGHT_GOLDENROD { 0.980392157f, 0.980392157f, 0.823529412f, 1.0f } -/* Light Gray color { R:211, G:211, B:211, A:255 } */ -#define SG_LIGHT_GRAY { 0.82745098f, 0.82745098f, 0.82745098f, 1.0f } -/* Light Green color { R:144, G:238, B:144, A:255 } */ -#define SG_LIGHT_GREEN { 0.564705882f, 0.933333333f, 0.564705882f, 1.0f } -/* Light Pink color { R:255, G:182, B:193, A:255 } */ -#define SG_LIGHT_PINK { 1.0f, 0.71372549f, 0.756862745f, 1.0f } -/* Light Salmon color { R:255, G:160, B:122, A:255 } */ -#define SG_LIGHT_SALMON { 1.0f, 0.62745098f, 0.478431373f, 1.0f } -/* Light Sea Green color { R:32, G:178, B:170, A:255 } */ -#define SG_LIGHT_SEA_GREEN { 0.125490196f, 0.698039216f, 0.666666667f, 1.0f } -/* Light Sky Blue color { R:135, G:206, B:250, A:255 } */ -#define SG_LIGHT_SKY_BLUE { 0.529411765f, 0.807843137f, 0.980392157f, 1.0f } -/* Light Slate Gray color { R:119, G:136, B:153, A:255 } */ -#define SG_LIGHT_SLATE_GRAY { 0.466666667f, 0.533333333f, 0.6f, 1.0f } -/* Light Steel Blue color { R:176, G:196, B:222, A:255 } */ -#define SG_LIGHT_STEEL_BLUE { 0.690196078f, 0.768627451f, 0.870588235f, 1.0f } -/* Light Yellow color { R:255, G:255, B:224, A:255 } */ -#define SG_LIGHT_YELLOW { 1.0f, 1.0f, 0.878431373f, 1.0f } -/* Lime color { R:0, G:255, B:0, A:255 } */ -#define SG_LIME { 0.0f, 1.0f, 0.0f, 1.0f } -/* Lime Green color { R:50, G:205, B:50, A:255 } */ -#define SG_LIME_GREEN { 0.196078431f, 0.803921569f, 0.196078431f, 1.0f } -/* Linen color { R:250, G:240, B:230, A:255 } */ -#define SG_LINEN { 0.980392157f, 0.941176471f, 0.901960784f, 1.0f } -/* Magenta color { R:255, G:0, B:255, A:255 } */ -#define SG_MAGENTA { 1.0f, 0.0f, 1.0f, 1.0f } -/* Maroon color { R:176, G:48, B:96, A:255 } */ -#define SG_MAROON { 0.690196078f, 0.188235294f, 0.376470588f, 1.0f } -/* Web Maroon color { R:128, G:0, B:0, A:255 } */ -#define SG_WEB_MAROON { 0.501960784f, 0.0f, 0.0f, 1.0f } -/* Medium Aquamarine color { R:102, G:205, B:170, A:255 } */ -#define SG_MEDIUM_AQUAMARINE { 0.4f, 0.803921569f, 0.666666667f, 1.0f } -/* Medium Blue color { R:0, G:0, B:205, A:255 } */ -#define SG_MEDIUM_BLUE { 0.0f, 0.0f, 0.803921569f, 1.0f } -/* Medium Orchid color { R:186, G:85, B:211, A:255 } */ -#define SG_MEDIUM_ORCHID { 0.729411765f, 0.333333333f, 0.82745098f, 1.0f } -/* Medium Purple color { R:147, G:112, B:219, A:255 } */ -#define SG_MEDIUM_PURPLE { 0.576470588f, 0.439215686f, 0.858823529f, 1.0f } -/* Medium Sea Green color { R:60, G:179, B:113, A:255 } */ -#define SG_MEDIUM_SEA_GREEN { 0.235294118f, 0.701960784f, 0.443137255f, 1.0f } -/* Medium Slate Blue color { R:123, G:104, B:238, A:255 } */ -#define SG_MEDIUM_SLATE_BLUE { 0.482352941f, 0.407843137f, 0.933333333f, 1.0f } -/* Medium Spring Green color { R:0, G:250, B:154, A:255 } */ -#define SG_MEDIUM_SPRING_GREEN { 0.0f, 0.980392157f, 0.603921569f, 1.0f } -/* Medium Turquoise color { R:72, G:209, B:204, A:255 } */ -#define SG_MEDIUM_TURQUOISE { 0.282352941f, 0.819607843f, 0.8f, 1.0f } -/* Medium Violet Red color { R:199, G:21, B:133, A:255 } */ -#define SG_MEDIUM_VIOLET_RED { 0.780392157f, 0.0823529412f, 0.521568627f, 1.0f } -/* Midnight Blue color { R:25, G:25, B:112, A:255 } */ -#define SG_MIDNIGHT_BLUE { 0.0980392157f, 0.0980392157f, 0.439215686f, 1.0f } -/* Mint Cream color { R:245, G:255, B:250, A:255 } */ -#define SG_MINT_CREAM { 0.960784314f, 1.0f, 0.980392157f, 1.0f } -/* Misty Rose color { R:255, G:228, B:225, A:255 } */ -#define SG_MISTY_ROSE { 1.0f, 0.894117647f, 0.882352941f, 1.0f } -/* Moccasin color { R:255, G:228, B:181, A:255 } */ -#define SG_MOCCASIN { 1.0f, 0.894117647f, 0.709803922f, 1.0f } -/* Navajo White color { R:255, G:222, B:173, A:255 } */ -#define SG_NAVAJO_WHITE { 1.0f, 0.870588235f, 0.678431373f, 1.0f } -/* Navy Blue color { R:0, G:0, B:128, A:255 } */ -#define SG_NAVY_BLUE { 0.0f, 0.0f, 0.501960784f, 1.0f } -/* Old Lace color { R:253, G:245, B:230, A:255 } */ -#define SG_OLD_LACE { 0.992156863f, 0.960784314f, 0.901960784f, 1.0f } -/* Olive color { R:128, G:128, B:0, A:255 } */ -#define SG_OLIVE { 0.501960784f, 0.501960784f, 0.0f, 1.0f } -/* Olive Drab color { R:107, G:142, B:35, A:255 } */ -#define SG_OLIVE_DRAB { 0.419607843f, 0.556862745f, 0.137254902f, 1.0f } -/* Orange color { R:255, G:165, B:0, A:255 } */ -#define SG_ORANGE { 1.0f, 0.647058824f, 0.0f, 1.0f } -/* Orange Red color { R:255, G:69, B:0, A:255 } */ -#define SG_ORANGE_RED { 1.0f, 0.270588235f, 0.0f, 1.0f } -/* Orchid color { R:218, G:112, B:214, A:255 } */ -#define SG_ORCHID { 0.854901961f, 0.439215686f, 0.839215686f, 1.0f } -/* Pale Goldenrod color { R:238, G:232, B:170, A:255 } */ -#define SG_PALE_GOLDENROD { 0.933333333f, 0.909803922f, 0.666666667f, 1.0f } -/* Pale Green color { R:152, G:251, B:152, A:255 } */ -#define SG_PALE_GREEN { 0.596078431f, 0.984313725f, 0.596078431f, 1.0f } -/* Pale Turquoise color { R:175, G:238, B:238, A:255 } */ -#define SG_PALE_TURQUOISE { 0.68627451f, 0.933333333f, 0.933333333f, 1.0f } -/* Pale Violet Red color { R:219, G:112, B:147, A:255 } */ -#define SG_PALE_VIOLET_RED { 0.858823529f, 0.439215686f, 0.576470588f, 1.0f } -/* Papaya Whip color { R:255, G:239, B:213, A:255 } */ -#define SG_PAPAYA_WHIP { 1.0f, 0.937254902f, 0.835294118f, 1.0f } -/* Peach Puff color { R:255, G:218, B:185, A:255 } */ -#define SG_PEACH_PUFF { 1.0f, 0.854901961f, 0.725490196f, 1.0f } -/* Peru color { R:205, G:133, B:63, A:255 } */ -#define SG_PERU { 0.803921569f, 0.521568627f, 0.247058824f, 1.0f } -/* Pink color { R:255, G:192, B:203, A:255 } */ -#define SG_PINK { 1.0f, 0.752941176f, 0.796078431f, 1.0f } -/* Plum color { R:221, G:160, B:221, A:255 } */ -#define SG_PLUM { 0.866666667f, 0.62745098f, 0.866666667f, 1.0f } -/* Powder Blue color { R:176, G:224, B:230, A:255 } */ -#define SG_POWDER_BLUE { 0.690196078f, 0.878431373f, 0.901960784f, 1.0f } -/* Purple color { R:160, G:32, B:240, A:255 } */ -#define SG_PURPLE { 0.62745098f, 0.125490196f, 0.941176471f, 1.0f } -/* Web Purple color { R:128, G:0, B:128, A:255 } */ -#define SG_WEB_PURPLE { 0.501960784f, 0.0f, 0.501960784f, 1.0f } -/* Rebecca Purple color { R:102, G:51, B:153, A:255 } */ -#define SG_REBECCA_PURPLE { 0.4f, 0.2f, 0.6f, 1.0f } -/* Red color { R:255, G:0, B:0, A:255 } */ -#define SG_RED { 1.0f, 0.0f, 0.0f, 1.0f } -/* Rosy Brown color { R:188, G:143, B:143, A:255 } */ -#define SG_ROSY_BROWN { 0.737254902f, 0.560784314f, 0.560784314f, 1.0f } -/* Royal Blue color { R:65, G:105, B:225, A:255 } */ -#define SG_ROYAL_BLUE { 0.254901961f, 0.411764706f, 0.882352941f, 1.0f } -/* Saddle Brown color { R:139, G:69, B:19, A:255 } */ -#define SG_SADDLE_BROWN { 0.545098039f, 0.270588235f, 0.0745098039f, 1.0f } -/* Salmon color { R:250, G:128, B:114, A:255 } */ -#define SG_SALMON { 0.980392157f, 0.501960784f, 0.447058824f, 1.0f } -/* Sandy Brown color { R:244, G:164, B:96, A:255 } */ -#define SG_SANDY_BROWN { 0.956862745f, 0.643137255f, 0.376470588f, 1.0f } -/* Sea Green color { R:46, G:139, B:87, A:255 } */ -#define SG_SEA_GREEN { 0.180392157f, 0.545098039f, 0.341176471f, 1.0f } -/* Seashell color { R:255, G:245, B:238, A:255 } */ -#define SG_SEASHELL { 1.0f, 0.960784314f, 0.933333333f, 1.0f } -/* Sienna color { R:160, G:82, B:45, A:255 } */ -#define SG_SIENNA { 0.62745098f, 0.321568627f, 0.176470588f, 1.0f } -/* Silver color { R:192, G:192, B:192, A:255 } */ -#define SG_SILVER { 0.752941176f, 0.752941176f, 0.752941176f, 1.0f } -/* Sky Blue color { R:135, G:206, B:235, A:255 } */ -#define SG_SKY_BLUE { 0.529411765f, 0.807843137f, 0.921568627f, 1.0f } -/* Slate Blue color { R:106, G:90, B:205, A:255 } */ -#define SG_SLATE_BLUE { 0.415686275f, 0.352941176f, 0.803921569f, 1.0f } -/* Slate Gray color { R:112, G:128, B:144, A:255 } */ -#define SG_SLATE_GRAY { 0.439215686f, 0.501960784f, 0.564705882f, 1.0f } -/* Snow color { R:255, G:250, B:250, A:255 } */ -#define SG_SNOW { 1.0f, 0.980392157f, 0.980392157f, 1.0f } -/* Spring Green color { R:0, G:255, B:127, A:255 } */ -#define SG_SPRING_GREEN { 0.0f, 1.0f, 0.498039216f, 1.0f } -/* Steel Blue color { R:70, G:130, B:180, A:255 } */ -#define SG_STEEL_BLUE { 0.274509804f, 0.509803922f, 0.705882353f, 1.0f } -/* Tan color { R:210, G:180, B:140, A:255 } */ -#define SG_TAN { 0.823529412f, 0.705882353f, 0.549019608f, 1.0f } -/* Teal color { R:0, G:128, B:128, A:255 } */ -#define SG_TEAL { 0.0f, 0.501960784f, 0.501960784f, 1.0f } -/* Thistle color { R:216, G:191, B:216, A:255 } */ -#define SG_THISTLE { 0.847058824f, 0.749019608f, 0.847058824f, 1.0f } -/* Tomato color { R:255, G:99, B:71, A:255 } */ -#define SG_TOMATO { 1.0f, 0.388235294f, 0.278431373f, 1.0f } -/* Transparent color { R:0, G:0, B:0, A:0 } */ -#define SG_TRANSPARENT { 0.0f, 0.0f, 0.0f, 0.0f } -/* Turquoise color { R:64, G:224, B:208, A:255 } */ -#define SG_TURQUOISE { 0.250980392f, 0.878431373f, 0.815686275f, 1.0f } -/* Violet color { R:238, G:130, B:238, A:255 } */ -#define SG_VIOLET { 0.933333333f, 0.509803922f, 0.933333333f, 1.0f } -/* Wheat color { R:245, G:222, B:179, A:255 } */ -#define SG_WHEAT { 0.960784314f, 0.870588235f, 0.701960784f, 1.0f } -/* White color { R:255, G:255, B:255, A:255 } */ -#define SG_WHITE { 1.0f, 1.0f, 1.0f, 1.0f } -/* White Smoke color { R:245, G:245, B:245, A:255 } */ -#define SG_WHITE_SMOKE { 0.960784314f, 0.960784314f, 0.960784314f, 1.0f } -/* Yellow color { R:255, G:255, B:0, A:255 } */ -#define SG_YELLOW { 1.0f, 1.0f, 0.0f, 1.0f } -/* Yellow Green color { R:154, G:205, B:50, A:255 } */ -#define SG_YELLOW_GREEN { 0.603921569f, 0.803921569f, 0.196078431f, 1.0f } - -/* Alice Blue color { R:240, G:248, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_alice_blue = SG_ALICE_BLUE; -/* Antique White color { R:250, G:235, B:215, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_antique_white = SG_ANTIQUE_WHITE; -/* Aqua color { R:0, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_aqua = SG_AQUA; -/* Aquamarine color { R:127, G:255, B:212, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_aquamarine = SG_AQUAMARINE; -/* Azure color { R:240, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_azure = SG_AZURE; -/* Beige color { R:245, G:245, B:220, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_beige = SG_BEIGE; -/* Bisque color { R:255, G:228, B:196, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_bisque = SG_BISQUE; -/* Black color { R:0, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_black = SG_BLACK; -/* Blanched Almond color { R:255, G:235, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_blanched_almond = SG_BLANCHED_ALMOND; -/* Blue color { R:0, G:0, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_blue = SG_BLUE; -/* Blue Violet color { R:138, G:43, B:226, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_blue_violet = SG_BLUE_VIOLET; -/* Brown color { R:165, G:42, B:42, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_brown = SG_BROWN; -/* Burlywood color { R:222, G:184, B:135, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_burlywood = SG_BURLYWOOD; -/* Cadet Blue color { R:95, G:158, B:160, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cadet_blue = SG_CADET_BLUE; -/* Chartreuse color { R:127, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_chartreuse = SG_CHARTREUSE; -/* Chocolate color { R:210, G:105, B:30, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_chocolate = SG_CHOCOLATE; -/* Coral color { R:255, G:127, B:80, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_coral = SG_CORAL; -/* Cornflower Blue color { R:100, G:149, B:237, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cornflower_blue = SG_CORNFLOWER_BLUE; -/* Cornsilk color { R:255, G:248, B:220, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cornsilk = SG_CORNSILK; -/* Crimson color { R:220, G:20, B:60, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_crimson = SG_CRIMSON; -/* Cyan color { R:0, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cyan = SG_CYAN; -/* Dark Blue color { R:0, G:0, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_blue = SG_DARK_BLUE; -/* Dark Cyan color { R:0, G:139, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_cyan = SG_DARK_CYAN; -/* Dark Goldenrod color { R:184, G:134, B:11, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_goldenrod = SG_DARK_GOLDENROD; -/* Dark Gray color { R:169, G:169, B:169, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_gray = SG_DARK_GRAY; -/* Dark Green color { R:0, G:100, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_green = SG_DARK_GREEN; -/* Dark Khaki color { R:189, G:183, B:107, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_khaki = SG_DARK_KHAKI; -/* Dark Magenta color { R:139, G:0, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_magenta = SG_DARK_MAGENTA; -/* Dark Olive Green color { R:85, G:107, B:47, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_olive_green = SG_DARK_OLIVE_GREEN; -/* Dark Orange color { R:255, G:140, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_orange = SG_DARK_ORANGE; -/* Dark Orchid color { R:153, G:50, B:204, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_orchid = SG_DARK_ORCHID; -/* Dark Red color { R:139, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_red = SG_DARK_RED; -/* Dark Salmon color { R:233, G:150, B:122, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_salmon = SG_DARK_SALMON; -/* Dark Sea Green color { R:143, G:188, B:143, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_sea_green = SG_DARK_SEA_GREEN; -/* Dark Slate Blue color { R:72, G:61, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_slate_blue = SG_DARK_SLATE_BLUE; -/* Dark Slate Gray color { R:47, G:79, B:79, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_slate_gray = SG_DARK_SLATE_GRAY; -/* Dark Turquoise color { R:0, G:206, B:209, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_turquoise = SG_DARK_TURQUOISE; -/* Dark Violet color { R:148, G:0, B:211, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_violet = SG_DARK_VIOLET; -/* Deep Pink color { R:255, G:20, B:147, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_deep_pink = SG_DEEP_PINK; -/* Deep Sky Blue color { R:0, G:191, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_deep_sky_blue = SG_DEEP_SKY_BLUE; -/* Dim Gray color { R:105, G:105, B:105, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dim_gray = SG_DIM_GRAY; -/* Dodger Blue color { R:30, G:144, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dodger_blue = SG_DODGER_BLUE; -/* Firebrick color { R:178, G:34, B:34, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_firebrick = SG_FIREBRICK; -/* Floral White color { R:255, G:250, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_floral_white = SG_FLORAL_WHITE; -/* Forest Green color { R:34, G:139, B:34, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_forest_green = SG_FOREST_GREEN; -/* Fuchsia color { R:255, G:0, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_fuchsia = SG_FUCHSIA; -/* Gainsboro color { R:220, G:220, B:220, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_gainsboro = SG_GAINSBORO; -/* Ghost White color { R:248, G:248, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_ghost_white = SG_GHOST_WHITE; -/* Gold color { R:255, G:215, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_gold = SG_GOLD; -/* Goldenrod color { R:218, G:165, B:32, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_goldenrod = SG_GOLDENROD; -/* Gray color { R:190, G:190, B:190, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_gray = SG_GRAY; -/* Web Gray color { R:128, G:128, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_gray = SG_WEB_GRAY; -/* Green color { R:0, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_green = SG_GREEN; -/* Web Green color { R:0, G:128, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_green = SG_WEB_GREEN; -/* Green Yellow color { R:173, G:255, B:47, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_green_yellow = SG_GREEN_YELLOW; -/* Honeydew color { R:240, G:255, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_honeydew = SG_HONEYDEW; -/* Hot Pink color { R:255, G:105, B:180, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_hot_pink = SG_HOT_PINK; -/* Indian Red color { R:205, G:92, B:92, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_indian_red = SG_INDIAN_RED; -/* Indigo color { R:75, G:0, B:130, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_indigo = SG_INDIGO; -/* Ivory color { R:255, G:255, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_ivory = SG_IVORY; -/* Khaki color { R:240, G:230, B:140, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_khaki = SG_KHAKI; -/* Lavender color { R:230, G:230, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lavender = SG_LAVENDER; -/* Lavender Blush color { R:255, G:240, B:245, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lavender_blush = SG_LAVENDER_BLUSH; -/* Lawn Green color { R:124, G:252, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lawn_green = SG_LAWN_GREEN; -/* Lemon Chiffon color { R:255, G:250, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lemon_chiffon = SG_LEMON_CHIFFON; -/* Light Blue color { R:173, G:216, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_blue = SG_LIGHT_BLUE; -/* Light Coral color { R:240, G:128, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_coral = SG_LIGHT_CORAL; -/* Light Cyan color { R:224, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_cyan = SG_LIGHT_CYAN; -/* Light Goldenrod color { R:250, G:250, B:210, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_goldenrod = SG_LIGHT_GOLDENROD; -/* Light Gray color { R:211, G:211, B:211, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_gray = SG_LIGHT_GRAY; -/* Light Green color { R:144, G:238, B:144, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_green = SG_LIGHT_GREEN; -/* Light Pink color { R:255, G:182, B:193, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_pink = SG_LIGHT_PINK; -/* Light Salmon color { R:255, G:160, B:122, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_salmon = SG_LIGHT_SALMON; -/* Light Sea Green color { R:32, G:178, B:170, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_sea_green = SG_LIGHT_SEA_GREEN; -/* Light Sky Blue color { R:135, G:206, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_sky_blue = SG_LIGHT_SKY_BLUE; -/* Light Slate Gray color { R:119, G:136, B:153, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_slate_gray = SG_LIGHT_SLATE_GRAY; -/* Light Steel Blue color { R:176, G:196, B:222, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_steel_blue = SG_LIGHT_STEEL_BLUE; -/* Light Yellow color { R:255, G:255, B:224, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_yellow = SG_LIGHT_YELLOW; -/* Lime color { R:0, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lime = SG_LIME; -/* Lime Green color { R:50, G:205, B:50, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lime_green = SG_LIME_GREEN; -/* Linen color { R:250, G:240, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_linen = SG_LINEN; -/* Magenta color { R:255, G:0, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_magenta = SG_MAGENTA; -/* Maroon color { R:176, G:48, B:96, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_maroon = SG_MAROON; -/* Web Maroon color { R:128, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_maroon = SG_WEB_MAROON; -/* Medium Aquamarine color { R:102, G:205, B:170, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_aquamarine = SG_MEDIUM_AQUAMARINE; -/* Medium Blue color { R:0, G:0, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_blue = SG_MEDIUM_BLUE; -/* Medium Orchid color { R:186, G:85, B:211, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_orchid = SG_MEDIUM_ORCHID; -/* Medium Purple color { R:147, G:112, B:219, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_purple = SG_MEDIUM_PURPLE; -/* Medium Sea Green color { R:60, G:179, B:113, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_sea_green = SG_MEDIUM_SEA_GREEN; -/* Medium Slate Blue color { R:123, G:104, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_slate_blue = SG_MEDIUM_SLATE_BLUE; -/* Medium Spring Green color { R:0, G:250, B:154, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_spring_green = SG_MEDIUM_SPRING_GREEN; -/* Medium Turquoise color { R:72, G:209, B:204, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_turquoise = SG_MEDIUM_TURQUOISE; -/* Medium Violet Red color { R:199, G:21, B:133, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_violet_red = SG_MEDIUM_VIOLET_RED; -/* Midnight Blue color { R:25, G:25, B:112, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_midnight_blue = SG_MIDNIGHT_BLUE; -/* Mint Cream color { R:245, G:255, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_mint_cream = SG_MINT_CREAM; -/* Misty Rose color { R:255, G:228, B:225, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_misty_rose = SG_MISTY_ROSE; -/* Moccasin color { R:255, G:228, B:181, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_moccasin = SG_MOCCASIN; -/* Navajo White color { R:255, G:222, B:173, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_navajo_white = SG_NAVAJO_WHITE; -/* Navy Blue color { R:0, G:0, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_navy_blue = SG_NAVY_BLUE; -/* Old Lace color { R:253, G:245, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_old_lace = SG_OLD_LACE; -/* Olive color { R:128, G:128, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_olive = SG_OLIVE; -/* Olive Drab color { R:107, G:142, B:35, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_olive_drab = SG_OLIVE_DRAB; -/* Orange color { R:255, G:165, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_orange = SG_ORANGE; -/* Orange Red color { R:255, G:69, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_orange_red = SG_ORANGE_RED; -/* Orchid color { R:218, G:112, B:214, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_orchid = SG_ORCHID; -/* Pale Goldenrod color { R:238, G:232, B:170, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_goldenrod = SG_PALE_GOLDENROD; -/* Pale Green color { R:152, G:251, B:152, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_green = SG_PALE_GREEN; -/* Pale Turquoise color { R:175, G:238, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_turquoise = SG_PALE_TURQUOISE; -/* Pale Violet Red color { R:219, G:112, B:147, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_violet_red = SG_PALE_VIOLET_RED; -/* Papaya Whip color { R:255, G:239, B:213, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_papaya_whip = SG_PAPAYA_WHIP; -/* Peach Puff color { R:255, G:218, B:185, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_peach_puff = SG_PEACH_PUFF; -/* Peru color { R:205, G:133, B:63, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_peru = SG_PERU; -/* Pink color { R:255, G:192, B:203, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pink = SG_PINK; -/* Plum color { R:221, G:160, B:221, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_plum = SG_PLUM; -/* Powder Blue color { R:176, G:224, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_powder_blue = SG_POWDER_BLUE; -/* Purple color { R:160, G:32, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_purple = SG_PURPLE; -/* Web Purple color { R:128, G:0, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_purple = SG_WEB_PURPLE; -/* Rebecca Purple color { R:102, G:51, B:153, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_rebecca_purple = SG_REBECCA_PURPLE; -/* Red color { R:255, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_red = SG_RED; -/* Rosy Brown color { R:188, G:143, B:143, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_rosy_brown = SG_ROSY_BROWN; -/* Royal Blue color { R:65, G:105, B:225, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_royal_blue = SG_ROYAL_BLUE; -/* Saddle Brown color { R:139, G:69, B:19, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_saddle_brown = SG_SADDLE_BROWN; -/* Salmon color { R:250, G:128, B:114, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_salmon = SG_SALMON; -/* Sandy Brown color { R:244, G:164, B:96, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sandy_brown = SG_SANDY_BROWN; -/* Sea Green color { R:46, G:139, B:87, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sea_green = SG_SEA_GREEN; -/* Seashell color { R:255, G:245, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_seashell = SG_SEASHELL; -/* Sienna color { R:160, G:82, B:45, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sienna = SG_SIENNA; -/* Silver color { R:192, G:192, B:192, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_silver = SG_SILVER; -/* Sky Blue color { R:135, G:206, B:235, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sky_blue = SG_SKY_BLUE; -/* Slate Blue color { R:106, G:90, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_slate_blue = SG_SLATE_BLUE; -/* Slate Gray color { R:112, G:128, B:144, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_slate_gray = SG_SLATE_GRAY; -/* Snow color { R:255, G:250, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_snow = SG_SNOW; -/* Spring Green color { R:0, G:255, B:127, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_spring_green = SG_SPRING_GREEN; -/* Steel Blue color { R:70, G:130, B:180, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_steel_blue = SG_STEEL_BLUE; -/* Tan color { R:210, G:180, B:140, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_tan = SG_TAN; -/* Teal color { R:0, G:128, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_teal = SG_TEAL; -/* Thistle color { R:216, G:191, B:216, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_thistle = SG_THISTLE; -/* Tomato color { R:255, G:99, B:71, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_tomato = SG_TOMATO; -/* Transparent color { R:0, G:0, B:0, A:0 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_transparent = SG_TRANSPARENT; -/* Turquoise color { R:64, G:224, B:208, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_turquoise = SG_TURQUOISE; -/* Violet color { R:238, G:130, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_violet = SG_VIOLET; -/* Wheat color { R:245, G:222, B:179, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_wheat = SG_WHEAT; -/* White color { R:255, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_white = SG_WHITE; -/* White Smoke color { R:245, G:245, B:245, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_white_smoke = SG_WHITE_SMOKE; -/* Yellow color { R:255, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_yellow = SG_YELLOW; -/* Yellow Green color { R:154, G:205, B:50, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_yellow_green = SG_YELLOW_GREEN; - -/* Alice Blue color { R:240, G:248, B:255, A:255 } */ -#define SG_ALICE_BLUE_RGBA32 0xF0F8FFFF -/* Antique White color { R:250, G:235, B:215, A:255 } */ -#define SG_ANTIQUE_WHITE_RGBA32 0xFAEBD7FF -/* Aqua color { R:0, G:255, B:255, A:255 } */ -#define SG_AQUA_RGBA32 0x00FFFFFF -/* Aquamarine color { R:127, G:255, B:212, A:255 } */ -#define SG_AQUAMARINE_RGBA32 0x7FFFD4FF -/* Azure color { R:240, G:255, B:255, A:255 } */ -#define SG_AZURE_RGBA32 0xF0FFFFFF -/* Beige color { R:245, G:245, B:220, A:255 } */ -#define SG_BEIGE_RGBA32 0xF5F5DCFF -/* Bisque color { R:255, G:228, B:196, A:255 } */ -#define SG_BISQUE_RGBA32 0xFFE4C4FF -/* Black color { R:0, G:0, B:0, A:255 } */ -#define SG_BLACK_RGBA32 0x000000FF -/* Blanched Almond color { R:255, G:235, B:205, A:255 } */ -#define SG_BLANCHED_ALMOND_RGBA32 0xFFEBCDFF -/* Blue color { R:0, G:0, B:255, A:255 } */ -#define SG_BLUE_RGBA32 0x0000FFFF -/* Blue Violet color { R:138, G:43, B:226, A:255 } */ -#define SG_BLUE_VIOLET_RGBA32 0x8A2BE2FF -/* Brown color { R:165, G:42, B:42, A:255 } */ -#define SG_BROWN_RGBA32 0xA52A2AFF -/* Burlywood color { R:222, G:184, B:135, A:255 } */ -#define SG_BURLYWOOD_RGBA32 0xDEB887FF -/* Cadet Blue color { R:95, G:158, B:160, A:255 } */ -#define SG_CADET_BLUE_RGBA32 0x5F9EA0FF -/* Chartreuse color { R:127, G:255, B:0, A:255 } */ -#define SG_CHARTREUSE_RGBA32 0x7FFF00FF -/* Chocolate color { R:210, G:105, B:30, A:255 } */ -#define SG_CHOCOLATE_RGBA32 0xD2691EFF -/* Coral color { R:255, G:127, B:80, A:255 } */ -#define SG_CORAL_RGBA32 0xFF7F50FF -/* Cornflower Blue color { R:100, G:149, B:237, A:255 } */ -#define SG_CORNFLOWER_BLUE_RGBA32 0x6495EDFF -/* Cornsilk color { R:255, G:248, B:220, A:255 } */ -#define SG_CORNSILK_RGBA32 0xFFF8DCFF -/* Crimson color { R:220, G:20, B:60, A:255 } */ -#define SG_CRIMSON_RGBA32 0xDC143CFF -/* Cyan color { R:0, G:255, B:255, A:255 } */ -#define SG_CYAN_RGBA32 0x00FFFFFF -/* Dark Blue color { R:0, G:0, B:139, A:255 } */ -#define SG_DARK_BLUE_RGBA32 0x00008BFF -/* Dark Cyan color { R:0, G:139, B:139, A:255 } */ -#define SG_DARK_CYAN_RGBA32 0x008B8BFF -/* Dark Goldenrod color { R:184, G:134, B:11, A:255 } */ -#define SG_DARK_GOLDENROD_RGBA32 0xB8860BFF -/* Dark Gray color { R:169, G:169, B:169, A:255 } */ -#define SG_DARK_GRAY_RGBA32 0xA9A9A9FF -/* Dark Green color { R:0, G:100, B:0, A:255 } */ -#define SG_DARK_GREEN_RGBA32 0x006400FF -/* Dark Khaki color { R:189, G:183, B:107, A:255 } */ -#define SG_DARK_KHAKI_RGBA32 0xBDB76BFF -/* Dark Magenta color { R:139, G:0, B:139, A:255 } */ -#define SG_DARK_MAGENTA_RGBA32 0x8B008BFF -/* Dark Olive Green color { R:85, G:107, B:47, A:255 } */ -#define SG_DARK_OLIVE_GREEN_RGBA32 0x556B2FFF -/* Dark Orange color { R:255, G:140, B:0, A:255 } */ -#define SG_DARK_ORANGE_RGBA32 0xFF8C00FF -/* Dark Orchid color { R:153, G:50, B:204, A:255 } */ -#define SG_DARK_ORCHID_RGBA32 0x9932CCFF -/* Dark Red color { R:139, G:0, B:0, A:255 } */ -#define SG_DARK_RED_RGBA32 0x8B0000FF -/* Dark Salmon color { R:233, G:150, B:122, A:255 } */ -#define SG_DARK_SALMON_RGBA32 0xE9967AFF -/* Dark Sea Green color { R:143, G:188, B:143, A:255 } */ -#define SG_DARK_SEA_GREEN_RGBA32 0x8FBC8FFF -/* Dark Slate Blue color { R:72, G:61, B:139, A:255 } */ -#define SG_DARK_SLATE_BLUE_RGBA32 0x483D8BFF -/* Dark Slate Gray color { R:47, G:79, B:79, A:255 } */ -#define SG_DARK_SLATE_GRAY_RGBA32 0x2F4F4FFF -/* Dark Turquoise color { R:0, G:206, B:209, A:255 } */ -#define SG_DARK_TURQUOISE_RGBA32 0x00CED1FF -/* Dark Violet color { R:148, G:0, B:211, A:255 } */ -#define SG_DARK_VIOLET_RGBA32 0x9400D3FF -/* Deep Pink color { R:255, G:20, B:147, A:255 } */ -#define SG_DEEP_PINK_RGBA32 0xFF1493FF -/* Deep Sky Blue color { R:0, G:191, B:255, A:255 } */ -#define SG_DEEP_SKY_BLUE_RGBA32 0x00BFFFFF -/* Dim Gray color { R:105, G:105, B:105, A:255 } */ -#define SG_DIM_GRAY_RGBA32 0x696969FF -/* Dodger Blue color { R:30, G:144, B:255, A:255 } */ -#define SG_DODGER_BLUE_RGBA32 0x1E90FFFF -/* Firebrick color { R:178, G:34, B:34, A:255 } */ -#define SG_FIREBRICK_RGBA32 0xB22222FF -/* Floral White color { R:255, G:250, B:240, A:255 } */ -#define SG_FLORAL_WHITE_RGBA32 0xFFFAF0FF -/* Forest Green color { R:34, G:139, B:34, A:255 } */ -#define SG_FOREST_GREEN_RGBA32 0x228B22FF -/* Fuchsia color { R:255, G:0, B:255, A:255 } */ -#define SG_FUCHSIA_RGBA32 0xFF00FFFF -/* Gainsboro color { R:220, G:220, B:220, A:255 } */ -#define SG_GAINSBORO_RGBA32 0xDCDCDCFF -/* Ghost White color { R:248, G:248, B:255, A:255 } */ -#define SG_GHOST_WHITE_RGBA32 0xF8F8FFFF -/* Gold color { R:255, G:215, B:0, A:255 } */ -#define SG_GOLD_RGBA32 0xFFD700FF -/* Goldenrod color { R:218, G:165, B:32, A:255 } */ -#define SG_GOLDENROD_RGBA32 0xDAA520FF -/* Gray color { R:190, G:190, B:190, A:255 } */ -#define SG_GRAY_RGBA32 0xBEBEBEFF -/* Web Gray color { R:128, G:128, B:128, A:255 } */ -#define SG_WEB_GRAY_RGBA32 0x808080FF -/* Green color { R:0, G:255, B:0, A:255 } */ -#define SG_GREEN_RGBA32 0x00FF00FF -/* Web Green color { R:0, G:128, B:0, A:255 } */ -#define SG_WEB_GREEN_RGBA32 0x008000FF -/* Green Yellow color { R:173, G:255, B:47, A:255 } */ -#define SG_GREEN_YELLOW_RGBA32 0xADFF2FFF -/* Honeydew color { R:240, G:255, B:240, A:255 } */ -#define SG_HONEYDEW_RGBA32 0xF0FFF0FF -/* Hot Pink color { R:255, G:105, B:180, A:255 } */ -#define SG_HOT_PINK_RGBA32 0xFF69B4FF -/* Indian Red color { R:205, G:92, B:92, A:255 } */ -#define SG_INDIAN_RED_RGBA32 0xCD5C5CFF -/* Indigo color { R:75, G:0, B:130, A:255 } */ -#define SG_INDIGO_RGBA32 0x4B0082FF -/* Ivory color { R:255, G:255, B:240, A:255 } */ -#define SG_IVORY_RGBA32 0xFFFFF0FF -/* Khaki color { R:240, G:230, B:140, A:255 } */ -#define SG_KHAKI_RGBA32 0xF0E68CFF -/* Lavender color { R:230, G:230, B:250, A:255 } */ -#define SG_LAVENDER_RGBA32 0xE6E6FAFF -/* Lavender Blush color { R:255, G:240, B:245, A:255 } */ -#define SG_LAVENDER_BLUSH_RGBA32 0xFFF0F5FF -/* Lawn Green color { R:124, G:252, B:0, A:255 } */ -#define SG_LAWN_GREEN_RGBA32 0x7CFC00FF -/* Lemon Chiffon color { R:255, G:250, B:205, A:255 } */ -#define SG_LEMON_CHIFFON_RGBA32 0xFFFACDFF -/* Light Blue color { R:173, G:216, B:230, A:255 } */ -#define SG_LIGHT_BLUE_RGBA32 0xADD8E6FF -/* Light Coral color { R:240, G:128, B:128, A:255 } */ -#define SG_LIGHT_CORAL_RGBA32 0xF08080FF -/* Light Cyan color { R:224, G:255, B:255, A:255 } */ -#define SG_LIGHT_CYAN_RGBA32 0xE0FFFFFF -/* Light Goldenrod color { R:250, G:250, B:210, A:255 } */ -#define SG_LIGHT_GOLDENROD_RGBA32 0xFAFAD2FF -/* Light Gray color { R:211, G:211, B:211, A:255 } */ -#define SG_LIGHT_GRAY_RGBA32 0xD3D3D3FF -/* Light Green color { R:144, G:238, B:144, A:255 } */ -#define SG_LIGHT_GREEN_RGBA32 0x90EE90FF -/* Light Pink color { R:255, G:182, B:193, A:255 } */ -#define SG_LIGHT_PINK_RGBA32 0xFFB6C1FF -/* Light Salmon color { R:255, G:160, B:122, A:255 } */ -#define SG_LIGHT_SALMON_RGBA32 0xFFA07AFF -/* Light Sea Green color { R:32, G:178, B:170, A:255 } */ -#define SG_LIGHT_SEA_GREEN_RGBA32 0x20B2AAFF -/* Light Sky Blue color { R:135, G:206, B:250, A:255 } */ -#define SG_LIGHT_SKY_BLUE_RGBA32 0x87CEFAFF -/* Light Slate Gray color { R:119, G:136, B:153, A:255 } */ -#define SG_LIGHT_SLATE_GRAY_RGBA32 0x778899FF -/* Light Steel Blue color { R:176, G:196, B:222, A:255 } */ -#define SG_LIGHT_STEEL_BLUE_RGBA32 0xB0C4DEFF -/* Light Yellow color { R:255, G:255, B:224, A:255 } */ -#define SG_LIGHT_YELLOW_RGBA32 0xFFFFE0FF -/* Lime color { R:0, G:255, B:0, A:255 } */ -#define SG_LIME_RGBA32 0x00FF00FF -/* Lime Green color { R:50, G:205, B:50, A:255 } */ -#define SG_LIME_GREEN_RGBA32 0x32CD32FF -/* Linen color { R:250, G:240, B:230, A:255 } */ -#define SG_LINEN_RGBA32 0xFAF0E6FF -/* Magenta color { R:255, G:0, B:255, A:255 } */ -#define SG_MAGENTA_RGBA32 0xFF00FFFF -/* Maroon color { R:176, G:48, B:96, A:255 } */ -#define SG_MAROON_RGBA32 0xB03060FF -/* Web Maroon color { R:128, G:0, B:0, A:255 } */ -#define SG_WEB_MAROON_RGBA32 0x800000FF -/* Medium Aquamarine color { R:102, G:205, B:170, A:255 } */ -#define SG_MEDIUM_AQUAMARINE_RGBA32 0x66CDAAFF -/* Medium Blue color { R:0, G:0, B:205, A:255 } */ -#define SG_MEDIUM_BLUE_RGBA32 0x0000CDFF -/* Medium Orchid color { R:186, G:85, B:211, A:255 } */ -#define SG_MEDIUM_ORCHID_RGBA32 0xBA55D3FF -/* Medium Purple color { R:147, G:112, B:219, A:255 } */ -#define SG_MEDIUM_PURPLE_RGBA32 0x9370DBFF -/* Medium Sea Green color { R:60, G:179, B:113, A:255 } */ -#define SG_MEDIUM_SEA_GREEN_RGBA32 0x3CB371FF -/* Medium Slate Blue color { R:123, G:104, B:238, A:255 } */ -#define SG_MEDIUM_SLATE_BLUE_RGBA32 0x7B68EEFF -/* Medium Spring Green color { R:0, G:250, B:154, A:255 } */ -#define SG_MEDIUM_SPRING_GREEN_RGBA32 0x00FA9AFF -/* Medium Turquoise color { R:72, G:209, B:204, A:255 } */ -#define SG_MEDIUM_TURQUOISE_RGBA32 0x48D1CCFF -/* Medium Violet Red color { R:199, G:21, B:133, A:255 } */ -#define SG_MEDIUM_VIOLET_RED_RGBA32 0xC71585FF -/* Midnight Blue color { R:25, G:25, B:112, A:255 } */ -#define SG_MIDNIGHT_BLUE_RGBA32 0x191970FF -/* Mint Cream color { R:245, G:255, B:250, A:255 } */ -#define SG_MINT_CREAM_RGBA32 0xF5FFFAFF -/* Misty Rose color { R:255, G:228, B:225, A:255 } */ -#define SG_MISTY_ROSE_RGBA32 0xFFE4E1FF -/* Moccasin color { R:255, G:228, B:181, A:255 } */ -#define SG_MOCCASIN_RGBA32 0xFFE4B5FF -/* Navajo White color { R:255, G:222, B:173, A:255 } */ -#define SG_NAVAJO_WHITE_RGBA32 0xFFDEADFF -/* Navy Blue color { R:0, G:0, B:128, A:255 } */ -#define SG_NAVY_BLUE_RGBA32 0x000080FF -/* Old Lace color { R:253, G:245, B:230, A:255 } */ -#define SG_OLD_LACE_RGBA32 0xFDF5E6FF -/* Olive color { R:128, G:128, B:0, A:255 } */ -#define SG_OLIVE_RGBA32 0x808000FF -/* Olive Drab color { R:107, G:142, B:35, A:255 } */ -#define SG_OLIVE_DRAB_RGBA32 0x6B8E23FF -/* Orange color { R:255, G:165, B:0, A:255 } */ -#define SG_ORANGE_RGBA32 0xFFA500FF -/* Orange Red color { R:255, G:69, B:0, A:255 } */ -#define SG_ORANGE_RED_RGBA32 0xFF4500FF -/* Orchid color { R:218, G:112, B:214, A:255 } */ -#define SG_ORCHID_RGBA32 0xDA70D6FF -/* Pale Goldenrod color { R:238, G:232, B:170, A:255 } */ -#define SG_PALE_GOLDENROD_RGBA32 0xEEE8AAFF -/* Pale Green color { R:152, G:251, B:152, A:255 } */ -#define SG_PALE_GREEN_RGBA32 0x98FB98FF -/* Pale Turquoise color { R:175, G:238, B:238, A:255 } */ -#define SG_PALE_TURQUOISE_RGBA32 0xAFEEEEFF -/* Pale Violet Red color { R:219, G:112, B:147, A:255 } */ -#define SG_PALE_VIOLET_RED_RGBA32 0xDB7093FF -/* Papaya Whip color { R:255, G:239, B:213, A:255 } */ -#define SG_PAPAYA_WHIP_RGBA32 0xFFEFD5FF -/* Peach Puff color { R:255, G:218, B:185, A:255 } */ -#define SG_PEACH_PUFF_RGBA32 0xFFDAB9FF -/* Peru color { R:205, G:133, B:63, A:255 } */ -#define SG_PERU_RGBA32 0xCD853FFF -/* Pink color { R:255, G:192, B:203, A:255 } */ -#define SG_PINK_RGBA32 0xFFC0CBFF -/* Plum color { R:221, G:160, B:221, A:255 } */ -#define SG_PLUM_RGBA32 0xDDA0DDFF -/* Powder Blue color { R:176, G:224, B:230, A:255 } */ -#define SG_POWDER_BLUE_RGBA32 0xB0E0E6FF -/* Purple color { R:160, G:32, B:240, A:255 } */ -#define SG_PURPLE_RGBA32 0xA020F0FF -/* Web Purple color { R:128, G:0, B:128, A:255 } */ -#define SG_WEB_PURPLE_RGBA32 0x800080FF -/* Rebecca Purple color { R:102, G:51, B:153, A:255 } */ -#define SG_REBECCA_PURPLE_RGBA32 0x663399FF -/* Red color { R:255, G:0, B:0, A:255 } */ -#define SG_RED_RGBA32 0xFF0000FF -/* Rosy Brown color { R:188, G:143, B:143, A:255 } */ -#define SG_ROSY_BROWN_RGBA32 0xBC8F8FFF -/* Royal Blue color { R:65, G:105, B:225, A:255 } */ -#define SG_ROYAL_BLUE_RGBA32 0x4169E1FF -/* Saddle Brown color { R:139, G:69, B:19, A:255 } */ -#define SG_SADDLE_BROWN_RGBA32 0x8B4513FF -/* Salmon color { R:250, G:128, B:114, A:255 } */ -#define SG_SALMON_RGBA32 0xFA8072FF -/* Sandy Brown color { R:244, G:164, B:96, A:255 } */ -#define SG_SANDY_BROWN_RGBA32 0xF4A460FF -/* Sea Green color { R:46, G:139, B:87, A:255 } */ -#define SG_SEA_GREEN_RGBA32 0x2E8B57FF -/* Seashell color { R:255, G:245, B:238, A:255 } */ -#define SG_SEASHELL_RGBA32 0xFFF5EEFF -/* Sienna color { R:160, G:82, B:45, A:255 } */ -#define SG_SIENNA_RGBA32 0xA0522DFF -/* Silver color { R:192, G:192, B:192, A:255 } */ -#define SG_SILVER_RGBA32 0xC0C0C0FF -/* Sky Blue color { R:135, G:206, B:235, A:255 } */ -#define SG_SKY_BLUE_RGBA32 0x87CEEBFF -/* Slate Blue color { R:106, G:90, B:205, A:255 } */ -#define SG_SLATE_BLUE_RGBA32 0x6A5ACDFF -/* Slate Gray color { R:112, G:128, B:144, A:255 } */ -#define SG_SLATE_GRAY_RGBA32 0x708090FF -/* Snow color { R:255, G:250, B:250, A:255 } */ -#define SG_SNOW_RGBA32 0xFFFAFAFF -/* Spring Green color { R:0, G:255, B:127, A:255 } */ -#define SG_SPRING_GREEN_RGBA32 0x00FF7FFF -/* Steel Blue color { R:70, G:130, B:180, A:255 } */ -#define SG_STEEL_BLUE_RGBA32 0x4682B4FF -/* Tan color { R:210, G:180, B:140, A:255 } */ -#define SG_TAN_RGBA32 0xD2B48CFF -/* Teal color { R:0, G:128, B:128, A:255 } */ -#define SG_TEAL_RGBA32 0x008080FF -/* Thistle color { R:216, G:191, B:216, A:255 } */ -#define SG_THISTLE_RGBA32 0xD8BFD8FF -/* Tomato color { R:255, G:99, B:71, A:255 } */ -#define SG_TOMATO_RGBA32 0xFF6347FF -/* Transparent color { R:0, G:0, B:0, A:0 } */ -#define SG_TRANSPARENT_RGBA32 0x00000000 -/* Turquoise color { R:64, G:224, B:208, A:255 } */ -#define SG_TURQUOISE_RGBA32 0x40E0D0FF -/* Violet color { R:238, G:130, B:238, A:255 } */ -#define SG_VIOLET_RGBA32 0xEE82EEFF -/* Wheat color { R:245, G:222, B:179, A:255 } */ -#define SG_WHEAT_RGBA32 0xF5DEB3FF -/* White color { R:255, G:255, B:255, A:255 } */ -#define SG_WHITE_RGBA32 0xFFFFFFFF -/* White Smoke color { R:245, G:245, B:245, A:255 } */ -#define SG_WHITE_SMOKE_RGBA32 0xF5F5F5FF -/* Yellow color { R:255, G:255, B:0, A:255 } */ -#define SG_YELLOW_RGBA32 0xFFFF00FF -/* Yellow Green color { R:154, G:205, B:50, A:255 } */ -#define SG_YELLOW_GREEN_RGBA32 0x9ACD32FF - -#ifdef __cplusplus -} /* extern "C" */ - -inline sg_color sg_make_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return sg_make_color_4b(r, g, b, a); -} - -inline sg_color sg_make_color(uint32_t rgba) { - return sg_make_color_1i(rgba); -} - -inline sg_color sg_color_lerp(const sg_color& color_a, const sg_color& color_b, float amount) { - return sg_color_lerp(&color_a, &color_b, amount); -} - -inline sg_color sg_color_lerp_precise(const sg_color& color_a, const sg_color& color_b, float amount) { - return sg_color_lerp_precise(&color_a, &color_b, amount); -} - -inline sg_color sg_color_multiply(const sg_color& color, float scale) { - return sg_color_multiply(&color, scale); -} - -#endif /* __cplusplus */ - -#endif /* SOKOL_COLOR_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_COLOR_IMPL -#define SOKOL_COLOR_IMPL_INCLUDED (1) - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -static inline float _sg_color_clamp(float v, float low, float high) { - if (v < low) { - return low; - } else if (v > high) { - return high; - } - return v; -} - -static inline float _sg_color_lerp(float a, float b, float amount) { - return a + (b - a) * amount; -} - -static inline float _sg_color_lerp_precise(float a, float b, float amount) { - return ((1.0f - amount) * a) + (b * amount); -} - -SOKOL_API_IMPL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - sg_color result; - result.r = r / 255.0f; - result.g = g / 255.0f; - result.b = b / 255.0f; - result.a = a / 255.0f; - return result; -} - -SOKOL_API_IMPL sg_color sg_make_color_1i(uint32_t rgba) { - return sg_make_color_4b( - (uint8_t)(rgba >> 24), - (uint8_t)(rgba >> 16), - (uint8_t)(rgba >> 8), - (uint8_t)(rgba >> 0) - ); -} - -SOKOL_API_IMPL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) { - SOKOL_ASSERT(color_a); - SOKOL_ASSERT(color_b); - amount = _sg_color_clamp(amount, 0.0f, 1.0f); - sg_color result; - result.r = _sg_color_lerp(color_a->r, color_b->r, amount); - result.g = _sg_color_lerp(color_a->g, color_b->g, amount); - result.b = _sg_color_lerp(color_a->b, color_b->b, amount); - result.a = _sg_color_lerp(color_a->a, color_b->a, amount); - return result; -} - -SOKOL_API_IMPL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) { - SOKOL_ASSERT(color_a); - SOKOL_ASSERT(color_b); - amount = _sg_color_clamp(amount, 0.0f, 1.0f); - sg_color result; - result.r = _sg_color_lerp_precise(color_a->r, color_b->r, amount); - result.g = _sg_color_lerp_precise(color_a->g, color_b->g, amount); - result.b = _sg_color_lerp_precise(color_a->b, color_b->b, amount); - result.a = _sg_color_lerp_precise(color_a->a, color_b->a, amount); - return result; -} - -SOKOL_API_IMPL sg_color sg_color_multiply(const sg_color* color, float scale) { - SOKOL_ASSERT(color); - sg_color result; - result.r = color->r * scale; - result.g = color->g * scale; - result.b = color->b * scale; - result.a = color->a * scale; - return result; -} - -#endif /* SOKOL_COLOR_IMPL */ diff --git a/source/engine/thirdparty/sokol/util/sokol_debugtext.h b/source/engine/thirdparty/sokol/util/sokol_debugtext.h deleted file mode 100644 index cec0694..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_debugtext.h +++ /dev/null @@ -1,4561 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_DEBUGTEXT_IMPL) -#define SOKOL_DEBUGTEXT_IMPL -#endif -#ifndef SOKOL_DEBUGTEXT_INCLUDED -/* - sokol_debugtext.h - simple ASCII debug text rendering on top of sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_DEBUGTEXT_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - The following defines are used by the implementation to select the - platform-specific embedded shader code (these are the same defines as - used by sokol_gfx.h and sokol_app.h): - - SOKOL_GLCORE33 - SOKOL_GLES3 - SOKOL_D3D11 - SOKOL_METAL - SOKOL_WGPU - - ...optionally provide the following macros to override defaults: - - SOKOL_VSNPRINTF - the function name of an alternative vsnprintf() function (default: vsnprintf) - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_DEBUGTEXT_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_DEBUGTEXT_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - If sokol_debugtext.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_DEBUGTEXT_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before including sokol_debugtext.h: - - sokol_gfx.h - - FEATURES AND CONCEPTS - ===================== - - renders 8-bit ASCII text as fixed-size 8x8 pixel characters - - comes with 6 embedded 8-bit home computer fonts (each taking up 2 KBytes) - - easily plug in your own fonts - - create multiple contexts for rendering text in different layers or render passes - - STEP BY STEP - ============ - - --- to initialize sokol-debugtext, call sdtx_setup() *after* initializing - sokol-gfx: - - sdtx_setup(&(sdtx_desc_t){ ... }); - - To see any warnings and errors, you should always install a logging callback. - The easiest way is via sokol_log.h: - - #include "sokol_log.h" - - sdtx_setup(&(sdtx_desc_t){ - .logger.func = slog_func, - }); - - --- configure sokol-debugtext by populating the sdtx_desc_t struct: - - .context_pool_size (default: 8) - The max number of text contexts that can be created. - - .printf_buf_size (default: 4096) - The size of the internal text formatting buffer used by - sdtx_printf() and sdtx_vprintf(). - - .fonts (default: none) - An array of sdtx_font_desc_t structs used to configure the - fonts that can be used for rendering. To use all builtin - fonts call sdtx_setup() like this (in C99): - - sdtx_setup(&(sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = sdtx_font_kc854(), - [2] = sdtx_font_z1013(), - [3] = sdtx_font_cpc(), - [4] = sdtx_font_c64(), - [5] = sdtx_font_oric() - } - }); - - For documentation on how to use you own font data, search - below for "USING YOUR OWN FONT DATA". - - .context - The setup parameters for the default text context. This will - be active right after sdtx_setup(), or when calling - sdtx_set_context(SDTX_DEFAULT_CONTEXT): - - .max_commands (default: 4096) - The max number of render commands that can be recorded - into the internal command buffer. This directly translates - to the number of render layer changes in a single frame. - - .char_buf_size (default: 4096) - The number of characters that can be rendered per frame in this - context, defines the size of an internal fixed-size vertex - buffer. Any additional characters will be silently ignored. - - .canvas_width (default: 640) - .canvas_height (default: 480) - The 'virtual canvas size' in pixels. This defines how big - characters will be rendered relative to the default framebuffer - dimensions. Each character occupies a grid of 8x8 'virtual canvas - pixels' (so a virtual canvas size of 640x480 means that 80x60 characters - fit on the screen). For rendering in a resizeable window, you - should dynamically update the canvas size in each frame by - calling sdtx_canvas(w, h). - - .tab_width (default: 4) - The width of a tab character in number of character cells. - - .color_format (default: 0) - .depth_format (default: 0) - .sample_count (default: 0) - The pixel format description for the default context needed - for creating the context's sg_pipeline object. When - rendering to the default framebuffer you can leave those - zero-initialized, in this case the proper values will be - filled in by sokol-gfx. You only need to provide non-default - values here when rendering to render targets with different - pixel format attributes than the default framebuffer. - - --- Before starting to render text, optionally call sdtx_canvas() to - dynamically resize the virtual canvas. This is recommended when - rendering to a resizeable window. The virtual canvas size can - also be used to scale text in relation to the display resolution. - - Examples when using sokol-app: - - - to render characters at 8x8 'physical pixels': - - sdtx_canvas(sapp_width(), sapp_height()); - - - to render characters at 16x16 physical pixels: - - sdtx_canvas(sapp_width()/2.0f, sapp_height()/2.0f); - - Do *not* use integer math here, since this will not look nice - when the render target size isn't divisible by 2. - - --- Optionally define the origin for the character grid with: - - sdtx_origin(x, y); - - The provided coordinates are in character grid cells, not in - virtual canvas pixels. E.g. to set the origin to 2 character tiles - from the left and top border: - - sdtx_origin(2, 2); - - You can define fractions, e.g. to start rendering half - a character tile from the top-left corner: - - sdtx_origin(0.5f, 0.5f); - - --- Optionally set a different font by calling: - - sdtx_font(font_index) - - sokol-debugtext provides 8 font slots which can be populated - with the builtin fonts or with user-provided font data, so - 'font_index' must be a number from 0 to 7. - - --- Position the text cursor with one of the following calls. All arguments - are in character grid cells as floats and relative to the - origin defined with sdtx_origin(): - - sdtx_pos(x, y) - sets absolute cursor position - sdtx_pos_x(x) - only set absolute x cursor position - sdtx_pos_y(y) - only set absolute y cursor position - - sdtx_move(x, y) - move cursor relative in x and y direction - sdtx_move_x(x) - move cursor relative only in x direction - sdtx_move_y(y) - move cursor relative only in y direction - - sdtx_crlf() - set cursor to beginning of next line - (same as sdtx_pos_x(0) + sdtx_move_y(1)) - sdtx_home() - resets the cursor to the origin - (same as sdtx_pos(0, 0)) - - --- Set a new text color with any of the following functions: - - sdtx_color3b(r, g, b) - RGB 0..255, A=255 - sdtx_color3f(r, g, b) - RGB 0.0f..1.0f, A=1.0f - sdtx_color4b(r, g, b, a) - RGBA 0..255 - sdtx_color4f(r, g, b, a) - RGBA 0.0f..1.0f - sdtx_color1i(uint32_t rgba) - ABGR (0xAABBGGRR) - - --- Output 8-bit ASCII text with the following functions: - - sdtx_putc(c) - output a single character - - sdtx_puts(str) - output a null-terminated C string, note that - this will *not* append a newline (so it behaves - differently than the CRT's puts() function) - - sdtx_putr(str, len) - 'put range' output the first 'len' characters of - a C string or until the zero character is encountered - - sdtx_printf(fmt, ...) - output with printf-formatting, note that you - can inject your own printf-compatible function - by overriding the SOKOL_VSNPRINTF define before - including the implementation - - sdtx_vprintf(fmt, args) - same as sdtx_printf() but with the arguments - provided in a va_list - - - Note that the text will not yet be rendered, only recorded for rendering - at a later time, the actual rendering happens when sdtx_draw() is called - inside a sokol-gfx render pass. - - This means also you can output text anywhere in the frame, it doesn't - have to be inside a render pass. - - Note that character codes <32 are reserved as control characters - and won't render anything. Currently only the following control - characters are implemented: - - \r - carriage return (same as sdtx_pos_x(0)) - \n - carriage return + line feed (same as stdx_crlf()) - \t - a tab character - - --- You can 'record' text into render layers, this allows to mix/interleave - sokol-debugtext rendering with other rendering operations inside - sokol-gfx render passes. To start recording text into a different render - layer, call: - - sdtx_layer(int layer_id) - - ...outside a sokol-gfx render pass. - - --- finally, from within a sokol-gfx render pass, call: - - sdtx_draw() - - ...for non-layered rendering, or to draw a specific layer: - - sdtx_draw_layer(int layer_id) - - NOTE that sdtx_draw() is equivalent to: - - sdtx_draw_layer(0) - - ...so sdtx_draw() will *NOT* render all text layers, instead it will - only render the 'default layer' 0. - - --- at the end of a frame (defined by the call to sg_commit()), sokol-debugtext - will rewind all contexts: - - - the internal vertex index is set to 0 - - the internal command index is set to 0 - - the current layer id is set to 0 - - the current font is set to 0 - - the cursor position is reset - - - RENDERING WITH MULTIPLE CONTEXTS - ================================ - Use multiple text contexts if you need to render debug text in different - sokol-gfx render passes, or want to render text to different layers - in the same render pass, each with its own set of parameters. - - To create a new text context call: - - sdtx_context ctx = sdtx_make_context(&(sdtx_context_desc_t){ ... }); - - The creation parameters in the sdtx_context_desc_t struct are the same - as already described above in the sdtx_setup() function: - - .char_buf_size -- max number of characters rendered in one frame, default: 4096 - .canvas_width -- the initial virtual canvas width, default: 640 - .canvas_height -- the initial virtual canvas height, default: 400 - .tab_width -- tab width in number of characters, default: 4 - .color_format -- color pixel format of target render pass - .depth_format -- depth pixel format of target render pass - .sample_count -- MSAA sample count of target render pass - - To make a new context the active context, call: - - sdtx_set_context(ctx) - - ...and after that call the text output functions as described above, and - finally, inside a sokol-gfx render pass, call sdtx_draw() to actually - render the text for this context. - - A context keeps track of the following parameters: - - - the active font - - the virtual canvas size - - the origin position - - the current cursor position - - the current tab width - - the current color - - and the current layer-id - - You can get the currently active context with: - - sdtx_get_context() - - To make the default context current, call sdtx_set_context() with the - special SDTX_DEFAULT_CONTEXT handle: - - sdtx_set_context(SDTX_DEFAULT_CONTEXT) - - Alternatively, use the function sdtx_default_context() to get the default - context handle: - - sdtx_set_context(sdtx_default_context()); - - To destroy a context, call: - - sdtx_destroy_context(ctx) - - If a context is set as active that no longer exists, all sokol-debugtext - functions that require an active context will silently fail. - - You can directly draw the recorded text in a specific context without - setting the active context: - - sdtx_context_draw(ctx) - sdtx_context_draw_layer(ctx, layer_id) - - USING YOUR OWN FONT DATA - ======================== - - Instead of the built-in fonts you can also plug your own font data - into sokol-debugtext by providing one or several sdtx_font_desc_t - structures in the sdtx_setup call. - - For instance to use a built-in font at slot 0, and a user-font at - font slot 1, the sdtx_setup() call might look like this: - - sdtx_setup(&sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = { - .data = { - .ptr = my_font_data, - .size = sizeof(my_font_data) - }, - .first_char = ..., - .last_char = ... - } - } - }); - - Where 'my_font_data' is a byte array where every character is described - by 8 bytes arranged like this: - - bits - 7 6 5 4 3 2 1 0 - . . . X X . . . byte 0: 0x18 - . . X X X X . . byte 1: 0x3C - . X X . . X X . byte 2: 0x66 - . X X . . X X . byte 3: 0x66 - . X X X X X X . byte 4: 0x7E - . X X . . X X . byte 5: 0x66 - . X X . . X X . byte 6: 0x66 - . . . . . . . . byte 7: 0x00 - - A complete font consists of 256 characters, resulting in 2048 bytes for - the font data array (but note that the character codes 0..31 will never - be rendered). - - If you provide such a complete font data array, you can drop the .first_char - and .last_char initialization parameters since those default to 0 and 255, - note that you can also use the SDTX_RANGE() helper macro to build the - .data item: - - sdtx_setup(&sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = { - .data = SDTX_RANGE(my_font_data) - } - } - }); - - If the font doesn't define all 256 character tiles, or you don't need an - entire 256-character font and want to save a couple of bytes, use the - .first_char and .last_char initialization parameters to define a sub-range. - For instance if the font only contains the characters between the Space - (ASCII code 32) and uppercase character 'Z' (ASCII code 90): - - sdtx_setup(&sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = { - .data = SDTX_RANGE(my_font_data), - .first_char = 32, // could also write ' ' - .last_char = 90 // could also write 'Z' - } - } - }); - - Character tiles that haven't been defined in the font will be rendered - as a solid 8x8 quad. - - - MEMORY ALLOCATION OVERRIDE - ========================== - You can override the memory allocation functions at initialization time - like this: - - void* my_alloc(size_t size, void* user_data) { - return malloc(size); - } - - void my_free(void* ptr, void* user_data) { - free(ptr); - } - - ... - sdtx_setup(&(sdtx_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - - ERROR REPORTING AND LOGGING - =========================== - To get any logging information at all you need to provide a logging callback in the setup call, - the easiest way is to use sokol_log.h: - - #include "sokol_log.h" - - sdtx_setup(&(sdtx_desc_t){ - // ... - .logger.func = slog_func - }); - - To override logging with your own callback, first write a logging function like this: - - void my_log(const char* tag, // e.g. 'sdtx' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SDTX_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_debugtext.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-debugtext like this: - - sdtx_setup(&(sdtx_desc_t){ - .logger = { - .func = my_log, - .user_data = my_user_data, - } - }); - - The provided logging function must be reentrant (e.g. be callable from - different threads). - - If you don't want to provide your own custom logger it is highly recommended to use - the standard logger in sokol_log.h instead, otherwise you won't see any warnings or - errors. - - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2020 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_DEBUGTEXT_INCLUDED (1) -#include -#include -#include // size_t -#include // va_list - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_debugtext.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_DEBUGTEXT_API_DECL) -#define SOKOL_DEBUGTEXT_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_DEBUGTEXT_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_DEBUGTEXT_IMPL) -#define SOKOL_DEBUGTEXT_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_DEBUGTEXT_API_DECL __declspec(dllimport) -#else -#define SOKOL_DEBUGTEXT_API_DECL extern -#endif -#endif - -#if defined(__GNUC__) -#define SOKOL_DEBUGTEXT_PRINTF_ATTR __attribute__((format(printf, 1, 2))) -#else -#define SOKOL_DEBUGTEXT_PRINTF_ATTR -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sdtx_log_item_t - - Log items are defined via X-Macros, and expanded to an - enum 'sdtx_log_item' - and in debug mode only - corresponding strings. - - Used as parameter in the logging callback. -*/ -#define _SDTX_LOG_ITEMS \ - _SDTX_LOGITEM_XMACRO(OK, "Ok") \ - _SDTX_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SDTX_LOGITEM_XMACRO(ADD_COMMIT_LISTENER_FAILED, "sg_add_commit_listener() failed") \ - _SDTX_LOGITEM_XMACRO(COMMAND_BUFFER_FULL, "command buffer full (adjust via sdtx_context_desc_t.max_commands)") \ - _SDTX_LOGITEM_XMACRO(CONTEXT_POOL_EXHAUSTED, "context pool exhausted (adjust via sdtx_desc_t.context_pool_size)") \ - _SDTX_LOGITEM_XMACRO(CANNOT_DESTROY_DEFAULT_CONTEXT, "cannot destroy default context") \ - -#define _SDTX_LOGITEM_XMACRO(item,msg) SDTX_LOGITEM_##item, -typedef enum sdtx_log_item_t { - _SDTX_LOG_ITEMS -} sdtx_log_item_t; -#undef _SDTX_LOGITEM_XMACRO - -/* - sdtx_logger_t - - Used in sdtx_desc_t to provide a custom logging and error reporting - callback to sokol-debugtext. -*/ -typedef struct sdtx_logger_t { - void (*func)( - const char* tag, // always "sdtx" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SDTX_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_debugtext.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sdtx_logger_t; - -/* a rendering context handle */ -typedef struct sdtx_context { uint32_t id; } sdtx_context; - -/* the default context handle */ -static const sdtx_context SDTX_DEFAULT_CONTEXT = { 0x00010001 }; - -/* - sdtx_range is a pointer-size-pair struct used to pass memory - blobs into sokol-debugtext. When initialized from a value type - (array or struct), use the SDTX_RANGE() macro to build - an sdtx_range struct. -*/ -typedef struct sdtx_range { - const void* ptr; - size_t size; -} sdtx_range; - -// disabling this for every includer isn't great, but the warning is also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ -#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */ -#endif -#if defined(__cplusplus) -#define SDTX_RANGE(x) sdtx_range{ &x, sizeof(x) } -#else -#define SDTX_RANGE(x) (sdtx_range){ &x, sizeof(x) } -#endif - -/* - sdtx_font_desc_t - - Describes the pixel data of a font. A font consists of up to - 256 8x8 character tiles, where each character tile is described - by 8 consecutive bytes, each byte describing 8 pixels. - - For instance the character 'A' could look like this (this is also - how most home computers used to describe their fonts in ROM): - - bits - 7 6 5 4 3 2 1 0 - . . . X X . . . byte 0: 0x18 - . . X X X X . . byte 1: 0x3C - . X X . . X X . byte 2: 0x66 - . X X . . X X . byte 3: 0x66 - . X X X X X X . byte 4: 0x7E - . X X . . X X . byte 5: 0x66 - . X X . . X X . byte 6: 0x66 - . . . . . . . . byte 7: 0x00 - */ -#define SDTX_MAX_FONTS (8) - -typedef struct sdtx_font_desc_t { - sdtx_range data; // pointer to and size of font pixel data - uint8_t first_char; // first character index in font pixel data - uint8_t last_char; // last character index in font pixel data, inclusive (default: 255) -} sdtx_font_desc_t; - -/* - sdtx_context_desc_t - - Describes the initialization parameters of a rendering context. Creating - additional rendering contexts is useful if you want to render in - different sokol-gfx rendering passes, or when rendering several layers - of text. -*/ -typedef struct sdtx_context_desc_t { - int max_commands; // max number of draw commands, each layer transition counts as a command, default: 4096 - int char_buf_size; // max number of characters rendered in one frame, default: 4096 - float canvas_width; // the initial virtual canvas width, default: 640 - float canvas_height; // the initial virtual canvas height, default: 400 - int tab_width; // tab width in number of characters, default: 4 - sg_pixel_format color_format; // color pixel format of target render pass - sg_pixel_format depth_format; // depth pixel format of target render pass - int sample_count; // MSAA sample count of target render pass -} sdtx_context_desc_t; - -/* - sdtx_allocator_t - - Used in sdtx_desc_t to provide custom memory-alloc and -free functions - to sokol_debugtext.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sdtx_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sdtx_allocator_t; - -/* - sdtx_desc_t - - Describes the sokol-debugtext API initialization parameters. Passed - to the sdtx_setup() function. - - NOTE: to populate the fonts item array with builtin fonts, use any - of the following functions: - - sdtx_font_kc853() - sdtx_font_kc854() - sdtx_font_z1013() - sdtx_font_cpc() - sdtx_font_c64() - sdtx_font_oric() -*/ -typedef struct sdtx_desc_t { - int context_pool_size; // max number of rendering contexts that can be created, default: 8 - int printf_buf_size; // size of internal buffer for snprintf(), default: 4096 - sdtx_font_desc_t fonts[SDTX_MAX_FONTS]; // up to 8 fonts descriptions - sdtx_context_desc_t context; // the default context creation parameters - sdtx_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - sdtx_logger_t logger; // optional log override function (default: NO LOGGING) -} sdtx_desc_t; - -/* initialization/shutdown */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_setup(const sdtx_desc_t* desc); -SOKOL_DEBUGTEXT_API_DECL void sdtx_shutdown(void); - -/* builtin font data (use to populate sdtx_desc.font[]) */ -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_kc853(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_kc854(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_z1013(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_cpc(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_c64(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_oric(void); - -/* context functions */ -SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_make_context(const sdtx_context_desc_t* desc); -SOKOL_DEBUGTEXT_API_DECL void sdtx_destroy_context(sdtx_context ctx); -SOKOL_DEBUGTEXT_API_DECL void sdtx_set_context(sdtx_context ctx); -SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_get_context(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_default_context(void); - -/* drawing functions (call inside sokol-gfx render pass) */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_draw(void); -SOKOL_DEBUGTEXT_API_DECL void sdtx_context_draw(sdtx_context ctx); -SOKOL_DEBUGTEXT_API_DECL void sdtx_draw_layer(int layer_id); -SOKOL_DEBUGTEXT_API_DECL void sdtx_context_draw_layer(sdtx_context ctx, int layer_id); - -/* switch render layer */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_layer(int layer_id); - -/* switch to a different font */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_font(int font_index); - -/* set a new virtual canvas size in screen pixels */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_canvas(float w, float h); - -/* set a new origin in character grid coordinates */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_origin(float x, float y); - -/* cursor movement functions (relative to origin in character grid coordinates) */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_home(void); -SOKOL_DEBUGTEXT_API_DECL void sdtx_pos(float x, float y); -SOKOL_DEBUGTEXT_API_DECL void sdtx_pos_x(float x); -SOKOL_DEBUGTEXT_API_DECL void sdtx_pos_y(float y); -SOKOL_DEBUGTEXT_API_DECL void sdtx_move(float dx, float dy); -SOKOL_DEBUGTEXT_API_DECL void sdtx_move_x(float dx); -SOKOL_DEBUGTEXT_API_DECL void sdtx_move_y(float dy); -SOKOL_DEBUGTEXT_API_DECL void sdtx_crlf(void); - -/* set the current text color */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_color3b(uint8_t r, uint8_t g, uint8_t b); // RGB 0..255, A=255 -SOKOL_DEBUGTEXT_API_DECL void sdtx_color3f(float r, float g, float b); // RGB 0.0f..1.0f, A=1.0f -SOKOL_DEBUGTEXT_API_DECL void sdtx_color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); // RGBA 0..255 -SOKOL_DEBUGTEXT_API_DECL void sdtx_color4f(float r, float g, float b, float a); // RGBA 0.0f..1.0f -SOKOL_DEBUGTEXT_API_DECL void sdtx_color1i(uint32_t rgba); // ABGR 0xAABBGGRR - -/* text rendering */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_putc(char c); -SOKOL_DEBUGTEXT_API_DECL void sdtx_puts(const char* str); // does NOT append newline! -SOKOL_DEBUGTEXT_API_DECL void sdtx_putr(const char* str, int len); // 'put range', also stops at zero-char -SOKOL_DEBUGTEXT_API_DECL int sdtx_printf(const char* fmt, ...) SOKOL_DEBUGTEXT_PRINTF_ATTR; -SOKOL_DEBUGTEXT_API_DECL int sdtx_vprintf(const char* fmt, va_list args); - -#ifdef __cplusplus -} /* extern "C" */ -/* C++ const-ref wrappers */ -inline void sdtx_setup(const sdtx_desc_t& desc) { return sdtx_setup(&desc); } -inline sdtx_context sdtx_make_context(const sdtx_context_desc_t& desc) { return sdtx_make_context(&desc); } -#endif -#endif /* SOKOL_DEBUGTEXT_INCLUDED */ - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_DEBUGTEXT_IMPL -#define SOKOL_DEBUGTEXT_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sdtx_desc_t.allocator to override memory allocation functions" -#endif - -#include // memset -#include // fmodf -#include // for vsnprintf -#include // malloc/free - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#ifndef SOKOL_VSNPRINTF -#include -#define SOKOL_VSNPRINTF vsnprintf -#endif - -#define _sdtx_def(val, def) (((val) == 0) ? (def) : (val)) -#define _SDTX_INIT_COOKIE (0xACBAABCA) - -#define _SDTX_DEFAULT_MAX_COMMANDS (4096) -#define _SDTX_DEFAULT_CONTEXT_POOL_SIZE (8) -#define _SDTX_DEFAULT_CHAR_BUF_SIZE (4096) -#define _SDTX_DEFAULT_PRINTF_BUF_SIZE (4096) -#define _SDTX_DEFAULT_CANVAS_WIDTH (640) -#define _SDTX_DEFAULT_CANVAS_HEIGHT (480) -#define _SDTX_DEFAULT_TAB_WIDTH (4) -#define _SDTX_DEFAULT_COLOR (0xFF00FFFF) -#define _SDTX_INVALID_SLOT_INDEX (0) -#define _SDTX_SLOT_SHIFT (16) -#define _SDTX_MAX_POOL_SIZE (1<<_SDTX_SLOT_SHIFT) -#define _SDTX_SLOT_MASK (_SDTX_MAX_POOL_SIZE-1) - -/* embedded font data */ -static const uint8_t _sdtx_font_kc853[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFF, // 00 - 0x00, 0x00, 0x22, 0x72, 0x22, 0x3E, 0x00, 0x00, // 01 - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x32, 0x12, 0x00, // 02 - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xB9, 0x81, // 03 - 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 04 - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 05 - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, // 06 - 0x00, 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x00, 0x00, // 07 - 0x00, 0x10, 0x30, 0x7E, 0x30, 0x10, 0x00, 0x00, // 08 - 0x00, 0x08, 0x0C, 0x7E, 0x0C, 0x08, 0x00, 0x00, // 09 - 0x00, 0x10, 0x10, 0x10, 0x7C, 0x38, 0x10, 0x00, // 0A - 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00, // 0B - 0x38, 0x30, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, // 0C - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x30, 0x10, 0x00, // 0D - 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // 0E - 0x3E, 0x7C, 0x7C, 0x3E, 0x3E, 0x7C, 0xF8, 0xF8, // 0F - 0x38, 0x30, 0x28, 0x04, 0x04, 0x04, 0x04, 0x00, // 10 - 0x7F, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x00, // 11 - 0x00, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x7F, // 12 - 0x7E, 0x81, 0x9D, 0xA1, 0xB9, 0x85, 0x85, 0xB9, // 13 - 0x00, 0x3C, 0x42, 0x5A, 0x5A, 0x42, 0x3C, 0x00, // 14 - 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, // 15 - 0x00, 0x7F, 0x22, 0x72, 0x27, 0x22, 0x7F, 0x00, // 16 - 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, // 17 - 0x00, 0x01, 0x09, 0x0D, 0x7F, 0x0D, 0x09, 0x01, // 18 - 0x00, 0x90, 0xB0, 0xFE, 0xB0, 0x90, 0x00, 0x00, // 19 - 0x00, 0x08, 0x7C, 0x06, 0x7C, 0x08, 0x00, 0x00, // 1A - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // 1B - 0x7E, 0x81, 0xA1, 0xA1, 0xA1, 0xA1, 0xBD, 0x81, // 1C - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xA5, 0x81, // 1D - 0x7E, 0x81, 0x99, 0xA1, 0xA1, 0xA1, 0x99, 0x81, // 1E - 0x00, 0x10, 0x3E, 0x60, 0x3E, 0x10, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, // 21 - 0x00, 0x66, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, // 22 - 0x00, 0x36, 0x7F, 0x36, 0x36, 0x7F, 0x36, 0x00, // 23 - 0x18, 0x3E, 0x6C, 0x3E, 0x1B, 0x1B, 0x7E, 0x18, // 24 - 0x00, 0x63, 0x66, 0x0C, 0x18, 0x36, 0x66, 0x00, // 25 - 0x18, 0x24, 0x28, 0x11, 0x2A, 0x44, 0x4A, 0x31, // 26 - 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // 27 - 0x00, 0x18, 0x30, 0x30, 0x30, 0x30, 0x18, 0x00, // 28 - 0x00, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x00, // 29 - 0x00, 0x00, 0x24, 0x18, 0x7E, 0x18, 0x24, 0x00, // 2A - 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, // 2C - 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // 2E - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, 0x00, // 2F - 0x00, 0x3C, 0x6E, 0x6E, 0x76, 0x76, 0x3C, 0x00, // 30 - 0x00, 0x1C, 0x3C, 0x0C, 0x0C, 0x0C, 0x3E, 0x00, // 31 - 0x00, 0x3C, 0x66, 0x06, 0x3C, 0x60, 0x7E, 0x00, // 32 - 0x00, 0x3C, 0x66, 0x0C, 0x06, 0x66, 0x3C, 0x00, // 33 - 0x00, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x00, // 34 - 0x00, 0x7E, 0x60, 0x7C, 0x06, 0x66, 0x3C, 0x00, // 35 - 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 36 - 0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, // 37 - 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 38 - 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x3C, 0x00, // 39 - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, // 3A - 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x30, 0x00, // 3B - 0x00, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, // 3C - 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, // 3D - 0x00, 0x00, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x00, // 3E - 0x00, 0x3C, 0x66, 0x06, 0x1C, 0x18, 0x00, 0x18, // 3F - 0x3C, 0x42, 0x81, 0x35, 0x49, 0x49, 0x49, 0x36, // 40 - 0x00, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 41 - 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, // 42 - 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x00, // 43 - 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // 44 - 0x00, 0x7E, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, // 45 - 0x00, 0x7E, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, // 46 - 0x00, 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x3C, 0x00, // 47 - 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 48 - 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 49 - 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, // 4A - 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x63, 0x00, // 4B - 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, // 4C - 0x00, 0x63, 0x77, 0x6B, 0x63, 0x63, 0x63, 0x00, // 4D - 0x00, 0x63, 0x73, 0x6B, 0x67, 0x63, 0x63, 0x00, // 4E - 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 4F - 0x00, 0x7C, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, // 50 - 0x00, 0x3C, 0x66, 0x66, 0x6E, 0x66, 0x3A, 0x01, // 51 - 0x00, 0x7C, 0x66, 0x7C, 0x6C, 0x66, 0x63, 0x00, // 52 - 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // 53 - 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 54 - 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 55 - 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 56 - 0x00, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, // 57 - 0x00, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0x00, // 58 - 0x00, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, // 59 - 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, // 5A - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5B - 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 5C - 0x00, 0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, // 5D - 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 5F - 0x7E, 0x81, 0x99, 0xA1, 0xA1, 0x99, 0x81, 0x7E, // 60 - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3B, 0x00, // 61 - 0x00, 0x60, 0x60, 0x78, 0x6C, 0x6C, 0x78, 0x00, // 62 - 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, // 63 - 0x00, 0x06, 0x06, 0x1E, 0x36, 0x36, 0x1E, 0x00, // 64 - 0x00, 0x00, 0x38, 0x6C, 0x7C, 0x60, 0x38, 0x00, // 65 - 0x00, 0x1E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, // 66 - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x3F, 0x06, 0x3C, // 67 - 0x00, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x00, // 68 - 0x00, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, // 69 - 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x30, // 6A - 0x00, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, // 6B - 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x00, // 6C - 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x63, 0x63, 0x00, // 6D - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, // 6E - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 6F - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, // 70 - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x06, // 71 - 0x00, 0x00, 0x36, 0x38, 0x30, 0x30, 0x30, 0x00, // 72 - 0x00, 0x00, 0x1C, 0x30, 0x1C, 0x06, 0x3C, 0x00, // 73 - 0x00, 0x18, 0x18, 0x3C, 0x18, 0x18, 0x0C, 0x00, // 74 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 75 - 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x00, // 76 - 0x00, 0x00, 0x63, 0x63, 0x6B, 0x7F, 0x36, 0x00, // 77 - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // 78 - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x30, 0x60, 0x00, // 79 - 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, // 7A - 0x66, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3B, 0x00, // 7B - 0x66, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 7C - 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 7D - 0x00, 0x38, 0x6C, 0x78, 0x6C, 0x78, 0x60, 0x60, // 7E - 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, // 7F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x00, // 80 - 0xFF, 0xFF, 0xDD, 0x8D, 0xDD, 0xC1, 0xFF, 0xFF, // 81 - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCD, 0xED, 0xFF, // 82 - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x46, 0x7E, // 83 - 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, // 84 - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // 85 - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, // 86 - 0xFF, 0xFF, 0xC3, 0xBD, 0xBD, 0x81, 0xFF, 0xFF, // 87 - 0xFF, 0xEF, 0xCF, 0x81, 0xCF, 0xEF, 0xFF, 0xFF, // 88 - 0xFF, 0xF7, 0xF3, 0x81, 0xF3, 0xF7, 0xFF, 0xFF, // 89 - 0xFF, 0xEF, 0xEF, 0xEF, 0x83, 0xC7, 0xEF, 0xFF, // 8A - 0xF7, 0xE3, 0xC1, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // 8B - 0xC7, 0xCF, 0xD7, 0xF7, 0xF7, 0xF7, 0xC1, 0xFF, // 8C - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCF, 0xEF, 0xFF, // 8D - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 8E - 0xC1, 0x83, 0x83, 0xC1, 0xC1, 0x83, 0x07, 0x07, // 8F - 0xC7, 0xCF, 0xD7, 0xFB, 0xFB, 0xFB, 0xFB, 0xFF, // 90 - 0x80, 0xF7, 0xE3, 0xD5, 0xF7, 0xF7, 0xF7, 0xFF, // 91 - 0xFF, 0xF7, 0xF7, 0xF7, 0xD5, 0xE3, 0xF7, 0x80, // 92 - 0x81, 0x7E, 0x62, 0x5E, 0x46, 0x7A, 0x7A, 0x46, // 93 - 0xFF, 0xC3, 0xBD, 0xA5, 0xA5, 0xBD, 0xC3, 0xFF, // 94 - 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE, // 95 - 0xFF, 0x80, 0xDD, 0x8D, 0xD8, 0xDD, 0x80, 0xFF, // 96 - 0xEE, 0xDD, 0xBB, 0x77, 0xEE, 0xDD, 0xBB, 0x77, // 97 - 0xFF, 0xFE, 0xF6, 0xF2, 0x80, 0xF2, 0xF6, 0xFE, // 98 - 0xFF, 0x6F, 0x4F, 0x01, 0x4F, 0x6F, 0xFF, 0xFF, // 99 - 0xFF, 0xF7, 0x83, 0xF9, 0x83, 0xF7, 0xFF, 0xFF, // 9A - 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // 9B - 0x81, 0x7E, 0x5E, 0x5E, 0x5E, 0x5E, 0x42, 0x7E, // 9C - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x5A, 0x7E, // 9D - 0x81, 0x7E, 0x66, 0x5E, 0x5E, 0x5E, 0x66, 0x7E, // 9E - 0xFF, 0xEF, 0xC1, 0x9F, 0xC1, 0xEF, 0xFF, 0xFF, // 9F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0 - 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xE7, 0xFF, // A1 - 0xFF, 0x99, 0x99, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xFF, 0xC9, 0x80, 0xC9, 0xC9, 0x80, 0xC9, 0xFF, // A3 - 0xE7, 0xC1, 0x93, 0xC1, 0xE4, 0xE4, 0x81, 0xE7, // A4 - 0xFF, 0x9C, 0x99, 0xF3, 0xE7, 0xC9, 0x99, 0xFF, // A5 - 0xE7, 0xDB, 0xD7, 0xEE, 0xD5, 0xBB, 0xB5, 0xCE, // A6 - 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, // A7 - 0xFF, 0xE7, 0xCF, 0xCF, 0xCF, 0xCF, 0xE7, 0xFF, // A8 - 0xFF, 0xE7, 0xF3, 0xF3, 0xF3, 0xF3, 0xE7, 0xFF, // A9 - 0xFF, 0xFF, 0xDB, 0xE7, 0x81, 0xE7, 0xDB, 0xFF, // AA - 0xFF, 0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, // AB - 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, // AC - 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, // AD - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, // AE - 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F, 0xFF, 0xFF, // AF - 0xFF, 0xC3, 0x91, 0x91, 0x89, 0x89, 0xC3, 0xFF, // B0 - 0xFF, 0xE3, 0xC3, 0xF3, 0xF3, 0xF3, 0xC1, 0xFF, // B1 - 0xFF, 0xC3, 0x99, 0xF9, 0xC3, 0x9F, 0x81, 0xFF, // B2 - 0xFF, 0xC3, 0x99, 0xF3, 0xF9, 0x99, 0xC3, 0xFF, // B3 - 0xFF, 0xC3, 0x93, 0x33, 0x01, 0xF3, 0xF3, 0xFF, // B4 - 0xFF, 0x81, 0x9F, 0x83, 0xF9, 0x99, 0xC3, 0xFF, // B5 - 0xFF, 0xC3, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF, // B6 - 0xFF, 0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, // B7 - 0xFF, 0xC3, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF, // B8 - 0xFF, 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xC3, 0xFF, // B9 - 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xE7, 0xE7, 0xFF, // BA - 0xFF, 0xFF, 0xE7, 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, // BB - 0xFF, 0xFF, 0xE7, 0xCF, 0x9F, 0xCF, 0xE7, 0xFF, // BC - 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xFF, // BD - 0xFF, 0xFF, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0xFF, // BE - 0xFF, 0xC3, 0x99, 0xF9, 0xE3, 0xE7, 0xFF, 0xE7, // BF - 0xC3, 0xBD, 0x7E, 0xCA, 0xB6, 0xB6, 0xB6, 0xC9, // C0 - 0xFF, 0xC3, 0x99, 0x99, 0x81, 0x99, 0x99, 0xFF, // C1 - 0xFF, 0x83, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF, // C2 - 0xFF, 0xC3, 0x99, 0x9F, 0x9F, 0x99, 0xC3, 0xFF, // C3 - 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0x83, 0xFF, // C4 - 0xFF, 0x81, 0x9F, 0x83, 0x9F, 0x9F, 0x81, 0xFF, // C5 - 0xFF, 0x81, 0x9F, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, // C6 - 0xFF, 0xC3, 0x99, 0x9F, 0x91, 0x99, 0xC3, 0xFF, // C7 - 0xFF, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, // C8 - 0xFF, 0xC3, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, // C9 - 0xFF, 0xE1, 0xF3, 0xF3, 0xF3, 0x93, 0xC7, 0xFF, // CA - 0xFF, 0x99, 0x93, 0x87, 0x93, 0x99, 0x9C, 0xFF, // CB - 0xFF, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF, // CC - 0xFF, 0x9C, 0x88, 0x94, 0x9C, 0x9C, 0x9C, 0xFF, // CD - 0xFF, 0x9C, 0x8C, 0x94, 0x98, 0x9C, 0x9C, 0xFF, // CE - 0xFF, 0xC3, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // CF - 0xFF, 0x83, 0x99, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, // D0 - 0xFF, 0xC3, 0x99, 0x99, 0x91, 0x99, 0xC5, 0xFE, // D1 - 0xFF, 0x83, 0x99, 0x83, 0x93, 0x99, 0x9C, 0xFF, // D2 - 0xFF, 0xC3, 0x9F, 0xC3, 0xF9, 0x99, 0xC3, 0xFF, // D3 - 0xFF, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // D4 - 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // D5 - 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, // D6 - 0xFF, 0x9C, 0x9C, 0x94, 0x94, 0x80, 0xC9, 0xFF, // D7 - 0xFF, 0x99, 0xC3, 0xE7, 0xE7, 0xC3, 0x99, 0xFF, // D8 - 0xFF, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // D9 - 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x9F, 0x81, 0xFF, // DA - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DB - 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // DC - 0xFF, 0x81, 0xF9, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, // DD - 0xFF, 0xFF, 0xFF, 0xF7, 0xE3, 0xC9, 0xFF, 0xFF, // DE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, // DF - 0x81, 0x7E, 0x66, 0x5E, 0x5E, 0x66, 0x7E, 0x81, // E0 - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC4, 0xFF, // E1 - 0xFF, 0x9F, 0x9F, 0x87, 0x93, 0x93, 0x87, 0xFF, // E2 - 0xFF, 0xFF, 0xC3, 0x99, 0x9F, 0x99, 0xC3, 0xFF, // E3 - 0xFF, 0xF9, 0xF9, 0xE1, 0xC9, 0xC9, 0xE1, 0xFF, // E4 - 0xFF, 0xFF, 0xC7, 0x93, 0x83, 0x9F, 0xC7, 0xFF, // E5 - 0xFF, 0xE1, 0xE7, 0x81, 0xE7, 0xE7, 0xE7, 0xFF, // E6 - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0xC0, 0xF9, 0xC3, // E7 - 0xFF, 0x9F, 0x9F, 0x93, 0x89, 0x99, 0x99, 0xFF, // E8 - 0xFF, 0xE7, 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // E9 - 0xFF, 0xE7, 0xFF, 0xC7, 0xE7, 0xE7, 0xE7, 0xCF, // EA - 0xFF, 0x9F, 0x99, 0x93, 0x87, 0x93, 0x99, 0xFF, // EB - 0xFF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xE7, 0xFF, // EC - 0xFF, 0xFF, 0xC9, 0x80, 0x94, 0x9C, 0x9C, 0xFF, // ED - 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF, // EE - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF, // EF - 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F, // F0 - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xF9, // F1 - 0xFF, 0xFF, 0xC9, 0xC7, 0xCF, 0xCF, 0xCF, 0xFF, // F2 - 0xFF, 0xFF, 0xE3, 0xCF, 0xE3, 0xF9, 0xC3, 0xFF, // F3 - 0xFF, 0xE7, 0xE7, 0xC3, 0xE7, 0xE7, 0xF3, 0xFF, // F4 - 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // F5 - 0xFF, 0xFF, 0x99, 0x99, 0xC3, 0xC3, 0xE7, 0xFF, // F6 - 0xFF, 0xFF, 0x9C, 0x9C, 0x94, 0x80, 0xC9, 0xFF, // F7 - 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0xFF, // F8 - 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xCF, 0x9F, 0xFF, // F9 - 0xFF, 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x81, 0xFF, // FA - 0x99, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC4, 0xFF, // FB - 0x99, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF, // FC - 0x99, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // FD - 0xFF, 0xC7, 0x93, 0x87, 0x93, 0x87, 0x9F, 0x9F, // FE - 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // FF -}; -static const uint8_t _sdtx_font_kc854[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFF, // 00 - 0x00, 0x00, 0x22, 0x72, 0x22, 0x3E, 0x00, 0x00, // 01 - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x32, 0x12, 0x00, // 02 - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xB9, 0x81, // 03 - 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 04 - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 05 - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, // 06 - 0x00, 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x00, 0x00, // 07 - 0x00, 0x10, 0x30, 0x7E, 0x30, 0x10, 0x00, 0x00, // 08 - 0x00, 0x08, 0x0C, 0x7E, 0x0C, 0x08, 0x00, 0x00, // 09 - 0x00, 0x10, 0x10, 0x10, 0x7C, 0x38, 0x10, 0x00, // 0A - 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00, // 0B - 0x38, 0x30, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, // 0C - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x30, 0x10, 0x00, // 0D - 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // 0E - 0x3E, 0x7C, 0x7C, 0x3E, 0x3E, 0x7C, 0xF8, 0xF8, // 0F - 0x38, 0x30, 0x28, 0x04, 0x04, 0x04, 0x04, 0x00, // 10 - 0x7F, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x00, // 11 - 0x00, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x7F, // 12 - 0x7E, 0x81, 0x9D, 0xA1, 0xB9, 0x85, 0x85, 0xB9, // 13 - 0x00, 0x3C, 0x42, 0x5A, 0x5A, 0x42, 0x3C, 0x00, // 14 - 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, // 15 - 0x00, 0x7F, 0x22, 0x72, 0x27, 0x22, 0x7F, 0x00, // 16 - 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, // 17 - 0x00, 0x01, 0x09, 0x0D, 0x7F, 0x0D, 0x09, 0x01, // 18 - 0x00, 0x90, 0xB0, 0xFE, 0xB0, 0x90, 0x00, 0x00, // 19 - 0x00, 0x08, 0x7C, 0x06, 0x7C, 0x08, 0x00, 0x00, // 1A - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // 1B - 0x7E, 0x81, 0xA1, 0xA1, 0xA1, 0xA1, 0xBD, 0x81, // 1C - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xA5, 0x81, // 1D - 0x7E, 0x81, 0x99, 0xA1, 0xA1, 0xA1, 0x99, 0x81, // 1E - 0x00, 0x10, 0x3E, 0x60, 0x3E, 0x10, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00, // 21 - 0x77, 0x33, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x36, 0x36, 0xFE, 0x6C, 0xFE, 0xD8, 0xD8, 0x00, // 23 - 0x18, 0x3E, 0x6C, 0x3E, 0x1B, 0x1B, 0x7E, 0x18, // 24 - 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, // 25 - 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, // 26 - 0x1C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, // 28 - 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, // 29 - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // 2A - 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x18, // 2C - 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, // 2E - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, // 2F - 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 30 - 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, // 31 - 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, // 32 - 0xFC, 0x18, 0x30, 0x78, 0x0C, 0xCC, 0x78, 0x00, // 33 - 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, // 34 - 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, // 35 - 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, // 36 - 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, // 37 - 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, // 38 - 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, // 39 - 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, // 3A - 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, // 3B - 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, // 3C - 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, // 3D - 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, // 3E - 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, // 3F - 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 40 - 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, // 41 - 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, // 42 - 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, // 43 - 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, // 44 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, // 45 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, // 46 - 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3C, 0x00, // 47 - 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, // 48 - 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, // 49 - 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, // 4A - 0xE6, 0x66, 0x6C, 0x70, 0x6C, 0x66, 0xE6, 0x00, // 4B - 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, // 4C - 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, // 4D - 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, // 4E - 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, // 4F - 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 50 - 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00, // 51 - 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, // 52 - 0x7C, 0xC6, 0xF0, 0x3C, 0x0E, 0xC6, 0x7C, 0x00, // 53 - 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, // 54 - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, // 55 - 0xCC, 0xCC, 0xCC, 0x78, 0x78, 0x30, 0x30, 0x00, // 56 - 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, // 57 - 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, // 58 - 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, // 59 - 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, // 5A - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5B - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 5C - 0x00, 0xFE, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, // 5D - 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 5F - 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C, // 60 - 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, // 61 - 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0xDC, 0x00, // 62 - 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, // 63 - 0x1C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 64 - 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, // 65 - 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00, // 66 - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, // 67 - 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, // 68 - 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0xFC, 0x00, // 69 - 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, // 6A - 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, // 6B - 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, // 6C - 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // 6D - 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, // 6E - 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, // 6F - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 70 - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, // 71 - 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00, // 72 - 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00, // 73 - 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00, // 74 - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 75 - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, // 76 - 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00, // 77 - 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, // 78 - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, // 79 - 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, // 7A - 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, // 7B - 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, // 7C - 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 7D - 0x3C, 0x66, 0x66, 0x6C, 0x66, 0x66, 0x6C, 0xF0, // 7E - 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, // 7F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x00, // 80 - 0xFF, 0xFF, 0xDD, 0x8D, 0xDD, 0xC1, 0xFF, 0xFF, // 81 - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCD, 0xED, 0xFF, // 82 - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x46, 0x7E, // 83 - 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, // 84 - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // 85 - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, // 86 - 0xFF, 0xFF, 0xC3, 0xBD, 0xBD, 0x81, 0xFF, 0xFF, // 87 - 0xFF, 0xEF, 0xCF, 0x81, 0xCF, 0xEF, 0xFF, 0xFF, // 88 - 0xFF, 0xF7, 0xF3, 0x81, 0xF3, 0xF7, 0xFF, 0xFF, // 89 - 0xFF, 0xEF, 0xEF, 0xEF, 0x83, 0xC7, 0xEF, 0xFF, // 8A - 0xF7, 0xE3, 0xC1, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // 8B - 0xC7, 0xCF, 0xD7, 0xF7, 0xF7, 0xF7, 0xC1, 0xFF, // 8C - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCF, 0xEF, 0xFF, // 8D - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 8E - 0xC1, 0x83, 0x83, 0xC1, 0xC1, 0x83, 0x07, 0x07, // 8F - 0xC7, 0xCF, 0xD7, 0xFB, 0xFB, 0xFB, 0xFB, 0xFF, // 90 - 0x80, 0xF7, 0xE3, 0xD5, 0xF7, 0xF7, 0xF7, 0xFF, // 91 - 0xFF, 0xF7, 0xF7, 0xF7, 0xD5, 0xE3, 0xF7, 0x80, // 92 - 0x81, 0x7E, 0x62, 0x5E, 0x46, 0x7A, 0x7A, 0x46, // 93 - 0xFF, 0xC3, 0xBD, 0xA5, 0xA5, 0xBD, 0xC3, 0xFF, // 94 - 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE, // 95 - 0xFF, 0x80, 0xDD, 0x8D, 0xD8, 0xDD, 0x80, 0xFF, // 96 - 0xEE, 0xDD, 0xBB, 0x77, 0xEE, 0xDD, 0xBB, 0x77, // 97 - 0xFF, 0xFE, 0xF6, 0xF2, 0x80, 0xF2, 0xF6, 0xFE, // 98 - 0xFF, 0x6F, 0x4F, 0x01, 0x4F, 0x6F, 0xFF, 0xFF, // 99 - 0xFF, 0xF7, 0x83, 0xF9, 0x83, 0xF7, 0xFF, 0xFF, // 9A - 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // 9B - 0x81, 0x7E, 0x5E, 0x5E, 0x5E, 0x5E, 0x42, 0x7E, // 9C - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x5A, 0x7E, // 9D - 0x81, 0x7E, 0x66, 0x5E, 0x5E, 0x5E, 0x66, 0x7E, // 9E - 0xFF, 0xEF, 0xC1, 0x9F, 0xC1, 0xEF, 0xFF, 0xFF, // 9F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0 - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xFF, 0xCF, 0xFF, // A1 - 0x88, 0xCC, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xC9, 0xC9, 0x01, 0x93, 0x01, 0x27, 0x27, 0xFF, // A3 - 0xE7, 0xC1, 0x93, 0xC1, 0xE4, 0xE4, 0x81, 0xE7, // A4 - 0xFF, 0x39, 0x33, 0xE7, 0xCF, 0x99, 0x39, 0xFF, // A5 - 0xC7, 0x93, 0xC7, 0x89, 0x23, 0x33, 0x89, 0xFF, // A6 - 0xE3, 0xF3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A7 - 0xE7, 0xCF, 0x9F, 0x9F, 0x9F, 0xCF, 0xE7, 0xFF, // A8 - 0x9F, 0xCF, 0xE7, 0xE7, 0xE7, 0xCF, 0x9F, 0xFF, // A9 - 0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF, // AA - 0xFF, 0xCF, 0xCF, 0x03, 0xCF, 0xCF, 0xFF, 0xFF, // AB - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xF3, 0xE7, // AC - 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, // AD - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xCF, 0xFF, // AE - 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F, 0x7F, 0xFF, // AF - 0x83, 0x39, 0x31, 0x21, 0x09, 0x19, 0x83, 0xFF, // B0 - 0xCF, 0x8F, 0xCF, 0xCF, 0xCF, 0xCF, 0x03, 0xFF, // B1 - 0x87, 0x33, 0xF3, 0xC7, 0x9F, 0x33, 0x03, 0xFF, // B2 - 0x03, 0xE7, 0xCF, 0x87, 0xF3, 0x33, 0x87, 0xFF, // B3 - 0xE3, 0xC3, 0x93, 0x33, 0x01, 0xF3, 0xE1, 0xFF, // B4 - 0x03, 0x3F, 0x07, 0xF3, 0xF3, 0x33, 0x87, 0xFF, // B5 - 0xC7, 0x9F, 0x3F, 0x07, 0x33, 0x33, 0x87, 0xFF, // B6 - 0x03, 0x33, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xFF, // B7 - 0x87, 0x33, 0x33, 0x87, 0x33, 0x33, 0x87, 0xFF, // B8 - 0x87, 0x33, 0x33, 0x83, 0xF3, 0xE7, 0x8F, 0xFF, // B9 - 0xFF, 0xFF, 0xCF, 0xCF, 0xFF, 0xCF, 0xCF, 0xFF, // BA - 0xFF, 0xFF, 0xCF, 0xCF, 0xFF, 0xCF, 0xCF, 0x9F, // BB - 0xE7, 0xCF, 0x9F, 0x3F, 0x9F, 0xCF, 0xE7, 0xFF, // BC - 0xFF, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, // BD - 0x9F, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, // BE - 0x87, 0x33, 0xF3, 0xE7, 0xCF, 0xFF, 0xCF, 0xFF, // BF - 0x83, 0x39, 0x21, 0x21, 0x21, 0x3F, 0x87, 0xFF, // C0 - 0xCF, 0x87, 0x33, 0x33, 0x03, 0x33, 0x33, 0xFF, // C1 - 0x03, 0x99, 0x99, 0x83, 0x99, 0x99, 0x03, 0xFF, // C2 - 0xC3, 0x99, 0x3F, 0x3F, 0x3F, 0x99, 0xC3, 0xFF, // C3 - 0x07, 0x93, 0x99, 0x99, 0x99, 0x93, 0x07, 0xFF, // C4 - 0x01, 0x9D, 0x97, 0x87, 0x97, 0x9D, 0x01, 0xFF, // C5 - 0x01, 0x9D, 0x97, 0x87, 0x97, 0x9F, 0x0F, 0xFF, // C6 - 0xC3, 0x99, 0x3F, 0x3F, 0x31, 0x99, 0xC3, 0xFF, // C7 - 0x33, 0x33, 0x33, 0x03, 0x33, 0x33, 0x33, 0xFF, // C8 - 0x87, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0x87, 0xFF, // C9 - 0xE1, 0xF3, 0xF3, 0xF3, 0x33, 0x33, 0x87, 0xFF, // CA - 0x19, 0x99, 0x93, 0x8F, 0x93, 0x99, 0x19, 0xFF, // CB - 0x0F, 0x9F, 0x9F, 0x9F, 0x9D, 0x99, 0x01, 0xFF, // CC - 0x39, 0x11, 0x01, 0x29, 0x39, 0x39, 0x39, 0xFF, // CD - 0x39, 0x19, 0x09, 0x21, 0x31, 0x39, 0x39, 0xFF, // CE - 0xC7, 0x93, 0x39, 0x39, 0x39, 0x93, 0xC7, 0xFF, // CF - 0x03, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0x0F, 0xFF, // D0 - 0x87, 0x33, 0x33, 0x33, 0x23, 0x87, 0xE3, 0xFF, // D1 - 0x03, 0x99, 0x99, 0x83, 0x93, 0x99, 0x19, 0xFF, // D2 - 0x83, 0x39, 0x0F, 0xC3, 0xF1, 0x39, 0x83, 0xFF, // D3 - 0x03, 0x4B, 0xCF, 0xCF, 0xCF, 0xCF, 0x87, 0xFF, // D4 - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x87, 0xFF, // D5 - 0x33, 0x33, 0x33, 0x87, 0x87, 0xCF, 0xCF, 0xFF, // D6 - 0x39, 0x39, 0x39, 0x29, 0x01, 0x11, 0x39, 0xFF, // D7 - 0x39, 0x39, 0x93, 0xC7, 0x93, 0x39, 0x39, 0xFF, // D8 - 0x33, 0x33, 0x33, 0x87, 0xCF, 0xCF, 0x87, 0xFF, // D9 - 0x01, 0x39, 0x73, 0xE7, 0xCD, 0x99, 0x01, 0xFF, // DA - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DB - 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // DC - 0xFF, 0x01, 0xF9, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, // DD - 0xEF, 0xC7, 0x93, 0x39, 0xFF, 0xFF, 0xFF, 0xFF, // DE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, // DF - 0xC3, 0xBD, 0x66, 0x5E, 0x5E, 0x66, 0xBD, 0xC3, // E0 - 0xFF, 0xFF, 0x87, 0xF3, 0x83, 0x33, 0x89, 0xFF, // E1 - 0x1F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x23, 0xFF, // E2 - 0xFF, 0xFF, 0x87, 0x33, 0x3F, 0x33, 0x87, 0xFF, // E3 - 0xE3, 0xF3, 0x83, 0x33, 0x33, 0x33, 0x89, 0xFF, // E4 - 0xFF, 0xFF, 0x87, 0x33, 0x03, 0x3F, 0x87, 0xFF, // E5 - 0xC7, 0x93, 0x9F, 0x0F, 0x9F, 0x9F, 0x0F, 0xFF, // E6 - 0xFF, 0xFF, 0x89, 0x33, 0x33, 0x83, 0xF3, 0x07, // E7 - 0x1F, 0x9F, 0x93, 0x89, 0x99, 0x99, 0x19, 0xFF, // E8 - 0xCF, 0xFF, 0x8F, 0xCF, 0xCF, 0xCF, 0x03, 0xFF, // E9 - 0xF3, 0xFF, 0xE3, 0xF3, 0xF3, 0x33, 0x33, 0x87, // EA - 0x1F, 0x9F, 0x99, 0x93, 0x87, 0x93, 0x19, 0xFF, // EB - 0x8F, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0x03, 0xFF, // EC - 0xFF, 0xFF, 0x33, 0x01, 0x01, 0x29, 0x39, 0xFF, // ED - 0xFF, 0xFF, 0x07, 0x33, 0x33, 0x33, 0x33, 0xFF, // EE - 0xFF, 0xFF, 0x87, 0x33, 0x33, 0x33, 0x87, 0xFF, // EF - 0xFF, 0xFF, 0x23, 0x99, 0x99, 0x83, 0x9F, 0x0F, // F0 - 0xFF, 0xFF, 0x89, 0x33, 0x33, 0x83, 0xF3, 0xE1, // F1 - 0xFF, 0xFF, 0x23, 0x89, 0x99, 0x9F, 0x0F, 0xFF, // F2 - 0xFF, 0xFF, 0x83, 0x3F, 0x87, 0xF3, 0x07, 0xFF, // F3 - 0xEF, 0xCF, 0x83, 0xCF, 0xCF, 0xCB, 0xE7, 0xFF, // F4 - 0xFF, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x89, 0xFF, // F5 - 0xFF, 0xFF, 0x33, 0x33, 0x33, 0x87, 0xCF, 0xFF, // F6 - 0xFF, 0xFF, 0x39, 0x29, 0x01, 0x01, 0x93, 0xFF, // F7 - 0xFF, 0xFF, 0x39, 0x93, 0xC7, 0x93, 0x39, 0xFF, // F8 - 0xFF, 0xFF, 0x33, 0x33, 0x33, 0x83, 0xF3, 0x07, // F9 - 0xFF, 0xFF, 0x03, 0x67, 0xCF, 0x9B, 0x03, 0xFF, // FA - 0x93, 0xFF, 0x87, 0xF3, 0x83, 0x33, 0x89, 0xFF, // FB - 0x33, 0xFF, 0x87, 0x33, 0x33, 0x33, 0x87, 0xFF, // FC - 0x33, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x89, 0xFF, // FD - 0xC3, 0x99, 0x99, 0x93, 0x99, 0x99, 0x93, 0x0F, // FE - 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // FF -}; -static const uint8_t _sdtx_font_z1013[2048] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 00 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 01 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 02 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 03 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 04 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 05 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 06 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 07 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 08 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 09 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0A - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0B - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0C - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0D - 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x24, 0x42, // 0E - 0xDB, 0xA5, 0x81, 0xFF, 0x24, 0x24, 0x24, 0x42, // 0F - 0x08, 0x34, 0x42, 0x81, 0x91, 0x69, 0x09, 0x31, // 10 - 0x42, 0x7E, 0x81, 0xFF, 0x00, 0x00, 0x00, 0x00, // 11 - 0x18, 0x24, 0x42, 0x99, 0xBD, 0x99, 0x42, 0x24, // 12 - 0x7E, 0x42, 0x99, 0xE7, 0x00, 0x00, 0x00, 0x00, // 13 - 0x18, 0xDB, 0xC3, 0x18, 0x99, 0xE7, 0x81, 0x42, // 14 - 0x18, 0x24, 0x18, 0xC3, 0xBD, 0x81, 0x81, 0x42, // 15 - 0x24, 0x7E, 0x81, 0xFF, 0x00, 0x00, 0x00, 0x00, // 16 - 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x3C, 0x7E, // 17 - 0xDB, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x7E, // 18 - 0x08, 0x3C, 0x7E, 0xFF, 0xFF, 0x6F, 0x0F, 0x3F, // 19 - 0x7E, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 1A - 0x18, 0x3C, 0x7E, 0xE7, 0xC3, 0xE7, 0x7E, 0x3C, // 1B - 0x7E, 0x7E, 0xFF, 0xE7, 0x00, 0x00, 0x00, 0x00, // 1C - 0x18, 0xDB, 0xC3, 0x18, 0x99, 0xFF, 0xFF, 0x7E, // 1D - 0x18, 0x3C, 0x18, 0xC3, 0xFF, 0xFF, 0xFF, 0x7E, // 1E - 0x3C, 0x3C, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x00, // 21 - 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x24, 0x7E, 0x24, 0x24, 0x24, 0x7E, 0x24, 0x00, // 23 - 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, // 24 - 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, // 25 - 0x10, 0x28, 0x28, 0x30, 0x54, 0x48, 0x34, 0x00, // 26 - 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // 28 - 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, // 29 - 0x00, 0x10, 0x54, 0x38, 0x54, 0x10, 0x00, 0x00, // 2A - 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, // 2C - 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, // 2E - 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 2F - 0x38, 0x44, 0x44, 0x54, 0x44, 0x44, 0x38, 0x00, // 30 - 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, // 31 - 0x38, 0x44, 0x04, 0x08, 0x10, 0x20, 0x7C, 0x00, // 32 - 0x7C, 0x08, 0x10, 0x08, 0x04, 0x44, 0x38, 0x00, // 33 - 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, // 34 - 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, // 35 - 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, // 36 - 0x7C, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00, // 37 - 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, // 38 - 0x38, 0x44, 0x44, 0x3C, 0x04, 0x08, 0x30, 0x00, // 39 - 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00, // 3A - 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x20, 0x00, // 3B - 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, // 3C - 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, // 3D - 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, // 3E - 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, // 3F - 0x38, 0x44, 0x5C, 0x54, 0x5C, 0x40, 0x3C, 0x00, // 40 - 0x38, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, // 41 - 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, // 42 - 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, // 43 - 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, // 44 - 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7C, 0x00, // 45 - 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00, // 46 - 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x3C, 0x00, // 47 - 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, // 48 - 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, // 49 - 0x1C, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, 0x00, // 4A - 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, // 4B - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, // 4C - 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, // 4D - 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, // 4E - 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, // 4F - 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, // 50 - 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, // 51 - 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, // 52 - 0x3C, 0x40, 0x40, 0x38, 0x04, 0x04, 0x78, 0x00, // 53 - 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // 54 - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, // 55 - 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, // 56 - 0x44, 0x44, 0x44, 0x54, 0x54, 0x6C, 0x44, 0x00, // 57 - 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, // 58 - 0x44, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, // 59 - 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, // 5A - 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, // 5B - 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, // 5C - 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, // 5D - 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, // 5F - 0x00, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, // 60 - 0x00, 0x00, 0x34, 0x4C, 0x44, 0x44, 0x3A, 0x00, // 61 - 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x78, 0x00, // 62 - 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, // 63 - 0x04, 0x04, 0x34, 0x4C, 0x44, 0x44, 0x3A, 0x00, // 64 - 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, // 65 - 0x08, 0x10, 0x38, 0x10, 0x10, 0x10, 0x10, 0x00, // 66 - 0x00, 0x00, 0x34, 0x4C, 0x44, 0x3C, 0x04, 0x38, // 67 - 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, // 68 - 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, // 69 - 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, // 6A - 0x40, 0x40, 0x48, 0x50, 0x70, 0x48, 0x44, 0x00, // 6B - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, // 6C - 0x00, 0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x00, // 6D - 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, // 6E - 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, // 6F - 0x00, 0x00, 0x58, 0x64, 0x44, 0x78, 0x40, 0x40, // 70 - 0x00, 0x00, 0x34, 0x4C, 0x44, 0x3C, 0x04, 0x04, // 71 - 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, // 72 - 0x00, 0x00, 0x38, 0x40, 0x38, 0x04, 0x78, 0x00, // 73 - 0x10, 0x10, 0x38, 0x10, 0x10, 0x10, 0x08, 0x00, // 74 - 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, // 75 - 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, // 76 - 0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, // 77 - 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, // 78 - 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, // 79 - 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, // 7A - 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, // 7B - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // 7C - 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, // 7D - 0x00, 0x00, 0x00, 0x32, 0x4C, 0x00, 0x00, 0x00, // 7E - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7F - 0xC0, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0xC0, // 80 - 0x03, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x03, // 81 - 0x81, 0x81, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00, // 82 - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x81, 0x81, // 83 - 0x10, 0x10, 0x20, 0xC0, 0x00, 0x00, 0x00, 0x00, // 84 - 0x08, 0x08, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, // 85 - 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x08, 0x08, // 86 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x20, 0x10, 0x10, // 87 - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, // 88 - 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 89 - 0x00, 0x10, 0x28, 0x44, 0x82, 0x44, 0x28, 0x10, // 8A - 0xFF, 0xEF, 0xC7, 0x83, 0x01, 0x83, 0xC7, 0xEF, // 8B - 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C, // 8C - 0xC3, 0x81, 0x00, 0x00, 0x00, 0x00, 0x81, 0xC3, // 8D - 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, // 8E - 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, // 8F - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, // 90 - 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, // 91 - 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x30, 0xC0, // 92 - 0x03, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, // 93 - 0x03, 0x0C, 0x30, 0xC0, 0xC0, 0x30, 0x0C, 0x03, // 94 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x03, // 95 - 0xC0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, // 96 - 0xC0, 0x30, 0x0C, 0x03, 0x03, 0x0C, 0x30, 0xC0, // 97 - 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, // 98 - 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, // 99 - 0x81, 0x81, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18, // 9A - 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, // 9B - 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, // 9C - 0x18, 0x18, 0x24, 0x24, 0x42, 0x42, 0x81, 0x81, // 9D - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9E - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 9F - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // A0 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // A1 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // A2 - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // A3 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // A4 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // A5 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, // A6 - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, // A7 - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, // A8 - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, // A9 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, // AA - 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x18, 0x07, // AB - 0x01, 0x01, 0x01, 0x02, 0x02, 0x04, 0x18, 0xE0, // AC - 0xE0, 0x18, 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, // AD - 0x07, 0x18, 0x20, 0x40, 0x40, 0x80, 0x80, 0x80, // AE - 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81, // AF - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // B0 - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // B1 - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // B2 - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // B3 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // B4 - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // B5 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // B6 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // B7 - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // B8 - 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // B9 - 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, // BA - 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // BB - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, // BC - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, // BD - 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, // BE - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // BF - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // C0 - 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C1 - 0xFF, 0x80, 0x80, 0x9C, 0x9C, 0x9C, 0x80, 0x80, // C2 - 0xFF, 0xFF, 0xFF, 0xE3, 0xE3, 0xE3, 0xFF, 0xFF, // C3 - 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x3C, 0x7E, 0xFF, // C4 - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, // C5 - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // C6 - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, // C7 - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, // C8 - 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, // C9 - 0x38, 0x10, 0x92, 0xFE, 0x92, 0x10, 0x38, 0x7C, // CA - 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, // CB - 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x7C, 0x10, 0x7C, // CC - 0xE7, 0xE7, 0x42, 0xFF, 0xFF, 0x42, 0xE7, 0xE7, // CD - 0xDB, 0xFF, 0xDB, 0x18, 0x18, 0xDB, 0xFF, 0xDB, // CE - 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, // CF - 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D0 - 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D1 - 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D2 - 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D3 - 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, // D4 - 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, // D5 - 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, // D6 - 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, // D7 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, // D8 - 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, // D9 - 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, // DA - 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, // DB - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, // DC - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, // DD - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, // DE - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, // DF - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, // E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, // E1 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // E2 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, // E3 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, // E4 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, // E5 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, // E6 - 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // E7 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // E8 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, // E9 - 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, // EA - 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EB - 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EC - 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ED - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EE - 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EF - 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F0 - 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F1 - 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, // F2 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, // F3 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // F4 - 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // F5 - 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, // F6 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, // F7 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // F8 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // F9 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // FA - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // FB - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FC - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FD - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FF -}; -static const uint8_t _sdtx_font_cpc[2048] = { - 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, // 00 - 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 01 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, // 02 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, // 03 - 0x0C, 0x18, 0x30, 0x7E, 0x0C, 0x18, 0x30, 0x00, // 04 - 0xFF, 0xC3, 0xE7, 0xDB, 0xDB, 0xE7, 0xC3, 0xFF, // 05 - 0x00, 0x01, 0x03, 0x06, 0xCC, 0x78, 0x30, 0x00, // 06 - 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0x24, 0xE7, 0x00, // 07 - 0x00, 0x00, 0x30, 0x60, 0xFF, 0x60, 0x30, 0x00, // 08 - 0x00, 0x00, 0x0C, 0x06, 0xFF, 0x06, 0x0C, 0x00, // 09 - 0x18, 0x18, 0x18, 0x18, 0xDB, 0x7E, 0x3C, 0x18, // 0A - 0x18, 0x3C, 0x7E, 0xDB, 0x18, 0x18, 0x18, 0x18, // 0B - 0x18, 0x5A, 0x3C, 0x99, 0xDB, 0x7E, 0x3C, 0x18, // 0C - 0x00, 0x03, 0x33, 0x63, 0xFE, 0x60, 0x30, 0x00, // 0D - 0x3C, 0x66, 0xFF, 0xDB, 0xDB, 0xFF, 0x66, 0x3C, // 0E - 0x3C, 0x66, 0xC3, 0xDB, 0xDB, 0xC3, 0x66, 0x3C, // 0F - 0xFF, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, // 10 - 0x3C, 0x7E, 0xDB, 0xDB, 0xDF, 0xC3, 0x66, 0x3C, // 11 - 0x3C, 0x66, 0xC3, 0xDF, 0xDB, 0xDB, 0x7E, 0x3C, // 12 - 0x3C, 0x66, 0xC3, 0xFB, 0xDB, 0xDB, 0x7E, 0x3C, // 13 - 0x3C, 0x7E, 0xDB, 0xDB, 0xFB, 0xC3, 0x66, 0x3C, // 14 - 0x00, 0x01, 0x33, 0x1E, 0xCE, 0x7B, 0x31, 0x00, // 15 - 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xE7, // 16 - 0x03, 0x03, 0x03, 0xFF, 0x03, 0x03, 0x03, 0x00, // 17 - 0xFF, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0xFF, // 18 - 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x3C, 0x18, 0x18, // 19 - 0x3C, 0x66, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // 1A - 0x3C, 0x66, 0xC3, 0xFF, 0xC3, 0xC3, 0x66, 0x3C, // 1B - 0xFF, 0xDB, 0xDB, 0xDB, 0xFB, 0xC3, 0xC3, 0xFF, // 1C - 0xFF, 0xC3, 0xC3, 0xFB, 0xDB, 0xDB, 0xDB, 0xFF, // 1D - 0xFF, 0xC3, 0xC3, 0xDF, 0xDB, 0xDB, 0xDB, 0xFF, // 1E - 0xFF, 0xDB, 0xDB, 0xDB, 0xDF, 0xC3, 0xC3, 0xFF, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, // 21 - 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, // 23 - 0x18, 0x3E, 0x58, 0x3C, 0x1A, 0x7C, 0x18, 0x00, // 24 - 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, // 25 - 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, // 26 - 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, // 28 - 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, // 29 - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // 2A - 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, // 2C - 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // 2E - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, // 2F - 0x7C, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0x7C, 0x00, // 30 - 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, // 31 - 0x3C, 0x66, 0x06, 0x3C, 0x60, 0x66, 0x7E, 0x00, // 32 - 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, // 33 - 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, // 34 - 0x7E, 0x62, 0x60, 0x7C, 0x06, 0x66, 0x3C, 0x00, // 35 - 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 36 - 0x7E, 0x66, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x00, // 37 - 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 38 - 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, // 39 - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, // 3A - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, // 3B - 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, // 3C - 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, // 3D - 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, // 3E - 0x3C, 0x66, 0x66, 0x0C, 0x18, 0x00, 0x18, 0x00, // 3F - 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x7C, 0x00, // 40 - 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 41 - 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, // 42 - 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, // 43 - 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, // 44 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, // 45 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, // 46 - 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00, // 47 - 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 48 - 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, // 49 - 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, // 4A - 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, // 4B - 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, // 4C - 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, // 4D - 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, // 4E - 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, // 4F - 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 50 - 0x38, 0x6C, 0xC6, 0xC6, 0xDA, 0xCC, 0x76, 0x00, // 51 - 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, // 52 - 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // 53 - 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 54 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 55 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 56 - 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, // 57 - 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0xC6, 0x00, // 58 - 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, // 59 - 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, // 5A - 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, // 5B - 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, // 5C - 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, // 5D - 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 5F - 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, // 60 - 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, // 61 - 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0xDC, 0x00, // 62 - 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, // 63 - 0x1C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 64 - 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, // 65 - 0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, // 66 - 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 67 - 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, // 68 - 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, // 69 - 0x06, 0x00, 0x0E, 0x06, 0x06, 0x66, 0x66, 0x3C, // 6A - 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, // 6B - 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 6C - 0x00, 0x00, 0x6C, 0xFE, 0xD6, 0xD6, 0xC6, 0x00, // 6D - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00, // 6E - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 6F - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 70 - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, // 71 - 0x00, 0x00, 0xDC, 0x76, 0x60, 0x60, 0xF0, 0x00, // 72 - 0x00, 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x7C, 0x00, // 73 - 0x30, 0x30, 0x7C, 0x30, 0x30, 0x36, 0x1C, 0x00, // 74 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, // 75 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 76 - 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, // 77 - 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, // 78 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 79 - 0x00, 0x00, 0x7E, 0x4C, 0x18, 0x32, 0x7E, 0x00, // 7A - 0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00, // 7B - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 7C - 0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00, // 7D - 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7E - 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, // 7F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // 81 - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // 82 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 83 - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // 84 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 85 - 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // 86 - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, // 87 - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // 88 - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // 89 - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 8A - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, // 8B - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 8C - 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // 8D - 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, // 8E - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8F - 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, // 90 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, // 91 - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x00, // 92 - 0x18, 0x18, 0x18, 0x1F, 0x0F, 0x00, 0x00, 0x00, // 93 - 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, // 94 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 95 - 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x18, 0x18, 0x18, // 96 - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // 97 - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, // 98 - 0x18, 0x18, 0x18, 0xF8, 0xF0, 0x00, 0x00, 0x00, // 99 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 9A - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 9B - 0x00, 0x00, 0x00, 0xF0, 0xF8, 0x18, 0x18, 0x18, // 9C - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // 9D - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 9E - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 9F - 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, // A0 - 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // A1 - 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A2 - 0x3C, 0x66, 0x60, 0xF8, 0x60, 0x66, 0xFE, 0x00, // A3 - 0x38, 0x44, 0xBA, 0xA2, 0xBA, 0x44, 0x38, 0x00, // A4 - 0x7E, 0xF4, 0xF4, 0x74, 0x34, 0x34, 0x34, 0x00, // A5 - 0x1E, 0x30, 0x38, 0x6C, 0x38, 0x18, 0xF0, 0x00, // A6 - 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, // A7 - 0x40, 0xC0, 0x44, 0x4C, 0x54, 0x1E, 0x04, 0x00, // A8 - 0x40, 0xC0, 0x4C, 0x52, 0x44, 0x08, 0x1E, 0x00, // A9 - 0xE0, 0x10, 0x62, 0x16, 0xEA, 0x0F, 0x02, 0x00, // AA - 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x7E, 0x00, // AB - 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, // AC - 0x00, 0x00, 0x00, 0x7E, 0x06, 0x06, 0x00, 0x00, // AD - 0x18, 0x00, 0x18, 0x30, 0x66, 0x66, 0x3C, 0x00, // AE - 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // AF - 0x00, 0x00, 0x73, 0xDE, 0xCC, 0xDE, 0x73, 0x00, // B0 - 0x7C, 0xC6, 0xC6, 0xFC, 0xC6, 0xC6, 0xF8, 0xC0, // B1 - 0x00, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // B2 - 0x3C, 0x60, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00, // B3 - 0x00, 0x00, 0x1E, 0x30, 0x7C, 0x30, 0x1E, 0x00, // B4 - 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00, // B5 - 0x00, 0xC0, 0x60, 0x30, 0x38, 0x6C, 0xC6, 0x00, // B6 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, // B7 - 0x00, 0x00, 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x00, // B8 - 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0x70, 0x00, // B9 - 0x03, 0x06, 0x0C, 0x3C, 0x66, 0x3C, 0x60, 0xC0, // BA - 0x03, 0x06, 0x0C, 0x66, 0x66, 0x3C, 0x60, 0xC0, // BB - 0x00, 0xE6, 0x3C, 0x18, 0x38, 0x6C, 0xC7, 0x00, // BC - 0x00, 0x00, 0x66, 0xC3, 0xDB, 0xDB, 0x7E, 0x00, // BD - 0xFE, 0xC6, 0x60, 0x30, 0x60, 0xC6, 0xFE, 0x00, // BE - 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x6C, 0xEE, 0x00, // BF - 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, // C0 - 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, // C1 - 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18, // C2 - 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, // C3 - 0x18, 0x3C, 0x66, 0xC3, 0x81, 0x00, 0x00, 0x00, // C4 - 0x18, 0x0C, 0x06, 0x03, 0x03, 0x06, 0x0C, 0x18, // C5 - 0x00, 0x00, 0x00, 0x81, 0xC3, 0x66, 0x3C, 0x18, // C6 - 0x18, 0x30, 0x60, 0xC0, 0xC0, 0x60, 0x30, 0x18, // C7 - 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, // C8 - 0x18, 0x0C, 0x06, 0x83, 0xC1, 0x60, 0x30, 0x18, // C9 - 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0x66, 0x3C, 0x18, // CA - 0xC3, 0xE7, 0x7E, 0x3C, 0x3C, 0x7E, 0xE7, 0xC3, // CB - 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xC0, // CC - 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, // CD - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // CE - 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // CF - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D0 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // D1 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // D2 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // D3 - 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, // D4 - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // D5 - 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, // D6 - 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, // D7 - 0xAA, 0x55, 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, // D8 - 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, // D9 - 0x00, 0x00, 0x00, 0x00, 0xAA, 0x55, 0xAA, 0x55, // DA - 0xA0, 0x50, 0xA0, 0x50, 0xA0, 0x50, 0xA0, 0x50, // DB - 0xAA, 0x54, 0xA8, 0x50, 0xA0, 0x40, 0x80, 0x00, // DC - 0xAA, 0x55, 0x2A, 0x15, 0x0A, 0x05, 0x02, 0x01, // DD - 0x01, 0x02, 0x05, 0x0A, 0x15, 0x2A, 0x55, 0xAA, // DE - 0x00, 0x80, 0x40, 0xA0, 0x50, 0xA8, 0x54, 0xAA, // DF - 0x7E, 0xFF, 0x99, 0xFF, 0xBD, 0xC3, 0xFF, 0x7E, // E0 - 0x7E, 0xFF, 0x99, 0xFF, 0xC3, 0xBD, 0xFF, 0x7E, // E1 - 0x38, 0x38, 0xFE, 0xFE, 0xFE, 0x10, 0x38, 0x00, // E2 - 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, // E3 - 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, // E4 - 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x10, 0x38, 0x00, // E5 - 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0x66, 0x3C, 0x00, // E6 - 0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x00, // E7 - 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00, // E8 - 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // E9 - 0x0F, 0x07, 0x0D, 0x78, 0xCC, 0xCC, 0xCC, 0x78, // EA - 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, // EB - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x7C, 0x38, // EC - 0x18, 0x1C, 0x1E, 0x1B, 0x18, 0x78, 0xF8, 0x70, // ED - 0x99, 0x5A, 0x24, 0xC3, 0xC3, 0x24, 0x5A, 0x99, // EE - 0x10, 0x38, 0x38, 0x38, 0x38, 0x38, 0x7C, 0xD6, // EF - 0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18, // F0 - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18, // F1 - 0x10, 0x30, 0x70, 0xFF, 0xFF, 0x70, 0x30, 0x10, // F2 - 0x08, 0x0C, 0x0E, 0xFF, 0xFF, 0x0E, 0x0C, 0x08, // F3 - 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, // F4 - 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, // F5 - 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, // F6 - 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, // F7 - 0x38, 0x38, 0x92, 0x7C, 0x10, 0x28, 0x28, 0x28, // F8 - 0x38, 0x38, 0x10, 0xFE, 0x10, 0x28, 0x44, 0x82, // F9 - 0x38, 0x38, 0x12, 0x7C, 0x90, 0x28, 0x24, 0x22, // FA - 0x38, 0x38, 0x90, 0x7C, 0x12, 0x28, 0x48, 0x88, // FB - 0x00, 0x3C, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, // FC - 0x3C, 0xFF, 0xFF, 0x18, 0x0C, 0x18, 0x30, 0x18, // FD - 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // FE - 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // FF -}; -static const uint8_t _sdtx_font_c64[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 00 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 01 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 02 - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 03 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 04 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 05 - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // 06 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 07 - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0x33, 0x33, // 08 - 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, // 09 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 0A - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // 0B - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // 0C - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, // 0D - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, // 0E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 0F - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, // 10 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 11 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 12 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // 13 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 14 - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, // 15 - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, // 16 - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 17 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // 18 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // 19 - 0x01, 0x03, 0x06, 0x6C, 0x78, 0x70, 0x60, 0x00, // 1A - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // 1B - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // 1C - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, // 1D - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // 1E - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00, // 21 - 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00, // 23 - 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, // 24 - 0x62, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x46, 0x00, // 25 - 0x3C, 0x66, 0x3C, 0x38, 0x67, 0x66, 0x3F, 0x00, // 26 - 0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, // 28 - 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, // 29 - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // 2A - 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, // 2C - 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // 2E - 0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, // 2F - 0x3C, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x3C, 0x00, // 30 - 0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E, 0x00, // 31 - 0x3C, 0x66, 0x06, 0x0C, 0x30, 0x60, 0x7E, 0x00, // 32 - 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, // 33 - 0x06, 0x0E, 0x1E, 0x66, 0x7F, 0x06, 0x06, 0x00, // 34 - 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, // 35 - 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 36 - 0x7E, 0x66, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, // 37 - 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 38 - 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, // 39 - 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, // 3A - 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, // 3B - 0x0E, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0E, 0x00, // 3C - 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, // 3D - 0x70, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x70, 0x00, // 3E - 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00, // 3F - 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, // 40 - 0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 41 - 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, // 42 - 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, // 43 - 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, // 44 - 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00, // 45 - 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, // 46 - 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, // 47 - 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 48 - 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 49 - 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, // 4A - 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, // 4B - 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, // 4C - 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00, // 4D - 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, // 4E - 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 4F - 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, // 50 - 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x0E, 0x00, // 51 - 0x7C, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0x66, 0x00, // 52 - 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // 53 - 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 54 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 55 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 56 - 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, // 57 - 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // 58 - 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // 59 - 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, // 5A - 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, // 5B - 0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00, // 5C - 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, // 5D - 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, // 5E - 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00, // 5F - 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, // 60 - 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, // 61 - 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // 62 - 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00, // 63 - 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // 64 - 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, // 65 - 0x00, 0x0E, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00, // 66 - 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 67 - 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x00, // 68 - 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00, // 69 - 0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3C, // 6A - 0x00, 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x00, // 6B - 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 6C - 0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00, // 6D - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, // 6E - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 6F - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, // 70 - 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, // 71 - 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00, // 72 - 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, // 73 - 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00, // 74 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, // 75 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 76 - 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00, // 77 - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // 78 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78, // 79 - 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, // 7A - 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, // 7B - 0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00, // 7C - 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, // 7D - 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, // 7E - 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00, // 7F - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 80 - 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x1C, 0x3E, 0x00, // 81 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 82 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 83 - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 84 - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // 85 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, // 86 - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 87 - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, // 88 - 0x00, 0x00, 0x00, 0xE0, 0xF0, 0x38, 0x18, 0x18, // 89 - 0x18, 0x18, 0x1C, 0x0F, 0x07, 0x00, 0x00, 0x00, // 8A - 0x18, 0x18, 0x38, 0xF0, 0xE0, 0x00, 0x00, 0x00, // 8B - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, // 8C - 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, // 8D - 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xC0, // 8E - 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 8F - 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 90 - 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, // 91 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, // 92 - 0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 93 - 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, // 94 - 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1C, 0x18, 0x18, // 95 - 0xC3, 0xE7, 0x7E, 0x3C, 0x3C, 0x7E, 0xE7, 0xC3, // 96 - 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x3C, 0x00, // 97 - 0x18, 0x18, 0x66, 0x66, 0x18, 0x18, 0x3C, 0x00, // 98 - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, // 99 - 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 9A - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 9B - 0xC0, 0xC0, 0x30, 0x30, 0xC0, 0xC0, 0x30, 0x30, // 9C - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 9D - 0x00, 0x00, 0x03, 0x3E, 0x76, 0x36, 0x36, 0x00, // 9E - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // 9F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A0 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // A1 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A3 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // A4 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // A5 - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // A6 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // A7 - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0x33, 0x33, // A8 - 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, // A9 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // AA - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // AB - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // AC - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, // AD - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, // AE - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // AF - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, // B0 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // B1 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // B2 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // B3 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // B4 - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, // B5 - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, // B6 - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B7 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // B8 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // B9 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, // BA - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // BB - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // BC - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, // BD - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // BE - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // BF - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // C0 - 0xF7, 0xE3, 0xC1, 0x80, 0x80, 0xE3, 0xC1, 0xFF, // C1 - 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, // C2 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // C3 - 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // C4 - 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C5 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, // C6 - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, // C7 - 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, // C8 - 0xFF, 0xFF, 0xFF, 0x1F, 0x0F, 0xC7, 0xE7, 0xE7, // C9 - 0xE7, 0xE7, 0xE3, 0xF0, 0xF8, 0xFF, 0xFF, 0xFF, // CA - 0xE7, 0xE7, 0xC7, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, // CB - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, // CC - 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, // CD - 0xFC, 0xF8, 0xF1, 0xE3, 0xC7, 0x8F, 0x1F, 0x3F, // CE - 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // CF - 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // D0 - 0xFF, 0xC3, 0x81, 0x81, 0x81, 0x81, 0xC3, 0xFF, // D1 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, // D2 - 0xC9, 0x80, 0x80, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, // D3 - 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, // D4 - 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xE3, 0xE7, 0xE7, // D5 - 0x3C, 0x18, 0x81, 0xC3, 0xC3, 0x81, 0x18, 0x3C, // D6 - 0xFF, 0xC3, 0x81, 0x99, 0x99, 0x81, 0xC3, 0xFF, // D7 - 0xE7, 0xE7, 0x99, 0x99, 0xE7, 0xE7, 0xC3, 0xFF, // D8 - 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, // D9 - 0xF7, 0xE3, 0xC1, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, // DA - 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xE7, 0xE7, 0xE7, // DB - 0x3F, 0x3F, 0xCF, 0xCF, 0x3F, 0x3F, 0xCF, 0xCF, // DC - 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, // DD - 0xFF, 0xFF, 0xFC, 0xC1, 0x89, 0xC9, 0xC9, 0xFF, // DE - 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, // DF - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // E0 - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // E1 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // E2 - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // E3 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, // E4 - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // E5 - 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // E6 - 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // E7 - 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0x33, 0xCC, 0xCC, // E8 - 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, // E9 - 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // EA - 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, // EB - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, // EC - 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xFF, 0xFF, 0xFF, // ED - 0xFF, 0xFF, 0xFF, 0x07, 0x07, 0xE7, 0xE7, 0xE7, // EE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, // EF - 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, // F0 - 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // F1 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE7, 0xE7, 0xE7, // F2 - 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xE7, 0xE7, 0xE7, // F3 - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // F4 - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, // F5 - 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, // F6 - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // F7 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // F8 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, // F9 - 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, // FA - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, // FB - 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // FC - 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xFF, 0xFF, 0xFF, // FD - 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, // FE - 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // FF -}; -static const uint8_t _sdtx_font_oric[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 00 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 01 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 02 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 03 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 04 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 05 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 06 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 07 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 08 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 09 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 11 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 12 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 13 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 14 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 15 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 17 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 18 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 19 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, // 21 - 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, // 23 - 0x08, 0x1E, 0x28, 0x1C, 0x0A, 0x3C, 0x08, 0x00, // 24 - 0x30, 0x32, 0x04, 0x08, 0x10, 0x26, 0x06, 0x00, // 25 - 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, // 26 - 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // 28 - 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, // 29 - 0x08, 0x2A, 0x1C, 0x08, 0x1C, 0x2A, 0x08, 0x00, // 2A - 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, // 2C - 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // 2E - 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 2F - 0x1C, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x1C, 0x00, // 30 - 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 31 - 0x1C, 0x22, 0x02, 0x04, 0x08, 0x10, 0x3E, 0x00, // 32 - 0x3E, 0x02, 0x04, 0x0C, 0x02, 0x22, 0x1C, 0x00, // 33 - 0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, 0x00, // 34 - 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, // 35 - 0x0C, 0x10, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, // 36 - 0x3E, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x00, // 37 - 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, // 38 - 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x04, 0x18, 0x00, // 39 - 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, // 3A - 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, // 3B - 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, // 3C - 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // 3D - 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, // 3E - 0x1C, 0x22, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, // 3F - 0x1C, 0x22, 0x2A, 0x2E, 0x2C, 0x20, 0x1E, 0x00, // 40 - 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, // 41 - 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, // 42 - 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, // 43 - 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3C, 0x00, // 44 - 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, // 45 - 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, // 46 - 0x1E, 0x20, 0x20, 0x20, 0x26, 0x22, 0x1E, 0x00, // 47 - 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, // 48 - 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 49 - 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, // 4A - 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, // 4B - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, // 4C - 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, // 4D - 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x00, // 4E - 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 4F - 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, // 50 - 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, // 51 - 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, // 52 - 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, // 53 - 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // 54 - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 55 - 0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 56 - 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, // 57 - 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, // 58 - 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, // 59 - 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, // 5A - 0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00, // 5B - 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // 5C - 0x3C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3C, 0x00, // 5D - 0x08, 0x14, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, // 5E - 0x0E, 0x11, 0x3C, 0x10, 0x3C, 0x11, 0x0E, 0x00, // 5F - 0x0C, 0x12, 0x2D, 0x29, 0x29, 0x2D, 0x12, 0x0C, // 60 - 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, // 61 - 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, // 62 - 0x00, 0x00, 0x1E, 0x20, 0x20, 0x20, 0x1E, 0x00, // 63 - 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, // 64 - 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1E, 0x00, // 65 - 0x0C, 0x12, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x00, // 66 - 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x1C, // 67 - 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, // 68 - 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, // 69 - 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x24, 0x18, // 6A - 0x20, 0x20, 0x22, 0x24, 0x38, 0x24, 0x22, 0x00, // 6B - 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 6C - 0x00, 0x00, 0x36, 0x2A, 0x2A, 0x2A, 0x22, 0x00, // 6D - 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, // 6E - 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, // 6F - 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, // 70 - 0x00, 0x00, 0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, // 71 - 0x00, 0x00, 0x2E, 0x30, 0x20, 0x20, 0x20, 0x00, // 72 - 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, // 73 - 0x10, 0x10, 0x3C, 0x10, 0x10, 0x12, 0x0C, 0x00, // 74 - 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, // 75 - 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 76 - 0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x00, // 77 - 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, // 78 - 0x00, 0x00, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, // 79 - 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, // 7A - 0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00, // 7B - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // 7C - 0x38, 0x0C, 0x0C, 0x06, 0x0C, 0x0C, 0x38, 0x00, // 7D - 0x2A, 0x15, 0x2A, 0x15, 0x2A, 0x15, 0x2A, 0x15, // 7E - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // 7F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 81 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 82 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 83 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 84 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 85 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 86 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 87 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 90 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 91 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 92 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 93 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 94 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 95 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 97 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 98 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 99 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0 - 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, 0xF7, 0xFF, // A1 - 0xEB, 0xEB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xEB, 0xEB, 0xC1, 0xEB, 0xC1, 0xEB, 0xEB, 0xFF, // A3 - 0xF7, 0xE1, 0xD7, 0xE3, 0xF5, 0xC3, 0xF7, 0xFF, // A4 - 0xCF, 0xCD, 0xFB, 0xF7, 0xEF, 0xD9, 0xF9, 0xFF, // A5 - 0xEF, 0xD7, 0xD7, 0xEF, 0xD5, 0xDB, 0xE5, 0xFF, // A6 - 0xF7, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A7 - 0xF7, 0xEF, 0xDF, 0xDF, 0xDF, 0xEF, 0xF7, 0xFF, // A8 - 0xF7, 0xFB, 0xFD, 0xFD, 0xFD, 0xFB, 0xF7, 0xFF, // A9 - 0xF7, 0xD5, 0xE3, 0xF7, 0xE3, 0xD5, 0xF7, 0xFF, // AA - 0xFF, 0xF7, 0xF7, 0xC1, 0xF7, 0xF7, 0xFF, 0xFF, // AB - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xF7, 0xEF, // AC - 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, // AD - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, // AE - 0xFF, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xFF, 0xFF, // AF - 0xE3, 0xDD, 0xD9, 0xD5, 0xCD, 0xDD, 0xE3, 0xFF, // B0 - 0xF7, 0xE7, 0xF7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // B1 - 0xE3, 0xDD, 0xFD, 0xFB, 0xF7, 0xEF, 0xC1, 0xFF, // B2 - 0xC1, 0xFD, 0xFB, 0xF3, 0xFD, 0xDD, 0xE3, 0xFF, // B3 - 0xFB, 0xF3, 0xEB, 0xDB, 0xC1, 0xFB, 0xFB, 0xFF, // B4 - 0xC1, 0xDF, 0xC3, 0xFD, 0xFD, 0xDD, 0xE3, 0xFF, // B5 - 0xF3, 0xEF, 0xDF, 0xC3, 0xDD, 0xDD, 0xE3, 0xFF, // B6 - 0xC1, 0xFD, 0xFB, 0xF7, 0xEF, 0xEF, 0xEF, 0xFF, // B7 - 0xE3, 0xDD, 0xDD, 0xE3, 0xDD, 0xDD, 0xE3, 0xFF, // B8 - 0xE3, 0xDD, 0xDD, 0xE1, 0xFD, 0xFB, 0xE7, 0xFF, // B9 - 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, // BA - 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xF7, 0xEF, // BB - 0xFB, 0xF7, 0xEF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFF, // BC - 0xFF, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, // BD - 0xEF, 0xF7, 0xFB, 0xFD, 0xFB, 0xF7, 0xEF, 0xFF, // BE - 0xE3, 0xDD, 0xFB, 0xF7, 0xF7, 0xFF, 0xF7, 0xFF, // BF - 0xE3, 0xDD, 0xD5, 0xD1, 0xD3, 0xDF, 0xE1, 0xFF, // C0 - 0xF7, 0xEB, 0xDD, 0xDD, 0xC1, 0xDD, 0xDD, 0xFF, // C1 - 0xC3, 0xDD, 0xDD, 0xC3, 0xDD, 0xDD, 0xC3, 0xFF, // C2 - 0xE3, 0xDD, 0xDF, 0xDF, 0xDF, 0xDD, 0xE3, 0xFF, // C3 - 0xC3, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xC3, 0xFF, // C4 - 0xC1, 0xDF, 0xDF, 0xC3, 0xDF, 0xDF, 0xC1, 0xFF, // C5 - 0xC1, 0xDF, 0xDF, 0xC3, 0xDF, 0xDF, 0xDF, 0xFF, // C6 - 0xE1, 0xDF, 0xDF, 0xDF, 0xD9, 0xDD, 0xE1, 0xFF, // C7 - 0xDD, 0xDD, 0xDD, 0xC1, 0xDD, 0xDD, 0xDD, 0xFF, // C8 - 0xE3, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // C9 - 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xDD, 0xE3, 0xFF, // CA - 0xDD, 0xDB, 0xD7, 0xCF, 0xD7, 0xDB, 0xDD, 0xFF, // CB - 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xC1, 0xFF, // CC - 0xDD, 0xC9, 0xD5, 0xD5, 0xDD, 0xDD, 0xDD, 0xFF, // CD - 0xDD, 0xDD, 0xCD, 0xD5, 0xD9, 0xDD, 0xDD, 0xFF, // CE - 0xE3, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xE3, 0xFF, // CF - 0xC3, 0xDD, 0xDD, 0xC3, 0xDF, 0xDF, 0xDF, 0xFF, // D0 - 0xE3, 0xDD, 0xDD, 0xDD, 0xD5, 0xDB, 0xE5, 0xFF, // D1 - 0xC3, 0xDD, 0xDD, 0xC3, 0xD7, 0xDB, 0xDD, 0xFF, // D2 - 0xE3, 0xDD, 0xDF, 0xE3, 0xFD, 0xDD, 0xE3, 0xFF, // D3 - 0xC1, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // D4 - 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xE3, 0xFF, // D5 - 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xEB, 0xF7, 0xFF, // D6 - 0xDD, 0xDD, 0xDD, 0xD5, 0xD5, 0xC9, 0xDD, 0xFF, // D7 - 0xDD, 0xDD, 0xEB, 0xF7, 0xEB, 0xDD, 0xDD, 0xFF, // D8 - 0xDD, 0xDD, 0xEB, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // D9 - 0xC1, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xC1, 0xFF, // DA - 0xE1, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xE1, 0xFF, // DB - 0xFF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFF, 0xFF, // DC - 0xC3, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xC3, 0xFF, // DD - 0xF7, 0xEB, 0xD5, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // DE - 0xF1, 0xEE, 0xC3, 0xEF, 0xC3, 0xEE, 0xF1, 0xFF, // DF - 0xF3, 0xED, 0xD2, 0xD6, 0xD6, 0xD2, 0xED, 0xF3, // E0 - 0xFF, 0xFF, 0xE3, 0xFD, 0xE1, 0xDD, 0xE1, 0xFF, // E1 - 0xDF, 0xDF, 0xC3, 0xDD, 0xDD, 0xDD, 0xC3, 0xFF, // E2 - 0xFF, 0xFF, 0xE1, 0xDF, 0xDF, 0xDF, 0xE1, 0xFF, // E3 - 0xFD, 0xFD, 0xE1, 0xDD, 0xDD, 0xDD, 0xE1, 0xFF, // E4 - 0xFF, 0xFF, 0xE3, 0xDD, 0xC1, 0xDF, 0xE1, 0xFF, // E5 - 0xF3, 0xED, 0xEF, 0xC3, 0xEF, 0xEF, 0xEF, 0xFF, // E6 - 0xFF, 0xFF, 0xE3, 0xDD, 0xDD, 0xE1, 0xFD, 0xE3, // E7 - 0xDF, 0xDF, 0xC3, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, // E8 - 0xF7, 0xFF, 0xE7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // E9 - 0xFB, 0xFF, 0xF3, 0xFB, 0xFB, 0xFB, 0xDB, 0xE7, // EA - 0xDF, 0xDF, 0xDD, 0xDB, 0xC7, 0xDB, 0xDD, 0xFF, // EB - 0xE7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // EC - 0xFF, 0xFF, 0xC9, 0xD5, 0xD5, 0xD5, 0xDD, 0xFF, // ED - 0xFF, 0xFF, 0xC3, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, // EE - 0xFF, 0xFF, 0xE3, 0xDD, 0xDD, 0xDD, 0xE3, 0xFF, // EF - 0xFF, 0xFF, 0xC3, 0xDD, 0xDD, 0xC3, 0xDF, 0xDF, // F0 - 0xFF, 0xFF, 0xE1, 0xDD, 0xDD, 0xE1, 0xFD, 0xFD, // F1 - 0xFF, 0xFF, 0xD1, 0xCF, 0xDF, 0xDF, 0xDF, 0xFF, // F2 - 0xFF, 0xFF, 0xE1, 0xDF, 0xE3, 0xFD, 0xC3, 0xFF, // F3 - 0xEF, 0xEF, 0xC3, 0xEF, 0xEF, 0xED, 0xF3, 0xFF, // F4 - 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xD9, 0xE5, 0xFF, // F5 - 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xEB, 0xF7, 0xFF, // F6 - 0xFF, 0xFF, 0xDD, 0xDD, 0xD5, 0xD5, 0xC9, 0xFF, // F7 - 0xFF, 0xFF, 0xDD, 0xEB, 0xF7, 0xEB, 0xDD, 0xFF, // F8 - 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xE1, 0xFD, 0xE3, // F9 - 0xFF, 0xFF, 0xC1, 0xFB, 0xF7, 0xEF, 0xC1, 0xFF, // FA - 0xF1, 0xE7, 0xE7, 0xCF, 0xE7, 0xE7, 0xF1, 0xFF, // FB - 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, // FC - 0xC7, 0xF3, 0xF3, 0xF9, 0xF3, 0xF3, 0xC7, 0xFF, // FD - 0xD5, 0xEA, 0xD5, 0xEA, 0xD5, 0xEA, 0xD5, 0xEA, // FE - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // FF -}; - -/* - Embedded source code compiled with: - - sokol-shdc -i debugtext.glsl -o debugtext.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = vec4(position * vec2(2.0, -2.0) + vec2(-1.0, +1.0), 0.0, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv).xxxx * color; - } - @end - - @program debugtext vs fs -*/ -#if defined(SOKOL_GLCORE33) -static const char _sdtx_vs_source_glsl330[298] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x6c,0x61, - 0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69, - 0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x76,0x65,0x63,0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2a,0x20, - 0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x20, - 0x2b,0x20,0x76,0x65,0x63,0x32,0x28,0x2d,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30, - 0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sdtx_fs_source_glsl330[182] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74, - 0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20, - 0x75,0x76,0x29,0x2e,0x78,0x78,0x78,0x78,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const char _sdtx_vs_source_glsl300es[301] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74, - 0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e, - 0x30,0x29,0x20,0x2b,0x20,0x76,0x65,0x63,0x32,0x28,0x2d,0x31,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sdtx_fs_source_glsl300es[255] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x2e,0x78,0x78,0x78, - 0x78,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sdtx_vs_bytecode_metal_macos[2796] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0xfe,0xa3,0xdd,0x3f,0xa3,0x19,0x66, - 0x48,0xdb,0x53,0x17,0xfa,0x47,0xab,0xcd,0x1c,0x32,0x10,0x34,0x47,0xde,0x1e,0x11, - 0x5c,0xfd,0x36,0x7a,0xb2,0xbe,0x26,0x50,0xa3,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xcc,0x09,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0x70,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x00,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0xc2,0xff,0xff,0xff,0xff,0x0f,0x80,0x04,0x50,0x00, - 0x49,0x18,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x00,0x00,0x00, - 0x89,0x20,0x00,0x00,0x11,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04, - 0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c, - 0x0b,0x84,0x84,0x4c,0x10,0x34,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76, - 0x08,0x91,0x42,0x4c,0x84,0x10,0x15,0x22,0x22,0x82,0x6c,0x20,0x60,0x8e,0x00,0x0c, - 0x52,0x20,0x87,0x11,0x88,0x64,0x04,0x00,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38, - 0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e, - 0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73, - 0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40, - 0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10, - 0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07, - 0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a, - 0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20, - 0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07, - 0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72, - 0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0, - 0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07, - 0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x29,0x00,0x00,0x08,0x00,0x00, - 0x00,0x00,0x00,0x18,0xc2,0x1c,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81, - 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x82,0x42,0x28,0x08, - 0xd2,0xb1,0x84,0x26,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xb1,0x00,0x00,0x00, - 0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7, - 0x21,0x46,0x42,0x20,0x80,0x72,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3, - 0x2b,0x1b,0x62,0x24,0x02,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4, - 0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac, - 0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10, - 0x43,0x8c,0x44,0x48,0x8c,0x64,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e, - 0x44,0x48,0x84,0x64,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56, - 0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56, - 0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65, - 0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c, - 0x65,0x43,0x04,0x64,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1, - 0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95, - 0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x51, - 0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d, - 0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69, - 0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34, - 0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9, - 0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21,0x11,0x22,0x21,0x13, - 0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6, - 0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85, - 0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e, - 0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10, - 0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85,0x64,0x08,0x47,0x28, - 0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e, - 0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b, - 0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf, - 0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf, - 0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x64,0x40,0x3c, - 0xe4,0x4b,0x86,0x44,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90,0x30,0x60,0x42,0x57, - 0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x04,0xc4,0x43,0xbe,0x44,0x48, - 0x04,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x44,0x40,0xc0,0x00,0x89,0x90,0x0b, - 0x99,0x90,0x32,0x18,0x62,0x20,0x62,0x80,0x90,0x01,0x62,0x06,0x43,0x8c,0x02,0x40, - 0x3a,0xe4,0x0c,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40, - 0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45, - 0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xa4,0x03,0x39,0x94,0x83, - 0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39, - 0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8, - 0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38,0x9c,0x43,0x39,0xfc,0x82, - 0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c,0x09,0x90,0x11,0x53,0x38, - 0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc, - 0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19, - 0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e, - 0x4c,0x09,0xd0,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c, - 0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07, - 0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e, - 0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43, - 0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c, - 0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76, - 0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e, - 0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8, - 0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4, - 0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68, - 0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07, - 0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71, - 0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5, - 0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4, - 0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90, - 0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43, - 0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b, - 0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78, - 0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2, - 0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20, - 0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0, - 0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83, - 0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07, - 0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61, - 0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d, - 0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39, - 0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79, - 0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3, - 0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4, - 0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8, - 0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83, - 0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x05,0x00,0x00,0x00, - 0x06,0x50,0x30,0x00,0xd2,0xd0,0x16,0xd0,0x00,0x48,0xe4,0x17,0x0c,0xe0,0x57,0x76, - 0x71,0xdb,0x00,0x00,0x61,0x20,0x00,0x00,0x1b,0x00,0x00,0x00,0x13,0x04,0x41,0x2c, - 0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xb4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10, - 0x83,0xd0,0x34,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82,0x20,0x18,0x80,0x20, - 0x08,0x82,0xe0,0x30,0x96,0x00,0x82,0x20,0x88,0xff,0x02,0x08,0x82,0x20,0xfe,0xcd, - 0x00,0x90,0xcc,0x41,0x54,0x15,0x35,0xd1,0xcc,0x00,0x10,0x8c,0x11,0x80,0x20,0x08, - 0xe2,0xdf,0x08,0xc0,0x0c,0x00,0x00,0x00,0x23,0x06,0x86,0x10,0x54,0x0e,0x72,0x0c, - 0x32,0x04,0xc7,0x32,0xc8,0x10,0x1c,0xcd,0x6c,0xc3,0x01,0x01,0xb3,0x0d,0x01,0x14, - 0xcc,0x36,0x04,0x83,0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_fs_bytecode_metal_macos[2825] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf6,0x61,0xa5,0x24,0x2e,0x8e,0x25, - 0x56,0xa9,0xb9,0xe4,0x35,0x58,0x0f,0xd8,0xb4,0x32,0x8b,0xbc,0x73,0xb0,0x70,0xbe, - 0x5d,0x66,0xf0,0xf4,0x12,0x93,0x26,0xe5,0xdd,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x1c,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x84,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xb2,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83, - 0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78, - 0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90, - 0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76, - 0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20, - 0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07, - 0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71, - 0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20, - 0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f, - 0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76, - 0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50, - 0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78, - 0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00, - 0x00,0x00,0x00,0x00,0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64, - 0x81,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50, - 0x10,0x65,0x40,0x70,0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00, - 0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37, - 0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b, - 0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c, - 0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26, - 0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac, - 0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0, - 0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79, - 0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6, - 0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6, - 0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62, - 0x6c,0x65,0x43,0x84,0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5, - 0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99, - 0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86, - 0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59, - 0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f, - 0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c, - 0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd, - 0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08, - 0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b, - 0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c, - 0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72, - 0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde, - 0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec, - 0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b, - 0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8, - 0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3, - 0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6, - 0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e, - 0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b, - 0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba,0x32,0xbc,0x21, - 0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1, - 0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e, - 0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c, - 0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41, - 0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88, - 0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1, - 0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61, - 0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07,0x7a,0x98,0x12, - 0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79,0x98,0x87,0x74, - 0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70,0x03,0x76,0x08, - 0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87,0x72,0x90,0x87, - 0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74,0x90,0x07,0x37, - 0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78,0x07,0x78,0xa0, - 0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98,0x70,0x48,0x07, - 0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77,0xa0,0x87,0x29, - 0xc1,0x1a,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00, - 0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45, - 0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00, - 0x00,0x61,0x20,0x00,0x00,0x0f,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00, - 0x00,0x06,0x00,0x00,0x00,0x14,0x47,0x00,0x88,0x8d,0x00,0x90,0x1a,0x01,0xa8,0x01, - 0x12,0x33,0x00,0x14,0x66,0x00,0x08,0x8c,0x00,0x00,0x00,0x00,0x00,0x23,0x06,0x8a, - 0x10,0x4c,0x09,0xb2,0x10,0x46,0x11,0x0c,0x32,0x04,0x03,0x62,0x01,0x23,0x9f,0xd9, - 0x06,0x23,0x00,0x32,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_vs_bytecode_metal_ios[2796] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0xba,0x9f,0x15,0xc2,0x1c,0x90,0x81, - 0x14,0x52,0x1d,0xff,0x02,0xbe,0x84,0x58,0x4b,0x16,0xdb,0x77,0xe8,0xfc,0xb2,0x67, - 0xb1,0x23,0xf1,0x84,0xb0,0x8d,0xed,0xb3,0x81,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc4,0x09,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0x6e,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x00,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0xc2,0xff,0xff,0xff,0xff,0x0f,0x80,0x04,0x50,0x00, - 0x49,0x18,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x00,0x00,0x00, - 0x89,0x20,0x00,0x00,0x11,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04, - 0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c, - 0x0b,0x84,0x84,0x4c,0x10,0x34,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76, - 0x08,0x91,0x42,0x4c,0x84,0x10,0x15,0x22,0x22,0x82,0x6c,0x20,0x60,0x8e,0x00,0x0c, - 0x52,0x20,0x87,0x11,0x88,0x64,0x04,0x00,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e, - 0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0, - 0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0, - 0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6, - 0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07, - 0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6, - 0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07, - 0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0, - 0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20, - 0x07,0x43,0x98,0x02,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0xcc,0x01,0x04, - 0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca, - 0x12,0x18,0x01,0x28,0x82,0x42,0x28,0x08,0xd2,0xb1,0x04,0x48,0x00,0x00,0x00,0x00, - 0x79,0x18,0x00,0x00,0xb1,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25, - 0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0x46,0x42,0x20,0x80,0x72,0x50,0xb9, - 0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x24,0x02,0x22,0x24,0x05, - 0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c, - 0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04, - 0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6, - 0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10,0x43,0x8c,0x44,0x48,0x8c,0x64,0x60,0xd1, - 0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e,0x44,0x48,0x84,0x64,0xe0,0x16,0x96,0x26, - 0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36, - 0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72, - 0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61, - 0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x21,0x19,0x84,0xa5, - 0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89, - 0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89, - 0xb1,0x95,0x0d,0x11,0x90,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19, - 0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7, - 0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70, - 0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5, - 0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20, - 0x0f,0x02,0x21,0x11,0x22,0x21,0x13,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b, - 0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed, - 0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85,0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d, - 0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb, - 0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86, - 0x18,0x48,0x85,0x64,0x08,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c, - 0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18, - 0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9, - 0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32, - 0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x43,0xa8,0x64,0x40,0x3c,0xe4,0x4b,0x86,0x44,0x40,0xc0,0x00,0x89,0x10, - 0x09,0x99,0x90,0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84, - 0x4a,0x04,0xc4,0x43,0xbe,0x44,0x48,0x04,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19, - 0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88, - 0x44,0x40,0xc0,0x00,0x89,0x90,0x0b,0x99,0x90,0x32,0x18,0x62,0x20,0x62,0x80,0x90, - 0x01,0x62,0x06,0x43,0x8c,0x02,0x40,0x3a,0xe4,0x0c,0x46,0x44,0xec,0xc0,0x0e,0xf6, - 0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40,0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0, - 0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45,0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4, - 0x83,0x1b,0xa4,0x03,0x39,0x94,0x83,0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43, - 0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94, - 0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8,0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4, - 0x43,0x38,0x9c,0x43,0x39,0xfc,0x82,0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83, - 0x3b,0x4c,0x09,0x90,0x11,0x53,0x38,0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b, - 0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc,0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8, - 0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19,0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43, - 0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e,0x4c,0x09,0xd0,0x00,0x00,0x79,0x18,0x00,0x00, - 0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88, - 0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6, - 0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce, - 0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8, - 0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48, - 0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11, - 0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e, - 0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89, - 0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b, - 0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37, - 0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78, - 0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81, - 0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1, - 0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c, - 0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39, - 0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc, - 0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58, - 0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87, - 0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f, - 0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e, - 0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66, - 0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0, - 0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e, - 0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc, - 0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3, - 0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07, - 0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e, - 0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e, - 0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d, - 0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00, - 0x71,0x20,0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x16,0xd0, - 0x00,0x48,0xe4,0x17,0x0c,0xe0,0x57,0x76,0x71,0xdb,0x00,0x00,0x61,0x20,0x00,0x00, - 0x1b,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, - 0xb4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10,0x83,0xd0,0x34,0x94,0x33,0x00,0x14,0x63, - 0x09,0x20,0x08,0x82,0x20,0x18,0x80,0x20,0x08,0x82,0xe0,0x30,0x96,0x00,0x82,0x20, - 0x88,0xff,0x02,0x08,0x82,0x20,0xfe,0xcd,0x00,0x90,0xcc,0x41,0x54,0x15,0x35,0xd1, - 0xcc,0x00,0x10,0x8c,0x11,0x80,0x20,0x08,0xe2,0xdf,0x08,0xc0,0x0c,0x00,0x00,0x00, - 0x23,0x06,0x86,0x10,0x54,0x0e,0x72,0x0c,0x32,0x04,0xc7,0x32,0xc8,0x10,0x1c,0xcd, - 0x6c,0xc3,0x01,0x01,0xb3,0x0d,0x01,0x14,0xcc,0x36,0x04,0x83,0x90,0x01,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_fs_bytecode_metal_ios[2825] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x5c,0x3b,0x31,0x10,0xb3,0x9b,0xe2, - 0x6d,0x48,0xbf,0xdd,0x8e,0xac,0x5d,0xcc,0x7d,0x7b,0xba,0xe9,0xfb,0xe5,0xd0,0xdd, - 0xf7,0xec,0x82,0x0c,0xb9,0x6a,0xd2,0x30,0x4d,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x14,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x82,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03, - 0x04,0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00, - 0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43, - 0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00, - 0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59, - 0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9, - 0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8, - 0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e, - 0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e, - 0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99, - 0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37, - 0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74, - 0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96, - 0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c, - 0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21, - 0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09, - 0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2, - 0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c, - 0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c, - 0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b, - 0x99,0x0f,0x07,0xba,0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c, - 0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65, - 0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87, - 0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d, - 0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88, - 0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda, - 0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61, - 0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20, - 0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03, - 0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70, - 0x48,0x07,0x79,0x70,0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28, - 0x87,0x5f,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32, - 0x62,0x0a,0x87,0x74,0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76, - 0x28,0x87,0x5f,0x78,0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83, - 0xc2,0x38,0x23,0x98,0x70,0x48,0x07,0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87, - 0x76,0x28,0x07,0x77,0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00,0x00,0x00,0x79,0x18,0x00, - 0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d, - 0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c, - 0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d, - 0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d, - 0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79, - 0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc, - 0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50, - 0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30, - 0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03, - 0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07, - 0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76, - 0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98, - 0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8, - 0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21, - 0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43, - 0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f, - 0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70, - 0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0, - 0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40, - 0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41, - 0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e, - 0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07, - 0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f, - 0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d, - 0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38, - 0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88, - 0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08, - 0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50, - 0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01, - 0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03, - 0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c, - 0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00, - 0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d, - 0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0f,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x14,0x47,0x00, - 0x88,0x8d,0x00,0x90,0x1a,0x01,0xa8,0x01,0x12,0x33,0x00,0x14,0x66,0x00,0x08,0x8c, - 0x00,0x00,0x00,0x00,0x00,0x23,0x06,0x8a,0x10,0x4c,0x09,0xb2,0x10,0x46,0x11,0x0c, - 0x32,0x04,0x03,0x62,0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const char _sdtx_vs_source_metal_sim[577] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28, - 0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65, - 0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74, - 0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64, - 0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, - 0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74, - 0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, - 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, - 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x28,0x66,0x6d,0x61,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x32,0x2e,0x30,0x2c, - 0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x2d, - 0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c, - 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75, - 0x76,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -static const char _sdtx_fs_source_metal_sim[441] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x29,0x2e,0x78,0x78,0x78,0x78,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f, - 0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, - 0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sdtx_vs_bytecode_hlsl4[692] = { - 0x44,0x58,0x42,0x43,0x07,0x05,0xa0,0xb3,0x53,0xc1,0x0a,0x0d,0x1e,0xf4,0xe4,0xa6, - 0x91,0xaf,0x4c,0xca,0x01,0x00,0x00,0x00,0xb4,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xe4,0x00,0x00,0x00,0x54,0x01,0x00,0x00, - 0x38,0x02,0x00,0x00,0x52,0x44,0x45,0x46,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x1c,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66, - 0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65, - 0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00, - 0x49,0x53,0x47,0x4e,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00,0x50,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x0f,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43, - 0x4f,0x4f,0x52,0x44,0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x00,0xab,0xab,0xab,0x53,0x48,0x44,0x52,0xdc,0x00,0x00,0x00,0x40,0x00,0x01,0x00, - 0x37,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0xf2,0x10,0x10,0x00,0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0x32,0x20,0x10,0x00, - 0x00,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00, - 0x67,0x00,0x00,0x04,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x36,0x00,0x00,0x05,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00, - 0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00,0x32,0x00,0x00,0x0f,0x32,0x20,0x10,0x00, - 0x02,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00, - 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x08,0xc2,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x80,0x3f,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0xb7,0xcd,0xbd,0xb1,0x6f,0x85,0x5d,0x59,0x07,0x7e,0xa3,0x6e, - 0xe2,0x23,0x68,0xa0,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_WGPU) -static const char _sdtx_vs_source_wgsl[922] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70, - 0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74, - 0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a, - 0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20, - 0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f, - 0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x28,0x28,0x78,0x5f,0x31,0x39,0x20,0x2a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x32,0x2e,0x30,0x66,0x2c,0x20,0x2d,0x32,0x2e, - 0x30,0x66,0x29,0x29,0x20,0x2b,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x2d,0x31,0x2e, - 0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34, - 0x66,0x28,0x78,0x5f,0x32,0x37,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x37,0x2e,0x79, - 0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x32, - 0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x33,0x37,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x34,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3d,0x20,0x78,0x5f,0x34,0x31,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72, - 0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74, - 0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x32, - 0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31, - 0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78,0x63, - 0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32, - 0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72, - 0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74, - 0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sdtx_fs_source_wgsl[663] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x38,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x32, - 0x34,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x34,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32, - 0x34,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x34,0x2e,0x78,0x29,0x20,0x2a,0x20,0x78, - 0x5f,0x32,0x38,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f, - 0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40, - 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b, - 0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31, - 0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sdtx_vs_src_dummy = ""; -static const char* _sdtx_fs_src_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs -typedef struct { - uint32_t id; - sg_resource_state state; -} _sdtx_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sdtx_pool_t; - -typedef struct { - float x, y; -} _sdtx_float2_t; - -typedef struct { - float x, y; - uint16_t u, v; - uint32_t color; -} _sdtx_vertex_t; - -typedef struct { - int layer_id; - int first_vertex; - int num_vertices; -} _sdtx_command_t; - -typedef struct { - _sdtx_slot_t slot; - sdtx_context_desc_t desc; - uint32_t frame_id; - uint32_t update_frame_id; - struct { - int cap; - int next; - _sdtx_vertex_t* ptr; - } vertices; - struct { - int cap; - int next; - _sdtx_command_t* ptr; - } commands; - sg_buffer vbuf; - sg_pipeline pip; - int cur_font; - int cur_layer_id; - _sdtx_float2_t canvas_size; - _sdtx_float2_t glyph_size; - _sdtx_float2_t origin; - _sdtx_float2_t pos; - float tab_width; - uint32_t color; -} _sdtx_context_t; - -typedef struct { - _sdtx_pool_t pool; - _sdtx_context_t* contexts; -} _sdtx_context_pool_t; - -typedef struct { - uint32_t init_cookie; - sdtx_desc_t desc; - sg_image font_img; - sg_sampler font_smp; - sg_shader shader; - uint32_t fmt_buf_size; - char* fmt_buf; - sdtx_context def_ctx_id; - sdtx_context cur_ctx_id; - _sdtx_context_t* cur_ctx; // may be 0! - _sdtx_context_pool_t context_pool; - uint8_t font_pixels[SDTX_MAX_FONTS * 256 * 8 * 8]; -} _sdtx_t; -static _sdtx_t _sdtx; - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SDTX_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sdtx_log_messages[] = { - _SDTX_LOG_ITEMS -}; -#undef _SDTX_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SDTX_PANIC(code) _sdtx_log(SDTX_LOGITEM_ ##code, 0, __LINE__) -#define _SDTX_ERROR(code) _sdtx_log(SDTX_LOGITEM_ ##code, 1, __LINE__) -#define _SDTX_WARN(code) _sdtx_log(SDTX_LOGITEM_ ##code, 2, __LINE__) -#define _SDTX_INFO(code) _sdtx_log(SDTX_LOGITEM_ ##code, 3, __LINE__) - -static void _sdtx_log(sdtx_log_item_t log_item, uint32_t log_level, uint32_t line_nr) { - if (_sdtx.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sdtx_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sdtx.desc.logger.func("sdtx", log_level, log_item, message, line_nr, filename, _sdtx.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _sdtx_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _sdtx_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sdtx.desc.allocator.alloc_fn) { - ptr = _sdtx.desc.allocator.alloc_fn(size, _sdtx.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SDTX_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _sdtx_malloc_clear(size_t size) { - void* ptr = _sdtx_malloc(size); - _sdtx_clear(ptr, size); - return ptr; -} - -static void _sdtx_free(void* ptr) { - if (_sdtx.desc.allocator.free_fn) { - _sdtx.desc.allocator.free_fn(ptr, _sdtx.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ███ ██ ████████ ███████ ██ ██ ████████ ██████ ██████ ██████ ██ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ████ ██ ███████ ██ ██ ██ ██ ██████ ██████ ███████ -// -// >>context pool -static void _sdtx_init_pool(_sdtx_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _sdtx_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _sdtx_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _sdtx_discard_pool(_sdtx_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sdtx_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sdtx_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _sdtx_pool_alloc_index(_sdtx_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SDTX_INVALID_SLOT_INDEX; - } -} - -static void _sdtx_pool_free_index(_sdtx_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SDTX_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -static void _sdtx_setup_context_pool(const sdtx_desc_t* desc) { - SOKOL_ASSERT(desc); - // note: the pool will have an additional item, since slot 0 is reserved - SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SDTX_MAX_POOL_SIZE)); - _sdtx_init_pool(&_sdtx.context_pool.pool, desc->context_pool_size); - size_t pool_byte_size = sizeof(_sdtx_context_t) * (size_t)_sdtx.context_pool.pool.size; - _sdtx.context_pool.contexts = (_sdtx_context_t*) _sdtx_malloc_clear(pool_byte_size); -} - -static void _sdtx_discard_context_pool(void) { - SOKOL_ASSERT(_sdtx.context_pool.contexts); - _sdtx_free(_sdtx.context_pool.contexts); - _sdtx.context_pool.contexts = 0; - _sdtx_discard_pool(&_sdtx.context_pool.pool); -} - -/* allocate the slot at slot_index: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the resource id -*/ -static uint32_t _sdtx_slot_alloc(_sdtx_pool_t* pool, _sdtx_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SDTX_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == SG_RESOURCESTATE_INITIAL) && (slot->id == SG_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SDTX_SLOT_SHIFT)|(slot_index & _SDTX_SLOT_MASK); - slot->state = SG_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _sdtx_slot_index(uint32_t id) { - int slot_index = (int) (id & _SDTX_SLOT_MASK); - SOKOL_ASSERT(_SDTX_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -// get context pointer without id-check -static _sdtx_context_t* _sdtx_context_at(uint32_t ctx_id) { - SOKOL_ASSERT(SG_INVALID_ID != ctx_id); - int slot_index = _sdtx_slot_index(ctx_id); - SOKOL_ASSERT((slot_index > _SDTX_INVALID_SLOT_INDEX) && (slot_index < _sdtx.context_pool.pool.size)); - return &_sdtx.context_pool.contexts[slot_index]; -} - -// get context pointer with id-check, returns 0 if no match -static _sdtx_context_t* _sdtx_lookup_context(uint32_t ctx_id) { - if (SG_INVALID_ID != ctx_id) { - _sdtx_context_t* ctx = _sdtx_context_at(ctx_id); - if (ctx->slot.id == ctx_id) { - return ctx; - } - } - return 0; -} - -// make context handle from raw uint32_t id -static sdtx_context _sdtx_make_ctx_id(uint32_t ctx_id) { - sdtx_context ctx; - ctx.id = ctx_id; - return ctx; -} - -static sdtx_context _sdtx_alloc_context(void) { - sdtx_context ctx_id; - int slot_index = _sdtx_pool_alloc_index(&_sdtx.context_pool.pool); - if (_SDTX_INVALID_SLOT_INDEX != slot_index) { - ctx_id = _sdtx_make_ctx_id(_sdtx_slot_alloc(&_sdtx.context_pool.pool, &_sdtx.context_pool.contexts[slot_index].slot, slot_index)); - } else { - // pool is exhausted - ctx_id = _sdtx_make_ctx_id(SG_INVALID_ID); - } - return ctx_id; -} - -static sdtx_context_desc_t _sdtx_context_desc_defaults(const sdtx_context_desc_t* desc) { - sdtx_context_desc_t res = *desc; - res.max_commands = _sdtx_def(res.max_commands, _SDTX_DEFAULT_MAX_COMMANDS); - res.char_buf_size = _sdtx_def(res.char_buf_size, _SDTX_DEFAULT_CHAR_BUF_SIZE); - res.canvas_width = _sdtx_def(res.canvas_width, _SDTX_DEFAULT_CANVAS_WIDTH); - res.canvas_height = _sdtx_def(res.canvas_height, _SDTX_DEFAULT_CANVAS_HEIGHT); - res.tab_width = _sdtx_def(res.tab_width, _SDTX_DEFAULT_TAB_WIDTH); - // keep pixel format attrs are passed as is into pipeline creation - SOKOL_ASSERT(res.char_buf_size > 0); - SOKOL_ASSERT(!isnan(res.canvas_width)); - SOKOL_ASSERT(!isnan(res.canvas_height)); - SOKOL_ASSERT(res.canvas_width > 0.0f); - SOKOL_ASSERT(res.canvas_height > 0.0f); - return res; -} - -static void _sdtx_set_layer(_sdtx_context_t* ctx, int layer_id); -static void _sdtx_rewind(_sdtx_context_t* ctx) { - SOKOL_ASSERT(ctx); - ctx->frame_id++; - ctx->vertices.next = 0; - ctx->commands.next = 0; - _sdtx_set_layer(ctx, 0); - ctx->cur_font = 0; - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; -} - -static void _sdtx_commit_listener(void* userdata) { - _sdtx_context_t* ctx = _sdtx_lookup_context((uint32_t)(uintptr_t)userdata); - if (ctx) { - _sdtx_rewind(ctx); - } -} - -static sg_commit_listener _sdtx_make_commit_listener(_sdtx_context_t* ctx) { - sg_commit_listener listener = { _sdtx_commit_listener, (void*)(uintptr_t)(ctx->slot.id) }; - return listener; -} - -static void _sdtx_init_context(sdtx_context ctx_id, const sdtx_context_desc_t* in_desc) { - sg_push_debug_group("sokol-debugtext"); - - SOKOL_ASSERT((ctx_id.id != SG_INVALID_ID) && in_desc); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - SOKOL_ASSERT(ctx); - ctx->desc = _sdtx_context_desc_defaults(in_desc); - // NOTE: frame_id must be non-zero, so that updates trigger in first frame - ctx->frame_id = 1; - - ctx->vertices.cap = 6 * ctx->desc.char_buf_size; - const size_t vbuf_size = (size_t)ctx->vertices.cap * sizeof(_sdtx_vertex_t); - ctx->vertices.ptr = (_sdtx_vertex_t*) _sdtx_malloc(vbuf_size); - - ctx->commands.cap = ctx->desc.max_commands; - ctx->commands.ptr = (_sdtx_command_t*) _sdtx_malloc((size_t)ctx->commands.cap * sizeof(_sdtx_command_t)); - _sdtx_set_layer(ctx, 0); - - sg_buffer_desc vbuf_desc; - _sdtx_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.size = vbuf_size; - vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.label = "sdtx-vbuf"; - ctx->vbuf = sg_make_buffer(&vbuf_desc); - SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id); - - sg_pipeline_desc pip_desc; - _sdtx_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.layout.buffers[0].stride = sizeof(_sdtx_vertex_t); - pip_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT2; - pip_desc.layout.attrs[1].format = SG_VERTEXFORMAT_USHORT2N; - pip_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; - pip_desc.shader = _sdtx.shader; - pip_desc.index_type = SG_INDEXTYPE_NONE; - pip_desc.sample_count = ctx->desc.sample_count; - pip_desc.depth.pixel_format = ctx->desc.depth_format; - pip_desc.colors[0].pixel_format = ctx->desc.color_format; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.label = "sdtx-pipeline"; - ctx->pip = sg_make_pipeline(&pip_desc); - SOKOL_ASSERT(SG_INVALID_ID != ctx->pip.id); - - ctx->canvas_size.x = ctx->desc.canvas_width; - ctx->canvas_size.y = ctx->desc.canvas_height; - ctx->glyph_size.x = 8.0f / ctx->canvas_size.x; - ctx->glyph_size.y = 8.0f / ctx->canvas_size.y; - ctx->tab_width = (float) ctx->desc.tab_width; - ctx->color = _SDTX_DEFAULT_COLOR; - - if (!sg_add_commit_listener(_sdtx_make_commit_listener(ctx))) { - _SDTX_ERROR(ADD_COMMIT_LISTENER_FAILED); - } - sg_pop_debug_group(); -} - -static void _sdtx_destroy_context(sdtx_context ctx_id) { - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - if (ctx) { - if (ctx->vertices.ptr) { - _sdtx_free(ctx->vertices.ptr); - ctx->vertices.ptr = 0; - ctx->vertices.cap = 0; - ctx->vertices.next = 0; - } - if (ctx->commands.ptr) { - _sdtx_free(ctx->commands.ptr); - ctx->commands.ptr = 0; - ctx->commands.cap = 0; - ctx->commands.next = 0; - } - sg_push_debug_group("sokol_debugtext"); - sg_destroy_buffer(ctx->vbuf); - sg_destroy_pipeline(ctx->pip); - sg_remove_commit_listener(_sdtx_make_commit_listener(ctx)); - sg_pop_debug_group(); - _sdtx_clear(ctx, sizeof(*ctx)); - _sdtx_pool_free_index(&_sdtx.context_pool.pool, _sdtx_slot_index(ctx_id.id)); - } -} - -static bool _sdtx_is_default_context(sdtx_context ctx_id) { - return ctx_id.id == SDTX_DEFAULT_CONTEXT.id; -} - -// ███ ███ ██ ███████ ██████ -// ████ ████ ██ ██ ██ -// ██ ████ ██ ██ ███████ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██████ -// -// >>misc - -// unpack linear 8x8 bits-per-pixel font data into 2D byte-per-pixel texture data -static void _sdtx_unpack_font(const sdtx_font_desc_t* font_desc, uint8_t* out_pixels) { - SOKOL_ASSERT(font_desc->data.ptr); - SOKOL_ASSERT((font_desc->data.size > 0) && ((font_desc->data.size % 8) == 0)); - SOKOL_ASSERT(font_desc->first_char <= font_desc->last_char); - SOKOL_ASSERT((size_t)(((font_desc->last_char - font_desc->first_char) + 1) * 8) == font_desc->data.size); - const uint8_t* ptr = (const uint8_t*) font_desc->data.ptr; - for (int chr = font_desc->first_char; chr <= font_desc->last_char; chr++) { - for (int line = 0; line < 8; line++) { - uint8_t bits = *ptr++; - for (int x = 0; x < 8; x++) { - out_pixels[line*256*8 + chr*8 + x] = ((bits>>(7-x)) & 1) ? 0xFF : 0x00; - } - } - } -} - -static void _sdtx_setup_common(void) { - - // common printf formatting buffer - _sdtx.fmt_buf_size = (uint32_t) _sdtx.desc.printf_buf_size + 1; - _sdtx.fmt_buf = (char*) _sdtx_malloc_clear(_sdtx.fmt_buf_size); - - sg_push_debug_group("sokol-debugtext"); - - // common shader for all contexts - sg_shader_desc shd_desc; - _sdtx_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.label = "sokol-debugtext-shader"; - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _sdtx_vs_source_glsl330; - shd_desc.fs.source = _sdtx_fs_source_glsl330; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _sdtx_vs_source_glsl300es; - shd_desc.fs.source = _sdtx_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sdtx_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sdtx_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sdtx_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sdtx_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = _sdtx_vs_source_metal_sim; - shd_desc.fs.source = _sdtx_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sdtx_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sdtx_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _sdtx_vs_source_wgsl; - shd_desc.fs.source = _sdtx_fs_source_wgsl; - #else - shd_desc.vs.source = _sdtx_vs_src_dummy; - shd_desc.fs.source = _sdtx_fs_src_dummy; - #endif - _sdtx.shader = sg_make_shader(&shd_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sdtx.shader.id); - - // unpack font data - memset(_sdtx.font_pixels, 0xFF, sizeof(_sdtx.font_pixels)); - const int unpacked_font_size = (int) (sizeof(_sdtx.font_pixels) / SDTX_MAX_FONTS); - for (int i = 0; i < SDTX_MAX_FONTS; i++) { - if (_sdtx.desc.fonts[i].data.ptr) { - _sdtx_unpack_font(&_sdtx.desc.fonts[i], &_sdtx.font_pixels[i * unpacked_font_size]); - } - } - - // create font texture and sampler - sg_image_desc img_desc; - _sdtx_clear(&img_desc, sizeof(img_desc)); - img_desc.width = 256 * 8; - img_desc.height = SDTX_MAX_FONTS * 8; - img_desc.pixel_format = SG_PIXELFORMAT_R8; - img_desc.data.subimage[0][0] = SG_RANGE(_sdtx.font_pixels); - img_desc.label = "sdtx-font-texture"; - _sdtx.font_img = sg_make_image(&img_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sdtx.font_img.id); - - sg_sampler_desc smp_desc; - _sdtx_clear(&smp_desc, sizeof(smp_desc)); - smp_desc.min_filter = SG_FILTER_NEAREST; - smp_desc.mag_filter = SG_FILTER_NEAREST; - smp_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - smp_desc.label = "sdtx-font-sampler"; - _sdtx.font_smp = sg_make_sampler(&smp_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sdtx.font_smp.id); - - sg_pop_debug_group(); -} - -static void _sdtx_discard_common(void) { - sg_push_debug_group("sokol-debugtext"); - sg_destroy_sampler(_sdtx.font_smp); - sg_destroy_image(_sdtx.font_img); - sg_destroy_shader(_sdtx.shader); - if (_sdtx.fmt_buf) { - _sdtx_free(_sdtx.fmt_buf); - _sdtx.fmt_buf = 0; - } - sg_pop_debug_group(); -} - -static uint32_t _sdtx_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r); -} - -static float _sdtx_clamp(float v, float lo, float hi) { - if (v < lo) return lo; - else if (v > hi) return hi; - else return v; -} - -static uint32_t _sdtx_pack_rgbaf(float r, float g, float b, float a) { - uint8_t r_u8 = (uint8_t) (_sdtx_clamp(r, 0.0f, 1.0f) * 255.0f); - uint8_t g_u8 = (uint8_t) (_sdtx_clamp(g, 0.0f, 1.0f) * 255.0f); - uint8_t b_u8 = (uint8_t) (_sdtx_clamp(b, 0.0f, 1.0f) * 255.0f); - uint8_t a_u8 = (uint8_t) (_sdtx_clamp(a, 0.0f, 1.0f) * 255.0f); - return _sdtx_pack_rgbab(r_u8, g_u8, b_u8, a_u8); -} - -static void _sdtx_ctrl_char(_sdtx_context_t* ctx, uint8_t c) { - switch (c) { - case '\r': - ctx->pos.x = 0.0f; - break; - case '\n': - ctx->pos.x = 0.0f; - ctx->pos.y += 1.0f; - break; - case '\t': - ctx->pos.x = (ctx->pos.x - fmodf(ctx->pos.x, ctx->tab_width)) + ctx->tab_width; - break; - case ' ': - ctx->pos.x += 1.0f; - break; - } -} - -static _sdtx_vertex_t* _sdtx_next_vertex(_sdtx_context_t* ctx) { - if ((ctx->vertices.next + 6) <= ctx->vertices.cap) { - _sdtx_vertex_t* vx = &ctx->vertices.ptr[ctx->vertices.next]; - ctx->vertices.next += 6; - return vx; - } else { - return 0; - } -} - -static _sdtx_command_t* _sdtx_cur_command(_sdtx_context_t* ctx) { - if (ctx->commands.next > 0) { - return &ctx->commands.ptr[ctx->commands.next - 1]; - } else { - return 0; - } -} - -static _sdtx_command_t* _sdtx_next_command(_sdtx_context_t* ctx) { - if (ctx->commands.next < ctx->commands.cap) { - return &ctx->commands.ptr[ctx->commands.next++]; - } else { - _SDTX_ERROR(COMMAND_BUFFER_FULL); - return 0; - } -} - -static void _sdtx_set_layer(_sdtx_context_t* ctx, int layer_id) { - ctx->cur_layer_id = layer_id; - _sdtx_command_t* cur_cmd = _sdtx_cur_command(ctx); - if (cur_cmd) { - if ((cur_cmd->num_vertices == 0) || (cur_cmd->layer_id == layer_id)) { - // no vertices recorded in current draw command, or layer hasn't changed, can just reuse this - cur_cmd->layer_id = layer_id; - } else { - // layer has changed, need to start a new draw command - _sdtx_command_t* next_cmd = _sdtx_next_command(ctx); - if (next_cmd) { - next_cmd->layer_id = layer_id; - next_cmd->first_vertex = cur_cmd->first_vertex + cur_cmd->num_vertices; - next_cmd->num_vertices = 0; - } - } - } else { - // first draw command in frame - _sdtx_command_t* next_cmd = _sdtx_next_command(ctx); - if (next_cmd) { - next_cmd->layer_id = layer_id; - next_cmd->first_vertex = 0; - next_cmd->num_vertices = 0; - } - } -} - -static void _sdtx_render_char(_sdtx_context_t* ctx, uint8_t c) { - _sdtx_vertex_t* vx = _sdtx_next_vertex(ctx); - _sdtx_command_t* cmd = _sdtx_cur_command(ctx); - if (vx && cmd) { - // update vertex count in current draw command - cmd->num_vertices += 6; - - const float x0 = (ctx->origin.x + ctx->pos.x) * ctx->glyph_size.x; - const float y0 = (ctx->origin.y + ctx->pos.y) * ctx->glyph_size.y; - const float x1 = x0 + ctx->glyph_size.x; - const float y1 = y0 + ctx->glyph_size.y; - - // glyph width and height in font texture space - // NOTE: the '+1' and '-2' fixes texture bleeding into the neighboring font texture cell - const uint16_t uvw = 0x10000 / 0x100; - const uint16_t uvh = 0x10000 / SDTX_MAX_FONTS; - const uint16_t u0 = (((uint16_t)c) * uvw) + 1; - const uint16_t v0 = (((uint16_t)ctx->cur_font) * uvh) + 1; - uint16_t u1 = (u0 + uvw) - 2; - uint16_t v1 = (v0 + uvh) - 2; - const uint32_t color = ctx->color; - - // write 6 vertices - vx->x=x0; vx->y=y0; vx->u = u0; vx->v = v0; vx->color = color; vx++; - vx->x=x1; vx->y=y0; vx->u = u1; vx->v = v0; vx->color = color; vx++; - vx->x=x1; vx->y=y1; vx->u = u1; vx->v = v1; vx->color = color; vx++; - - vx->x=x0; vx->y=y0; vx->u = u0; vx->v = v0; vx->color = color; vx++; - vx->x=x1; vx->y=y1; vx->u = u1; vx->v = v1; vx->color = color; vx++; - vx->x=x0; vx->y=y1; vx->u = u0; vx->v = v1; vx->color = color; vx++; - } - ctx->pos.x += 1.0f; -} - -static void _sdtx_put_char(_sdtx_context_t* ctx, char c) { - uint8_t c_u8 = (uint8_t)c; - if (c_u8 <= 32) { - _sdtx_ctrl_char(ctx, c_u8); - } else { - _sdtx_render_char(ctx, c_u8); - } -} - -SOKOL_API_IMPL void _sdtx_draw_layer(_sdtx_context_t* ctx, int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(ctx); - if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { - sg_push_debug_group("sokol-debugtext"); - - if (ctx->update_frame_id != ctx->frame_id) { - ctx->update_frame_id = ctx->frame_id; - const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sdtx_vertex_t) }; - sg_update_buffer(ctx->vbuf, &range); - } - - sg_apply_pipeline(ctx->pip); - sg_bindings bindings; - _sdtx_clear(&bindings, sizeof(bindings)); - bindings.vertex_buffers[0] = ctx->vbuf; - bindings.fs.images[0] = _sdtx.font_img; - bindings.fs.samplers[0] = _sdtx.font_smp; - sg_apply_bindings(&bindings); - for (int cmd_index = 0; cmd_index < ctx->commands.next; cmd_index++) { - const _sdtx_command_t* cmd = &ctx->commands.ptr[cmd_index]; - if (cmd->layer_id != layer_id) { - continue; - } - SOKOL_ASSERT((cmd->num_vertices % 6) == 0); - sg_draw(cmd->first_vertex, cmd->num_vertices, 1); - } - sg_pop_debug_group(); - } -} - - -static sdtx_desc_t _sdtx_desc_defaults(const sdtx_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sdtx_desc_t res = *desc; - res.context_pool_size = _sdtx_def(res.context_pool_size, _SDTX_DEFAULT_CONTEXT_POOL_SIZE); - res.printf_buf_size = _sdtx_def(res.printf_buf_size, _SDTX_DEFAULT_PRINTF_BUF_SIZE); - for (int i = 0; i < SDTX_MAX_FONTS; i++) { - if (res.fonts[i].data.ptr) { - res.fonts[i].last_char = _sdtx_def(res.fonts[i].last_char, 255); - } - } - res.context = _sdtx_context_desc_defaults(&res.context); - SOKOL_ASSERT(res.context_pool_size > 0); - SOKOL_ASSERT(res.printf_buf_size > 0); - SOKOL_ASSERT(res.context.char_buf_size > 0); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sdtx_setup(const sdtx_desc_t* desc) { - SOKOL_ASSERT(desc); - _sdtx_clear(&_sdtx, sizeof(_sdtx)); - _sdtx.init_cookie = _SDTX_INIT_COOKIE; - _sdtx.desc = _sdtx_desc_defaults(desc); - _sdtx_setup_context_pool(&_sdtx.desc); - _sdtx_setup_common(); - _sdtx.def_ctx_id = sdtx_make_context(&_sdtx.desc.context); - SOKOL_ASSERT(SDTX_DEFAULT_CONTEXT.id == _sdtx.def_ctx_id.id); - sdtx_set_context(_sdtx.def_ctx_id); -} - -SOKOL_API_IMPL void sdtx_shutdown(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - for (int i = 0; i < _sdtx.context_pool.pool.size; i++) { - _sdtx_context_t* ctx = &_sdtx.context_pool.contexts[i]; - _sdtx_destroy_context(_sdtx_make_ctx_id(ctx->slot.id)); - } - _sdtx_discard_common(); - _sdtx_discard_context_pool(); - _sdtx.init_cookie = 0; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_kc853(void) { - sdtx_font_desc_t desc = { { _sdtx_font_kc853, sizeof(_sdtx_font_kc853) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_kc854(void) { - sdtx_font_desc_t desc = { { _sdtx_font_kc854, sizeof(_sdtx_font_kc854) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_z1013(void) { - sdtx_font_desc_t desc = { { _sdtx_font_z1013, sizeof(_sdtx_font_z1013) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_cpc(void) { - sdtx_font_desc_t desc = { { _sdtx_font_cpc, sizeof(_sdtx_font_cpc) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_c64(void) { - sdtx_font_desc_t desc = { { _sdtx_font_c64, sizeof(_sdtx_font_c64) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_oric(void) { - sdtx_font_desc_t desc = { { _sdtx_font_oric, sizeof(_sdtx_font_oric) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_context sdtx_make_context(const sdtx_context_desc_t* desc) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(desc); - sdtx_context ctx_id = _sdtx_alloc_context(); - if (ctx_id.id != SG_INVALID_ID) { - _sdtx_init_context(ctx_id, desc); - } else { - _SDTX_ERROR(CONTEXT_POOL_EXHAUSTED); - } - return ctx_id; -} - -SOKOL_API_IMPL void sdtx_destroy_context(sdtx_context ctx_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - if (_sdtx_is_default_context(ctx_id)) { - _SDTX_ERROR(CANNOT_DESTROY_DEFAULT_CONTEXT); - return; - } - _sdtx_destroy_context(ctx_id); - // re-validate the current context pointer (this will return a nullptr - // if we just destroyed the current context) - _sdtx.cur_ctx = _sdtx_lookup_context(_sdtx.cur_ctx_id.id); -} - -SOKOL_API_IMPL void sdtx_set_context(sdtx_context ctx_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - if (_sdtx_is_default_context(ctx_id)) { - _sdtx.cur_ctx_id = _sdtx.def_ctx_id; - } else { - _sdtx.cur_ctx_id = ctx_id; - } - // this may return a nullptr if the ctx_id handle is invalid - _sdtx.cur_ctx = _sdtx_lookup_context(_sdtx.cur_ctx_id.id); -} - -SOKOL_API_IMPL sdtx_context sdtx_get_context(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - return _sdtx.cur_ctx_id; -} - -SOKOL_API_IMPL sdtx_context sdtx_default_context(void) { - return SDTX_DEFAULT_CONTEXT; -} - -SOKOL_API_IMPL void sdtx_layer(int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_set_layer(ctx, layer_id); - } -} - -SOKOL_API_IMPL void sdtx_font(int font_index) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT((font_index >= 0) && (font_index < SDTX_MAX_FONTS)); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->cur_font = font_index; - } -} - -SOKOL_API_IMPL void sdtx_canvas(float w, float h) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(!isnan(w)); - SOKOL_ASSERT(!isnan(h)); - SOKOL_ASSERT((w > 0.0f) && (h > 0.0f)); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->canvas_size.x = w; - ctx->canvas_size.y = h; - ctx->glyph_size.x = (8.0f / ctx->canvas_size.x); - ctx->glyph_size.y = (8.0f / ctx->canvas_size.y); - ctx->origin.x = 0.0f; - ctx->origin.y = 0.0f; - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; - } -} - -SOKOL_API_IMPL void sdtx_origin(float x, float y) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->origin.x = x; - ctx->origin.y = y; - } -} - -SOKOL_API_IMPL void sdtx_home(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; - } -} - -SOKOL_API_IMPL void sdtx_pos(float x, float y) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = x; - ctx->pos.y = y; - } -} - -SOKOL_API_IMPL void sdtx_pos_x(float x) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = x; - } -} - -SOKOL_API_IMPL void sdtx_pos_y(float y) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.y = y; - } -} - -SOKOL_API_IMPL void sdtx_move(float dx, float dy) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x += dx; - ctx->pos.y += dy; - } -} - -SOKOL_API_IMPL void sdtx_move_x(float dx) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x += dx; - } -} - -SOKOL_API_IMPL void sdtx_move_y(float dy) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.y += dy; - } -} - -SOKOL_API_IMPL void sdtx_crlf(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = 0.0f; - ctx->pos.y += 1.0f; - } -} - -SOKOL_API_IMPL void sdtx_color3b(uint8_t r, uint8_t g, uint8_t b) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbab(r, g, b, 255); - } -} - -SOKOL_API_IMPL void sdtx_color3f(float r, float g, float b) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbaf(r, g, b, 1.0f); - } -} - -SOKOL_API_IMPL void sdtx_color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbab(r, g, b, a); - } -} - -SOKOL_API_IMPL void sdtx_color4f(float r, float g, float b, float a) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbaf(r, g, b, a); - } -} - -SOKOL_API_IMPL void sdtx_color1i(uint32_t rgba) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = rgba; - } -} - -SOKOL_DEBUGTEXT_API_DECL void sdtx_putc(char chr) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_put_char(ctx, chr); - } -} - -SOKOL_DEBUGTEXT_API_DECL void sdtx_puts(const char* str) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - char chr; - while (0 != (chr = *str++)) { - _sdtx_put_char(ctx, chr); - } - } -} - -SOKOL_DEBUGTEXT_API_DECL void sdtx_putr(const char* str, int len) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - for (int i = 0; i < len; i++) { - char chr = str[i]; - if (0 == chr) { - break; - } - _sdtx_put_char(ctx, chr); - } - } -} - -SOKOL_DEBUGTEXT_API_DECL int sdtx_vprintf(const char* fmt, va_list args) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(_sdtx.fmt_buf && (_sdtx.fmt_buf_size >= 2)); - int res = SOKOL_VSNPRINTF(_sdtx.fmt_buf, _sdtx.fmt_buf_size, fmt, args); - // make sure we're 0-terminated in case we're on an old MSVC - _sdtx.fmt_buf[_sdtx.fmt_buf_size-1] = 0; - sdtx_puts(_sdtx.fmt_buf); - return res; -} - -SOKOL_DEBUGTEXT_API_DECL int sdtx_printf(const char* fmt, ...) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(_sdtx.fmt_buf && (_sdtx.fmt_buf_size >= 2)); - va_list args; - va_start(args, fmt); - int res = SOKOL_VSNPRINTF(_sdtx.fmt_buf, _sdtx.fmt_buf_size, fmt, args); - va_end(args); - // make sure we're 0-terminated in case we're on an old MSVC - _sdtx.fmt_buf[_sdtx.fmt_buf_size-1] = 0; - sdtx_puts(_sdtx.fmt_buf); - return res; -} - -SOKOL_API_IMPL void sdtx_draw(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_draw_layer(ctx, 0); - } -} - -SOKOL_API_IMPL void sdtx_context_draw(sdtx_context ctx_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - if (ctx) { - _sdtx_draw_layer(ctx, 0); - } -} - -SOKOL_API_IMPL void sdtx_draw_layer(int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_draw_layer(ctx, layer_id); - } -} - -SOKOL_API_IMPL void sdtx_context_draw_layer(sdtx_context ctx_id, int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - if (ctx) { - _sdtx_draw_layer(ctx, layer_id); - } -} -#endif // SOKOL_DEBUGTEXT_IMPL diff --git a/source/engine/thirdparty/sokol/util/sokol_fontstash.h b/source/engine/thirdparty/sokol/util/sokol_fontstash.h deleted file mode 100644 index 048c821..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_fontstash.h +++ /dev/null @@ -1,1784 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_FONTSTASH_IMPL) -#define SOKOL_FONTSTASH_IMPL -#endif -#ifndef SOKOL_FONTSTASH_INCLUDED -/* - sokol_fontstash.h -- renderer for https://github.com/memononen/fontstash - on top of sokol_gl.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_FONTSTASH_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - The following defines are used by the implementation to select the - platform-specific embedded shader code (these are the same defines as - used by sokol_gfx.h and sokol_app.h): - - SOKOL_GLCORE33 - SOKOL_GLES3 - SOKOL_D3D11 - SOKOL_METAL - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_FONTSTASH_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - Include the following headers before including sokol_fontstash.h: - - sokol_gfx.h - - Additionally include the following headers for including the sokol_fontstash.h - implementation: - - sokol_gl.h - - HOW TO - ====== - --- First initialize sokol-gfx and sokol-gl as usual: - - sg_setup(&(sg_desc){...}); - sgl_setup(&(sgl_desc){...}); - - --- Create at least one fontstash context with sfons_create() (this replaces - glfonsCreate() from fontstash.h's example GL renderer: - - FONScontext* ctx = sfons_create(&(sfons_desc_t){ - .width = atlas_width, - .height = atlas_height, - }); - - Each FONScontext manages one font atlas texture which can hold rasterized - glyphs for multiple fonts. - - --- From here on, use fontstash.h's functions "as usual" to add TTF - font data and draw text. Note that (just like with sokol-gl), text - rendering can happen anywhere in the frame, not only inside - a sokol-gfx rendering pass. - - --- You can use the helper function - - uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - - To convert a 0..255 RGBA color into a packed uint32_t color value - expected by fontstash.h. - - --- Once per frame before calling sgl_draw(), call: - - sfons_flush(FONScontext* ctx) - - ...this will update the dynamic sokol-gfx texture with the latest font - atlas content. - - --- To actually render the text (and any other sokol-gl draw commands), - call sgl_draw() inside a sokol-gfx frame. - - --- NOTE that you can mix fontstash.h calls with sokol-gl calls to mix - text rendering with sokol-gl rendering. You can also use - sokol-gl's matrix stack to position fontstash.h text in 3D. - - --- finally on application shutdown, call: - - sfons_destroy(FONScontext* ctx) - - before sgl_shutdown() and sg_shutdown() - - - WHAT HAPPENS UNDER THE HOOD: - ============================ - - FONScontext* sfons_create(const sfons_desc_t* desc) - - creates a sokol-gfx shader compatible with sokol-gl - - creates an sgl_pipeline object with alpha-blending using - this shader - - creates a 1-byte-per-pixel font atlas texture via sokol-gfx - (pixel format SG_PIXELFORMAT_R8) - - fonsDrawText(): - - this will call the following sequence of sokol-gl functions: - - sgl_enable_texture(); - sgl_texture(...); - sgl_push_pipeline(); - sgl_load_pipeline(...); - sgl_begin_triangles(); - for each vertex: - sgl_v2f_t2f_c1i(...); - sgl_end(); - sgl_pop_pipeline(); - sgl_disable_texture(); - - - note that sokol-gl will merge several sgl_*_begin/sgl_end pairs - into a single draw call if no relevant state has changed, typically - all calls to fonsDrawText() will be merged into a single draw call - as long as all calls use the same FONScontext - - sfons_flush(FONScontext* ctx): - - this will call sg_update_image() on the font atlas texture - if fontstash.h has added any rasterized glyphs since the last - frame - - sfons_destroy(FONScontext* ctx): - - destroy the font atlas texture, sgl_pipeline and sg_shader objects - - - MEMORY ALLOCATION OVERRIDE - ========================== - You can override the memory allocation functions at initialization time - like this: - - void* my_alloc(size_t size, void* user_data) { - return malloc(size); - } - - void my_free(void* ptr, void* user_data) { - free(ptr); - } - - ... - FONScontext* fons_context = sfons_create(&(sfons_desc_t){ - ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }); - ... - - If no overrides are provided, malloc and free will be used. Please - note that this doesn't affect any memory allocation performed - in fontstash.h (unfortunately those are hardwired to malloc/free). - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2018 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_FONTSTASH_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_fontstash.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_FONTSTASH_API_DECL) -#define SOKOL_FONTSTASH_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_FONTSTASH_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_FONTSTASH_IMPL) -#define SOKOL_FONTSTASH_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_FONTSTASH_API_DECL __declspec(dllimport) -#else -#define SOKOL_FONTSTASH_API_DECL extern -#endif -#endif -#ifdef __cplusplus -extern "C" { -#endif - -/* - sfonst_allocator_t - - Used in sfons_desc_t to provide custom memory-alloc and -free functions - to sokol_fontstash.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). - - NOTE that this does not affect memory allocation calls inside - fontstash.h -*/ -typedef struct sfons_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sfons_allocator_t; - -typedef struct sfons_desc_t { - int width; // initial width of font atlas texture (default: 512, must be power of 2) - int height; // initial height of font atlas texture (default: 512, must be power of 2) - sfons_allocator_t allocator; // optional memory allocation overrides -} sfons_desc_t; - -SOKOL_FONTSTASH_API_DECL FONScontext* sfons_create(const sfons_desc_t* desc); -SOKOL_FONTSTASH_API_DECL void sfons_destroy(FONScontext* ctx); -SOKOL_FONTSTASH_API_DECL void sfons_flush(FONScontext* ctx); -SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif /* SOKOL_FONTSTASH_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_FONTSTASH_IMPL -#define SOKOL_FONTSTASH_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sfons_desc_t.allocator to override memory allocation functions" -#endif - -#include // memset, memcpy -#include // malloc, free - -#if !defined(SOKOL_GL_INCLUDED) -#error "Please include sokol_gl.h before sokol_fontstash.h" -#endif -#if !defined(FONS_H) -#error "Please include fontstash.h before sokol_fontstash.h" -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#if defined(SOKOL_GLCORE33) -/* - Embedded source code compiled with: - - sokol-shdc -i sfons.glsl -o sfons.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - uniform mat4 mvp; - uniform mat4 tm; - }; - in vec4 position; - in vec2 texcoord0; - in vec4 color0; - in float psize; - out vec4 uv; - out vec4 color; - void main() { - gl_Position = mvp * position; - #ifndef SOKOL_WGSL - gl_PointSize = psize; - #endif - uv = tm * vec4(texcoord0, 0.0, 1.0); - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec4 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = vec4(1.0, 1.0, 1.0, texture(sampler2D(tex, smp), uv.xy).r) * color; - } - @end - - @program sfontstash vs fs -*/ -static const char _sfons_vs_source_glsl330[478] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69, - 0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30, - 0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a, - 0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34, - 0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sfons_fs_source_glsl330[203] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76, - 0x65,0x63,0x34,0x28,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e, - 0x30,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73, - 0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e,0x78,0x79,0x29,0x2e,0x78,0x29,0x20,0x2a,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const char _sfons_vs_source_glsl300es[481] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x20,0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74, - 0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b, - 0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20, - 0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70, - 0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d, - 0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65, - 0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e, - 0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -static const char _sfons_fs_source_glsl300es[276] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x31,0x2e,0x30, - 0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e, - 0x78,0x79,0x29,0x2e,0x78,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sfons_vs_bytecode_metal_macos[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x76,0x25,0x5f,0x37,0x22,0xd0,0x3f, - 0x64,0xef,0xff,0xc3,0x45,0x1a,0x3d,0xb7,0x5e,0x83,0x13,0x96,0xd3,0x09,0xec,0x53, - 0x25,0xd5,0x7e,0x0c,0xed,0xb9,0x58,0x34,0x02,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc4,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xee,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x81,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x18,0x42, - 0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40, - 0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04,0x60,0x89,0x10,0x02, - 0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2,0x50,0x0f,0xe3,0x40, - 0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0,0x07,0xed,0x10,0x0e, - 0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x49, - 0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28,0x86,0x08,0x23,0x80, - 0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80,0xc2,0x20,0x42,0x20, - 0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0xc8,0x02,0x01,0x00,0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18, - 0x50,0x08,0x65,0x50,0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x34, - 0x01,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32, - 0x28,0x00,0xb3,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0x81,0x22,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25, - 0x58,0x90,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82, - 0x45,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04, - 0x65,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba, - 0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61, - 0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde, - 0xc2,0xe8,0x68,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95, - 0x51,0xa8,0xb3,0x1b,0xc2,0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9, - 0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26, - 0x37,0x84,0x51,0x1e,0xc5,0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7, - 0x02,0xf7,0x36,0x97,0x46,0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e, - 0x8d,0x2e,0xed,0xcd,0x6d,0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2, - 0xd2,0xe4,0x5c,0xe0,0xde,0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1, - 0xbd,0x85,0xd1,0x91,0x39,0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b, - 0x1b,0xa2,0x28,0x9c,0x12,0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9, - 0x94,0x8f,0x50,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b, - 0x5c,0x1d,0x1d,0xa5,0xb0,0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7, - 0xaf,0x34,0x37,0xb2,0x32,0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64, - 0x28,0x5f,0x5f,0x61,0x69,0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64, - 0x65,0x72,0x5f,0x5f,0x29,0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50, - 0x8b,0xa0,0x84,0x81,0x22,0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93, - 0x42,0x06,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd, - 0xc9,0x91,0xc1,0x0c,0xa1,0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31, - 0x50,0x22,0xc5,0x0c,0x94,0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43, - 0xa8,0x65,0x50,0xc2,0x40,0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94, - 0x49,0x49,0x03,0x16,0x70,0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11, - 0x83,0xc5,0x58,0x02,0x65,0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69, - 0x72,0x2e,0x62,0x75,0x66,0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc, - 0xcc,0xca,0xe4,0xbe,0xe6,0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85, - 0x91,0x91,0x0a,0x4b,0x93,0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83, - 0x2b,0xfb,0x4a,0x73,0x33,0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3, - 0xa1,0xcd,0x0e,0x8e,0x02,0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50, - 0xe4,0x60,0x21,0x16,0x62,0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b, - 0x98,0xdc,0xd9,0x17,0x5d,0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34, - 0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7, - 0xaf,0xb9,0x34,0xbd,0x32,0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c, - 0xbe,0x62,0x72,0x86,0x90,0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0, - 0x08,0x4b,0xa0,0xbc,0x81,0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c, - 0x89,0x12,0x29,0x77,0xa0,0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51, - 0x03,0x85,0x0d,0x94,0x3c,0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b, - 0x73,0x4b,0x83,0x7b,0xa3,0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95, - 0xd6,0x06,0xc7,0x56,0x06,0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50, - 0xfa,0x60,0x88,0xa1,0xf0,0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83, - 0x46,0x19,0x11,0xb1,0x03,0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4, - 0x03,0x3b,0x94,0x83,0x1b,0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18, - 0x46,0x28,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40, - 0x0f,0x53,0x82,0x62,0xc4,0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f, - 0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e, - 0xc0,0x0e,0xe1,0xe0,0x0e,0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50, - 0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e, - 0xf2,0xe0,0x06,0xe3,0xf0,0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef, - 0x00,0x0f,0xf4,0x90,0x0e,0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12, - 0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25, - 0xd8,0x03,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00, - 0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22, - 0x86,0x61,0x18,0xc6,0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40, - 0x19,0x14,0x01,0xbd,0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00, - 0x00,0xe3,0x15,0x4b,0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9, - 0x8c,0x57,0x3c,0x55,0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63, - 0x41,0x01,0x9f,0xf1,0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43, - 0x99,0x10,0xc8,0xc7,0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50, - 0x06,0x19,0xbe,0x48,0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68, - 0x03,0x36,0x20,0x03,0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b, - 0xc4,0x00,0x0d,0xe2,0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42, - 0x20,0x1f,0x0b,0x0a,0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05, - 0xc5,0x86,0x00,0x3e,0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d, - 0xc1,0x23,0xcc,0x36,0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00, - 0x00,0x5b,0x86,0x20,0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61, - 0xcb,0xf0,0x04,0xa0,0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19, - 0xba,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_fs_bytecode_metal_macos[2857] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x29,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x50,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x38,0x3c,0x07,0x7d,0xe0,0x21,0x6b, - 0x04,0x03,0x36,0x12,0x1d,0xbc,0x24,0x12,0xc4,0x27,0xab,0xef,0x84,0x17,0xbe,0x12, - 0x8d,0xc7,0xbc,0x06,0xbc,0x98,0x53,0xdb,0x0b,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x30,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x89,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xb2,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83, - 0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78, - 0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90, - 0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76, - 0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20, - 0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07, - 0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71, - 0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20, - 0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f, - 0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76, - 0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50, - 0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78, - 0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x41,0x00,0x00,0x08,0x00, - 0x00,0x00,0x00,0x00,0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64, - 0x81,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50, - 0x10,0x65,0x40,0x70,0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb7,0x00,0x00, - 0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37, - 0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b, - 0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c, - 0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26, - 0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac, - 0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0, - 0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79, - 0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6, - 0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6, - 0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62, - 0x6c,0x65,0x43,0x84,0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5, - 0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99, - 0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86, - 0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59, - 0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f, - 0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c, - 0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd, - 0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08, - 0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b, - 0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c, - 0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72, - 0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x14,0xea,0xec,0x86, - 0x48,0xcb,0xf0,0x58,0xcf,0xf5,0x60,0x4f,0xf6,0x40,0x4f,0xf4,0x48,0x8f,0xc6,0xa5, - 0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x2d,0x26,0x85,0xc5,0xd8,0x1b,0xdb,0x9b, - 0xdc,0x10,0x69,0x11,0x1e,0xeb,0xe1,0x1e,0xec,0xc9,0x1e,0xe8,0x89,0x1e,0xe9,0xe9, - 0xb8,0x84,0xa5,0xc9,0xb9,0xd0,0x95,0xe1,0xd1,0xd5,0xc9,0x95,0x51,0x0a,0x4b,0x93, - 0x73,0x61,0x7b,0x1b,0x0b,0xa3,0x4b,0x7b,0x73,0xfb,0x4a,0x73,0x23,0x2b,0xc3,0xa3, - 0x12,0x96,0x26,0xe7,0x32,0x17,0xd6,0x06,0xc7,0x56,0x46,0x8c,0xae,0x0c,0x8f,0xae, - 0x4e,0xae,0x4c,0x86,0x8c,0xc7,0x8c,0xed,0x2d,0x8c,0x8e,0x05,0x64,0x2e,0xac,0x0d, - 0x8e,0xad,0xcc,0x87,0x03,0x5d,0x19,0xde,0x10,0x6a,0x21,0x9e,0xef,0x01,0x83,0x65, - 0x58,0x84,0x27,0x0c,0x1e,0xe8,0x11,0x83,0x47,0x7a,0xc6,0x80,0x4b,0x58,0x9a,0x9c, - 0xcb,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x8f,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39, - 0x0e,0x73,0x6d,0x70,0x43,0xa4,0xe5,0x78,0xca,0xe0,0x01,0x83,0x65,0x58,0x84,0x07, - 0x7a,0xcc,0xe0,0x91,0x9e,0x33,0x18,0x82,0x3c,0xdb,0xe3,0x3d,0x64,0xf0,0xa0,0xc1, - 0x10,0x03,0x01,0x9e,0xea,0x49,0x83,0x11,0x11,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b, - 0xb4,0xc3,0x3b,0x90,0x43,0x3d,0xb0,0x43,0x39,0xb8,0x81,0x39,0xb0,0x43,0x38,0x9c, - 0xc3,0x3c,0x4c,0x11,0x82,0x61,0x84,0xc2,0x0e,0xec,0x60,0x0f,0xed,0xe0,0x06,0xe9, - 0x40,0x0e,0xe5,0xe0,0x0e,0xf4,0x30,0x25,0x28,0x46,0x2c,0xe1,0x90,0x0e,0xf2,0xe0, - 0x06,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x30,0x46,0x50, - 0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xec,0x10,0x0e,0xee,0x70,0x0e,0xf5,0x10,0x0e,0xe7, - 0x50,0x0e,0xbf,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02, - 0x64,0xc4,0x14,0x0e,0xe9,0x20,0x0f,0x6e,0x30,0x0e,0xef,0xd0,0x0e,0xf0,0x90,0x0e, - 0xec,0x50,0x0e,0xbf,0xf0,0x0e,0xf0,0x40,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x0f,0x53, - 0x06,0x85,0x71,0x46,0x30,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe6,0x20,0x0f,0xe1,0x70, - 0x0e,0xed,0x50,0x0e,0xee,0x40,0x0f,0x53,0x02,0x35,0x00,0x00,0x00,0x79,0x18,0x00, - 0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d, - 0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c, - 0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d, - 0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d, - 0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79, - 0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc, - 0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50, - 0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30, - 0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03, - 0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07, - 0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76, - 0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98, - 0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8, - 0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21, - 0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43, - 0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f, - 0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70, - 0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0, - 0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40, - 0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41, - 0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e, - 0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07, - 0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f, - 0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d, - 0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38, - 0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88, - 0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08, - 0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50, - 0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01, - 0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03, - 0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c, - 0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00, - 0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d, - 0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x16,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x14,0xc7,0x22, - 0x80,0x40,0x20,0x88,0x8d,0x00,0x8c,0x25,0x00,0x01,0xa9,0x11,0x80,0x1a,0x20,0x31, - 0x03,0x40,0x61,0x0e,0xe2,0xba,0xae,0x6a,0x06,0x80,0xc0,0x0c,0xc0,0x08,0xc0,0x18, - 0x01,0x08,0x82,0x20,0xfe,0x01,0x00,0x00,0x00,0x83,0x0c,0x0f,0x91,0x8c,0x18,0x28, - 0x42,0x80,0x39,0x4d,0x80,0x2c,0xc9,0x30,0xc8,0x70,0x04,0x8d,0x05,0x91,0x7c,0x66, - 0x1b,0x94,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_vs_bytecode_metal_ios[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x17,0x11,0x57,0x16,0x94,0x42,0x52, - 0xfb,0x1e,0xd0,0x32,0xfd,0x87,0x16,0xb0,0xa4,0xd0,0xc2,0x43,0xbe,0x93,0x8c,0xe0, - 0x2d,0x7a,0x5c,0x3e,0x06,0x4c,0x57,0xeb,0x4b,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc0,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xed,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x82,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x20,0x42, - 0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00, - 0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48, - 0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90, - 0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04, - 0x60,0x89,0x10,0x02,0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2, - 0x50,0x0f,0xe3,0x40,0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0, - 0x07,0xed,0x10,0x0e,0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44, - 0x09,0x93,0x5f,0x49,0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28, - 0x86,0x08,0x23,0x80,0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80, - 0xc2,0x20,0x42,0x20,0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18,0x50,0x08,0x65,0x50, - 0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x40,0x02,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28,0x00,0xb3,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0x81,0x22,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58,0x90,0x45,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d, - 0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6, - 0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79, - 0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x68,0xc8,0x84, - 0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2, - 0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61, - 0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26,0x37,0x84,0x51,0x1e,0xc5, - 0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7,0x02,0xf7,0x36,0x97,0x46, - 0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x6d, - 0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2,0xd2,0xe4,0x5c,0xe0,0xde, - 0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1,0xbd,0x85,0xd1,0x91,0x39, - 0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b,0x1b,0xa2,0x28,0x9c,0x12, - 0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9,0x94,0x8f,0x50,0x58,0x9a, - 0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b,0x5c,0x1d,0x1d,0xa5,0xb0, - 0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7,0xaf,0x34,0x37,0xb2,0x32, - 0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x28,0x5f,0x5f,0x61,0x69, - 0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,0x5f,0x5f,0x29, - 0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50,0x8b,0xa0,0x84,0x81,0x22, - 0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93,0x42,0x06,0x34,0xcc,0xd8, - 0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd,0xc9,0x91,0xc1,0x0c,0xa1, - 0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31,0x50,0x22,0xc5,0x0c,0x94, - 0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65,0x50,0xc2,0x40, - 0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94,0x49,0x49,0x03,0x16,0x70, - 0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11,0x83,0xc5,0x58,0x02,0x65, - 0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69,0x72,0x2e,0x62,0x75,0x66, - 0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc,0xcc,0xca,0xe4,0xbe,0xe6, - 0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85,0x91,0x91,0x0a,0x4b,0x93, - 0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83,0x2b,0xfb,0x4a,0x73,0x33, - 0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3,0xa1,0xcd,0x0e,0x8e,0x02, - 0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50,0xe4,0x60,0x21,0x16,0x62, - 0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b,0x98,0xdc,0xd9,0x17,0x5d, - 0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3, - 0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7,0xaf,0xb9,0x34,0xbd,0x32, - 0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c,0xbe,0x62,0x72,0x86,0x90, - 0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0,0x08,0x4b,0xa0,0xbc,0x81, - 0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c,0x89,0x12,0x29,0x77,0xa0, - 0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51,0x03,0x85,0x0d,0x94,0x3c, - 0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b,0x73,0x4b,0x83,0x7b,0xa3, - 0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95,0xd6,0x06,0xc7,0x56,0x06, - 0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50,0xfa,0x60,0x88,0xa1,0xf0, - 0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83,0x46,0x19,0x11,0xb1,0x03, - 0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4,0x03,0x3b,0x94,0x83,0x1b, - 0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18,0x46,0x28,0xec,0xc0,0x0e, - 0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40,0x0f,0x53,0x82,0x62,0xc4, - 0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0, - 0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e,0xc0,0x0e,0xe1,0xe0,0x0e, - 0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9, - 0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe3,0xf0, - 0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef,0x00,0x0f,0xf4,0x90,0x0e, - 0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12,0x0e,0xe9,0x20,0x0f,0x6e, - 0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25,0xd8,0x03,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30, - 0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22,0x86,0x61,0x18,0xc6, - 0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40,0x19,0x14,0x01,0xbd, - 0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00,0x00,0xe3,0x15,0x4b, - 0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9,0x8c,0x57,0x3c,0x55, - 0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1, - 0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43,0x99,0x10,0xc8,0xc7, - 0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50,0x06,0x19,0xbe,0x48, - 0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68,0x03,0x36,0x20,0x03, - 0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b,0xc4,0x00,0x0d,0xe2, - 0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42,0x20,0x1f,0x0b,0x0a, - 0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05,0xc5,0x86,0x00,0x3e, - 0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d,0xc1,0x23,0xcc,0x36, - 0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00,0x00,0x5b,0x86,0x20, - 0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61,0xcb,0xf0,0x04,0xa0, - 0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19,0xba,0x00,0x14,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_fs_bytecode_metal_ios[2841] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x19,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x40,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x7c,0x59,0x61,0x85,0x8c,0x08,0x62, - 0xf6,0xd0,0x45,0x0a,0x3a,0xcb,0xa8,0xa5,0x3c,0x2d,0x6c,0x6b,0x9c,0x3d,0xf0,0xf5, - 0xc4,0xdc,0xb5,0x90,0xdc,0xee,0x5a,0x9f,0x63,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x28,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x87,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x18,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03, - 0x04,0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00, - 0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43, - 0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00, - 0x00,0x79,0x18,0x00,0x00,0xb7,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59, - 0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9, - 0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8, - 0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e, - 0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e, - 0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99, - 0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37, - 0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74, - 0x69,0x76,0x65,0x14,0xea,0xec,0x86,0x48,0xcb,0xf0,0x58,0xcf,0xf5,0x60,0x4f,0xf6, - 0x40,0x4f,0xf4,0x48,0x8f,0xc6,0xa5,0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x2d, - 0x26,0x85,0xc5,0xd8,0x1b,0xdb,0x9b,0xdc,0x10,0x69,0x11,0x1e,0xeb,0xe1,0x1e,0xec, - 0xc9,0x1e,0xe8,0x89,0x1e,0xe9,0xe9,0xb8,0x84,0xa5,0xc9,0xb9,0xd0,0x95,0xe1,0xd1, - 0xd5,0xc9,0x95,0x51,0x0a,0x4b,0x93,0x73,0x61,0x7b,0x1b,0x0b,0xa3,0x4b,0x7b,0x73, - 0xfb,0x4a,0x73,0x23,0x2b,0xc3,0xa3,0x12,0x96,0x26,0xe7,0x32,0x17,0xd6,0x06,0xc7, - 0x56,0x46,0x8c,0xae,0x0c,0x8f,0xae,0x4e,0xae,0x4c,0x86,0x8c,0xc7,0x8c,0xed,0x2d, - 0x8c,0x8e,0x05,0x64,0x2e,0xac,0x0d,0x8e,0xad,0xcc,0x87,0x03,0x5d,0x19,0xde,0x10, - 0x6a,0x21,0x9e,0xef,0x01,0x83,0x65,0x58,0x84,0x27,0x0c,0x1e,0xe8,0x11,0x83,0x47, - 0x7a,0xc6,0x80,0x4b,0x58,0x9a,0x9c,0xcb,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x8f, - 0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39,0x0e,0x73,0x6d,0x70,0x43,0xa4,0xe5,0x78,0xca, - 0xe0,0x01,0x83,0x65,0x58,0x84,0x07,0x7a,0xcc,0xe0,0x91,0x9e,0x33,0x18,0x82,0x3c, - 0xdb,0xe3,0x3d,0x64,0xf0,0xa0,0xc1,0x10,0x03,0x01,0x9e,0xea,0x49,0x83,0x11,0x11, - 0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xb4,0xc3,0x3b,0x90,0x43,0x3d,0xb0,0x43,0x39, - 0xb8,0x81,0x39,0xb0,0x43,0x38,0x9c,0xc3,0x3c,0x4c,0x11,0x82,0x61,0x84,0xc2,0x0e, - 0xec,0x60,0x0f,0xed,0xe0,0x06,0xe9,0x40,0x0e,0xe5,0xe0,0x0e,0xf4,0x30,0x25,0x28, - 0x46,0x2c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9,0xf0, - 0x0e,0xee,0x30,0x25,0x30,0x46,0x50,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xec,0x10,0x0e, - 0xee,0x70,0x0e,0xf5,0x10,0x0e,0xe7,0x50,0x0e,0xbf,0x60,0x0f,0xe5,0x20,0x0f,0xf3, - 0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x64,0xc4,0x14,0x0e,0xe9,0x20,0x0f,0x6e,0x30, - 0x0e,0xef,0xd0,0x0e,0xf0,0x90,0x0e,0xec,0x50,0x0e,0xbf,0xf0,0x0e,0xf0,0x40,0x0f, - 0xe9,0xf0,0x0e,0xee,0x30,0x0f,0x53,0x06,0x85,0x71,0x46,0x30,0xe1,0x90,0x0e,0xf2, - 0xe0,0x06,0xe6,0x20,0x0f,0xe1,0x70,0x0e,0xed,0x50,0x0e,0xee,0x40,0x0f,0x53,0x02, - 0x35,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00, - 0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45, - 0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00, - 0x00,0x61,0x20,0x00,0x00,0x16,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x14,0xc7,0x22,0x80,0x40,0x20,0x88,0x8d,0x00,0x8c,0x25, - 0x00,0x01,0xa9,0x11,0x80,0x1a,0x20,0x31,0x03,0x40,0x61,0x0e,0xe2,0xba,0xae,0x6a, - 0x06,0x80,0xc0,0x0c,0xc0,0x08,0xc0,0x18,0x01,0x08,0x82,0x20,0xfe,0x01,0x00,0x00, - 0x00,0x83,0x0c,0x0f,0x91,0x8c,0x18,0x28,0x42,0x80,0x39,0x4d,0x80,0x2c,0xc9,0x30, - 0xc8,0x70,0x04,0x8d,0x05,0x91,0x7c,0x66,0x1b,0x94,0x00,0xc8,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const char _sfons_vs_source_metal_sim[756] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x74,0x6d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, - 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a, - 0x65,0x20,0x5b,0x5b,0x70,0x6f,0x69,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x5d,0x5d, - 0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74, - 0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72, - 0x64,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75, - 0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69, - 0x62,0x75,0x74,0x65,0x28,0x33,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76, - 0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69, - 0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20, - 0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72, - 0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20,0x2a, - 0x20,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69, - 0x7a,0x65,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20, - 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e, - 0x74,0x6d,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31, - 0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -static const char _sfons_fs_source_metal_sim[464] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x28,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e, - 0x30,0x2c,0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d, - 0x70,0x2c,0x20,0x69,0x6e,0x2e,0x75,0x76,0x2e,0x78,0x79,0x29,0x2e,0x78,0x29,0x20, - 0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sfons_vs_bytecode_hlsl4[1032] = { - 0x44,0x58,0x42,0x43,0x74,0x7f,0x01,0xd9,0xf4,0xd5,0xed,0x1d,0x74,0xc1,0x30,0x27, - 0xd8,0xe9,0x9d,0x50,0x01,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x02,0x00,0x00, - 0x8c,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xd8,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0xaf,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f, - 0x6d,0x76,0x70,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f,0x74,0x6d,0x00,0x4d,0x69,0x63,0x72,0x6f, - 0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68, - 0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30, - 0x2e,0x31,0x00,0xab,0x49,0x53,0x47,0x4e,0x74,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x68,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x84,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x61,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x56,0x15,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x36,0x00,0x00,0x05, - 0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00, - 0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x56,0x15,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0xa6,0x1a,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0xf6,0x1f,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54, - 0x74,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_fs_bytecode_hlsl4[628] = { - 0x44,0x58,0x42,0x43,0xb6,0x66,0xf0,0xfc,0x09,0x54,0x2a,0x35,0x84,0x1d,0x27,0xd2, - 0xff,0xb3,0x2e,0xdb,0x01,0x00,0x00,0x00,0x74,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xf8,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0xa8,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x96,0x73,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0x12,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x01,0x40,0x00,0x00,0x00,0x00,0x80,0x3f,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00, - 0x00,0x00,0x00,0x00,0x06,0x0c,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00, - 0x01,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_WGPU) -static const char _sfons_vs_source_wgsl[1162] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x6d,0x76,0x70,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78,0x34,0x66,0x2c,0x0a, - 0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x36,0x34,0x29, - 0x20,0x2a,0x2f,0x0a,0x20,0x20,0x74,0x6d,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78, - 0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29, - 0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76,0x61,0x72, - 0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x66,0x33,0x32,0x3b,0x0a,0x0a, - 0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b, - 0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x32,0x20,0x3a,0x20,0x6d,0x61, - 0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x35,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f, - 0x31,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x32,0x20,0x2a,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x32,0x20,0x3a,0x20,0x6d, - 0x61,0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x74,0x6d, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x36,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x28,0x78,0x5f,0x33,0x32,0x20,0x2a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x33,0x36,0x2e,0x78,0x2c,0x20,0x78, - 0x5f,0x33,0x36,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30, - 0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x35,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x35, - 0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73, - 0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b, - 0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a, - 0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c, - 0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x33,0x29,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x66,0x33,0x32,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65, - 0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x70,0x73,0x69,0x7a,0x65,0x20, - 0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74, - 0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sfons_fs_source_wgsl[674] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x36,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x78,0x5f,0x32,0x34,0x2e,0x78, - 0x2c,0x20,0x78,0x5f,0x32,0x34,0x2e,0x79,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x33,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x34,0x66,0x28,0x31,0x2e, - 0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x2c,0x20, - 0x78,0x5f,0x32,0x36,0x2e,0x78,0x29,0x20,0x2a,0x20,0x78,0x5f,0x33,0x32,0x29,0x3b, - 0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74, - 0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a, - 0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20, - 0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66,0x72,0x61,0x67,0x6d, - 0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63, - 0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20, - 0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x75,0x76,0x20, - 0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20, - 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74, - 0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a, - 0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sfons_vs_source_dummy = ""; -static const char* _sfons_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -typedef struct _sfons_t { - sfons_desc_t desc; - sg_shader shd; - sgl_pipeline pip; - sg_image img; - sg_sampler smp; - int cur_width, cur_height; - bool img_dirty; -} _sfons_t; - -static void _sfons_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _sfons_malloc(const sfons_allocator_t* allocator, size_t size) { - SOKOL_ASSERT(allocator && (size > 0)); - void* ptr; - if (allocator->alloc_fn) { - ptr = allocator->alloc_fn(size, allocator->user_data); - } else { - ptr = malloc(size); - } - SOKOL_ASSERT(ptr); - return ptr; -} - -static void* _sfons_malloc_clear(const sfons_allocator_t* allocator, size_t size) { - void* ptr = _sfons_malloc(allocator, size); - _sfons_clear(ptr, size); - return ptr; -} - -static void _sfons_free(const sfons_allocator_t* allocator, void* ptr) { - SOKOL_ASSERT(allocator); - if (allocator->free_fn) { - allocator->free_fn(ptr, allocator->user_data); - } else { - free(ptr); - } -} - -static int _sfons_render_create(void* user_ptr, int width, int height) { - SOKOL_ASSERT(user_ptr && (width > 8) && (height > 8)); - _sfons_t* sfons = (_sfons_t*) user_ptr; - - // sokol-gl compatible shader which treats RED channel as alpha - if (sfons->shd.id == SG_INVALID_ID) { - sg_shader_desc shd_desc; - _sfons_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[3].name = "psize"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.attrs[3].sem_name = "TEXCOORD"; - shd_desc.attrs[3].sem_index = 3; - sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; - ub->size = 128; - ub->uniforms[0].name = "vs_params"; - ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - ub->uniforms[0].array_count = 8; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.label = "sokol-fontstash-shader"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _sfons_vs_source_glsl330; - shd_desc.fs.source = _sfons_fs_source_glsl330; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _sfons_vs_source_glsl300es; - shd_desc.fs.source = _sfons_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = _sfons_vs_source_metal_sim; - shd_desc.fs.source = _sfons_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _sfons_vs_source_wgsl; - shd_desc.fs.source = _sfons_fs_source_wgsl; - #else - shd_desc.vs.source = _sfons_vs_source_dummy; - shd_desc.fs.source = _sfons_fs_source_dummy; - #endif - shd_desc.label = "sfons-shader"; - sfons->shd = sg_make_shader(&shd_desc); - } - - // sokol-gl pipeline object - if (sfons->pip.id == SG_INVALID_ID) { - sg_pipeline_desc pip_desc; - _sfons_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.shader = sfons->shd; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - sfons->pip = sgl_make_pipeline(&pip_desc); - } - - // a sampler object - if (sfons->smp.id == SG_INVALID_ID) { - sg_sampler_desc smp_desc; - _sfons_clear(&smp_desc, sizeof(smp_desc)); - smp_desc.min_filter = SG_FILTER_LINEAR; - smp_desc.mag_filter = SG_FILTER_LINEAR; - smp_desc.mipmap_filter = SG_FILTER_NONE; - sfons->smp = sg_make_sampler(&smp_desc); - } - - // create or re-create font atlas texture - if (sfons->img.id != SG_INVALID_ID) { - sg_destroy_image(sfons->img); - sfons->img.id = SG_INVALID_ID; - } - sfons->cur_width = width; - sfons->cur_height = height; - - SOKOL_ASSERT(sfons->img.id == SG_INVALID_ID); - sg_image_desc img_desc; - _sfons_clear(&img_desc, sizeof(img_desc)); - img_desc.width = sfons->cur_width; - img_desc.height = sfons->cur_height; - img_desc.usage = SG_USAGE_DYNAMIC; - img_desc.pixel_format = SG_PIXELFORMAT_R8; - sfons->img = sg_make_image(&img_desc); - return 1; -} - -static int _sfons_render_resize(void* user_ptr, int width, int height) { - return _sfons_render_create(user_ptr, width, height); -} - -static void _sfons_render_update(void* user_ptr, int* rect, const unsigned char* data) { - SOKOL_ASSERT(user_ptr && rect && data); - _SOKOL_UNUSED(rect); - _SOKOL_UNUSED(data); - _sfons_t* sfons = (_sfons_t*) user_ptr; - sfons->img_dirty = true; -} - -static void _sfons_render_draw(void* user_ptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) { - SOKOL_ASSERT(user_ptr && verts && tcoords && colors && (nverts > 0)); - _sfons_t* sfons = (_sfons_t*) user_ptr; - sgl_enable_texture(); - sgl_texture(sfons->img, sfons->smp); - sgl_push_pipeline(); - sgl_load_pipeline(sfons->pip); - sgl_begin_triangles(); - for (int i = 0; i < nverts; i++) { - sgl_v2f_t2f_c1i(verts[2*i+0], verts[2*i+1], tcoords[2*i+0], tcoords[2*i+1], colors[i]); - } - sgl_end(); - sgl_pop_pipeline(); - sgl_disable_texture(); -} - -static void _sfons_render_delete(void* user_ptr) { - SOKOL_ASSERT(user_ptr); - _sfons_t* sfons = (_sfons_t*) user_ptr; - if (sfons->img.id != SG_INVALID_ID) { - sg_destroy_image(sfons->img); - sfons->img.id = SG_INVALID_ID; - } - if (sfons->smp.id != SG_INVALID_ID) { - sg_destroy_sampler(sfons->smp); - sfons->smp.id = SG_INVALID_ID; - } - if (sfons->pip.id != SG_INVALID_ID) { - sgl_destroy_pipeline(sfons->pip); - sfons->pip.id = SG_INVALID_ID; - } - if (sfons->shd.id != SG_INVALID_ID) { - sg_destroy_shader(sfons->shd); - sfons->shd.id = SG_INVALID_ID; - } -} - -#define _sfons_def(val, def) (((val) == 0) ? (def) : (val)) - -static sfons_desc_t _sfons_desc_defaults(const sfons_desc_t* desc) { - SOKOL_ASSERT(desc); - sfons_desc_t res = *desc; - res.width = _sfons_def(res.width, 512); - res.height = _sfons_def(res.height, 512); - return res; -} - -SOKOL_API_IMPL FONScontext* sfons_create(const sfons_desc_t* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - _sfons_t* sfons = (_sfons_t*) _sfons_malloc_clear(&desc->allocator, sizeof(_sfons_t)); - sfons->desc = _sfons_desc_defaults(desc); - FONSparams params; - _sfons_clear(¶ms, sizeof(params)); - params.width = sfons->desc.width; - params.height = sfons->desc.height; - params.flags = FONS_ZERO_TOPLEFT; - params.renderCreate = _sfons_render_create; - params.renderResize = _sfons_render_resize; - params.renderUpdate = _sfons_render_update; - params.renderDraw = _sfons_render_draw; - params.renderDelete = _sfons_render_delete; - params.userPtr = sfons; - return fonsCreateInternal(¶ms); -} - -SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) { - SOKOL_ASSERT(ctx); - _sfons_t* sfons = (_sfons_t*) ctx->params.userPtr; - fonsDeleteInternal(ctx); - const sfons_allocator_t allocator = sfons->desc.allocator; - _sfons_free(&allocator, sfons); -} - -SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) { - SOKOL_ASSERT(ctx && ctx->params.userPtr); - _sfons_t* sfons = (_sfons_t*) ctx->params.userPtr; - if (sfons->img_dirty) { - sfons->img_dirty = false; - sg_image_data data; - _sfons_clear(&data, sizeof(data)); - data.subimage[0][0].ptr = ctx->texData; - data.subimage[0][0].size = (size_t) (sfons->cur_width * sfons->cur_height); - sg_update_image(sfons->img, &data); - } -} - -SOKOL_API_IMPL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return ((uint32_t)r) | ((uint32_t)g<<8) | ((uint32_t)b<<16) | ((uint32_t)a<<24); -} - -#endif // SOKOL_FONTSTASH_IMPL diff --git a/source/engine/thirdparty/sokol/util/sokol_gfx_imgui.h b/source/engine/thirdparty/sokol/util/sokol_gfx_imgui.h deleted file mode 100644 index eed45e3..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_gfx_imgui.h +++ /dev/null @@ -1,4720 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMGUI_IMPL) -#define SOKOL_GFX_IMGUI_IMPL -#endif -#ifndef SOKOL_GFX_IMGUI_INCLUDED -/* - sokol_gfx_imgui.h -- debug-inspection UI for sokol_gfx.h using Dear ImGui - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_GFX_IMGUI_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - NOTE that the implementation can be compiled either as C++ or as C. - When compiled as C++, sokol_gfx_imgui.h will directly call into the - Dear ImGui C++ API. When compiled as C, sokol_gfx_imgui.h will call - cimgui.h functions instead. - - Include the following file(s) before including sokol_gfx_imgui.h: - - sokol_gfx.h - - Additionally, include the following headers before including the - implementation: - - If the implementation is compiled as C++: - imgui.h - - If the implementation is compiled as C: - cimgui.h - - The sokol_gfx.h implementation must be compiled with debug trace hooks - enabled by defining: - - SOKOL_TRACE_HOOKS - - ...before including the sokol_gfx.h implementation. - - Before including the sokol_gfx_imgui.h implementation, optionally - override the following macros: - - SOKOL_ASSERT(c) -- your own assert macro, default: assert(c) - SOKOL_UNREACHABLE -- your own macro to annotate unreachable code, - default: SOKOL_ASSERT(false) - SOKOL_GFX_IMGUI_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_GFX_IMGUI_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_gfx_imgui.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_GFX_IMGUI_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - STEP BY STEP: - ============= - --- create an sgimgui_t struct (which must be preserved between frames) - and initialize it with: - - sgimgui_init(&sgimgui, &(sgimgui_desc_t){ 0 }); - - Note that from C++ you can't inline the desc structure initialization: - - const sgimgui_desc_t desc = { }; - sgimgui_init(&sgimgui, &desc); - - Provide optional memory allocator override functions (compatible with malloc/free) like this: - - sgimgui_init(&sgimgui, &(sgimgui_desc_t){ - .allocator = { - .alloc_fn = my_malloc, - .free_fn = my_free, - } - }); - - --- somewhere in the per-frame code call: - - sgimgui_draw(&sgimgui) - - this won't draw anything yet, since no windows are open. - - --- call the convenience function sgimgui_draw_menu(ctx, title) - to render a menu which allows to open/close the provided debug windows - - sgimgui_draw_menu(&sgimgui, "sokol-gfx"); - - --- alternative, open and close windows directly by setting the following public - booleans in the sgimgui_t struct: - - sgimgui.caps_window.open = true; - sgimgui.frame_stats_window.open = true; - sgimgui.buffer_window.open = true; - sgimgui.image_window.open = true; - sgimgui.sampler_window.open = true; - sgimgui.shader_window.open = true; - sgimgui.pipeline_window.open = true; - sgimgui.attachments_window.open = true; - sgimgui.capture_window.open = true; - sgimgui.frame_stats_window.open = true; - - ...for instance, to control the window visibility through - menu items, the following code can be used: - - if (ImGui::BeginMainMenuBar()) { - if (ImGui::BeginMenu("sokol-gfx")) { - ImGui::MenuItem("Capabilities", 0, &sgimgui.caps_window.open); - ImGui::MenuItem("Frame Stats", 0, &sgimgui.frame_stats_window.open); - ImGui::MenuItem("Buffers", 0, &sgimgui.buffer_window.open); - ImGui::MenuItem("Images", 0, &sgimgui.image_window.open); - ImGui::MenuItem("Samplers", 0, &sgimgui.sampler_window.open); - ImGui::MenuItem("Shaders", 0, &sgimgui.shader_window.open); - ImGui::MenuItem("Pipelines", 0, &sgimgui.pipeline_window.open); - ImGui::MenuItem("Attachments", 0, &sgimgui.attachments_window.open); - ImGui::MenuItem("Calls", 0, &sgimgui.capture_window.open); - ImGui::EndMenu(); - } - ImGui::EndMainMenuBar(); - } - - --- before application shutdown, call: - - sgimgui_discard(&sgimgui); - - ...this is not strictly necessary because the application exits - anyway, but not doing this may trigger memory leak detection tools. - - --- finally, your application needs an ImGui renderer, you can either - provide your own, or drop in the sokol_imgui.h utility header - - ALTERNATIVE DRAWING FUNCTIONS: - ============================== - Instead of the convenient, but all-in-one sgimgui_draw() function, - you can also use the following granular functions which might allow - better integration with your existing UI: - - The following functions only render the window *content* (so you - can integrate the UI into you own windows): - - void sgimgui_draw_buffer_window_content(sgimgui_t* ctx); - void sgimgui_draw_image_window_content(sgimgui_t* ctx); - void sgimgui_draw_sampler_window_content(sgimgui_t* ctx); - void sgimgui_draw_shader_window_content(sgimgui_t* ctx); - void sgimgui_draw_pipeline_window_content(sgimgui_t* ctx); - void sgimgui_draw_attachments_window_content(sgimgui_t* ctx); - void sgimgui_draw_capture_window_content(sgimgui_t* ctx); - - And these are the 'full window' drawing functions: - - void sgimgui_draw_buffer_window(sgimgui_t* ctx); - void sgimgui_draw_image_window(sgimgui_t* ctx); - void sgimgui_draw_sampler_window(sgimgui_t* ctx); - void sgimgui_draw_shader_window(sgimgui_t* ctx); - void sgimgui_draw_pipeline_window(sgimgui_t* ctx); - void sgimgui_draw_attachments_window(sgimgui_t* ctx); - void sgimgui_draw_capture_window(sgimgui_t* ctx); - - Finer-grained drawing functions may be moved to the public API - in the future as needed. - - MEMORY ALLOCATION OVERRIDE - ========================== - You can override the memory allocation functions at initialization time - like this: - - void* my_alloc(size_t size, void* user_data) { - return malloc(size); - } - - void my_free(void* ptr, void* user_data) { - free(ptr); - } - - ... - sgimgui_init(&(&ctx, &(sgimgui_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - This only affects memory allocation calls done by sokol_gfx_imgui.h - itself though, not any allocations in OS libraries. - - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2018 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_GFX_IMGUI_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_gfx_imgui.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GFX_IMGUI_API_DECL) -#define SOKOL_GFX_IMGUI_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_GFX_IMGUI_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GFX_IMGUI_IMPL) -#define SOKOL_GFX_IMGUI_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_GFX_IMGUI_API_DECL __declspec(dllimport) -#else -#define SOKOL_GFX_IMGUI_API_DECL extern -#endif -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -#define sgimgui_STRBUF_LEN (96) -/* max number of captured calls per frame */ -#define sgimgui_MAX_FRAMECAPTURE_ITEMS (4096) - -typedef struct sgimgui_str_t { - char buf[sgimgui_STRBUF_LEN]; -} sgimgui_str_t; - -typedef struct sgimgui_buffer_t { - sg_buffer res_id; - sgimgui_str_t label; - sg_buffer_desc desc; -} sgimgui_buffer_t; - -typedef struct sgimgui_image_t { - sg_image res_id; - float ui_scale; - sgimgui_str_t label; - sg_image_desc desc; - simgui_image_t simgui_img; -} sgimgui_image_t; - -typedef struct sgimgui_sampler_t { - sg_sampler res_id; - sgimgui_str_t label; - sg_sampler_desc desc; -} sgimgui_sampler_t; - -typedef struct sgimgui_shader_t { - sg_shader res_id; - sgimgui_str_t label; - sgimgui_str_t vs_entry; - sgimgui_str_t vs_d3d11_target; - sgimgui_str_t vs_image_sampler_name[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; - sgimgui_str_t vs_uniform_name[SG_MAX_SHADERSTAGE_UBS][SG_MAX_UB_MEMBERS]; - sgimgui_str_t fs_entry; - sgimgui_str_t fs_d3d11_target; - sgimgui_str_t fs_image_sampler_name[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; - sgimgui_str_t fs_uniform_name[SG_MAX_SHADERSTAGE_UBS][SG_MAX_UB_MEMBERS]; - sgimgui_str_t attr_name[SG_MAX_VERTEX_ATTRIBUTES]; - sgimgui_str_t attr_sem_name[SG_MAX_VERTEX_ATTRIBUTES]; - sg_shader_desc desc; -} sgimgui_shader_t; - -typedef struct sgimgui_pipeline_t { - sg_pipeline res_id; - sgimgui_str_t label; - sg_pipeline_desc desc; -} sgimgui_pipeline_t; - -typedef struct sgimgui_attachments_t { - sg_attachments res_id; - sgimgui_str_t label; - float color_image_scale[SG_MAX_COLOR_ATTACHMENTS]; - float resolve_image_scale[SG_MAX_COLOR_ATTACHMENTS]; - float ds_image_scale; - sg_attachments_desc desc; -} sgimgui_attachments_t; - -typedef struct sgimgui_buffer_window_t { - bool open; - int num_slots; - sg_buffer sel_buf; - sgimgui_buffer_t* slots; -} sgimgui_buffer_window_t; - -typedef struct sgimgui_image_window_t { - bool open; - int num_slots; - sg_image sel_img; - sgimgui_image_t* slots; -} sgimgui_image_window_t; - -typedef struct sgimgui_sampler_window_t { - bool open; - int num_slots; - sg_sampler sel_smp; - sgimgui_sampler_t* slots; -} sgimgui_sampler_window_t; - -typedef struct sgimgui_shader_window_t { - bool open; - int num_slots; - sg_shader sel_shd; - sgimgui_shader_t* slots; -} sgimgui_shader_window_t; - -typedef struct sgimgui_pipeline_window_t { - bool open; - int num_slots; - sg_pipeline sel_pip; - sgimgui_pipeline_t* slots; -} sgimgui_pipeline_window_t; - -typedef struct sgimgui_attachments_window_t { - bool open; - int num_slots; - sg_attachments sel_atts; - sgimgui_attachments_t* slots; -} sgimgui_attachments_window_t; - -typedef enum sgimgui_cmd_t { - SGIMGUI_CMD_INVALID, - SGIMGUI_CMD_RESET_STATE_CACHE, - SGIMGUI_CMD_MAKE_BUFFER, - SGIMGUI_CMD_MAKE_IMAGE, - SGIMGUI_CMD_MAKE_SAMPLER, - SGIMGUI_CMD_MAKE_SHADER, - SGIMGUI_CMD_MAKE_PIPELINE, - SGIMGUI_CMD_MAKE_ATTACHMENTS, - SGIMGUI_CMD_DESTROY_BUFFER, - SGIMGUI_CMD_DESTROY_IMAGE, - SGIMGUI_CMD_DESTROY_SAMPLER, - SGIMGUI_CMD_DESTROY_SHADER, - SGIMGUI_CMD_DESTROY_PIPELINE, - SGIMGUI_CMD_DESTROY_ATTACHMENTS, - SGIMGUI_CMD_UPDATE_BUFFER, - SGIMGUI_CMD_UPDATE_IMAGE, - SGIMGUI_CMD_APPEND_BUFFER, - SGIMGUI_CMD_BEGIN_PASS, - SGIMGUI_CMD_APPLY_VIEWPORT, - SGIMGUI_CMD_APPLY_SCISSOR_RECT, - SGIMGUI_CMD_APPLY_PIPELINE, - SGIMGUI_CMD_APPLY_BINDINGS, - SGIMGUI_CMD_APPLY_UNIFORMS, - SGIMGUI_CMD_DRAW, - SGIMGUI_CMD_END_PASS, - SGIMGUI_CMD_COMMIT, - SGIMGUI_CMD_ALLOC_BUFFER, - SGIMGUI_CMD_ALLOC_IMAGE, - SGIMGUI_CMD_ALLOC_SAMPLER, - SGIMGUI_CMD_ALLOC_SHADER, - SGIMGUI_CMD_ALLOC_PIPELINE, - SGIMGUI_CMD_ALLOC_ATTACHMENTS, - SGIMGUI_CMD_DEALLOC_BUFFER, - SGIMGUI_CMD_DEALLOC_IMAGE, - SGIMGUI_CMD_DEALLOC_SAMPLER, - SGIMGUI_CMD_DEALLOC_SHADER, - SGIMGUI_CMD_DEALLOC_PIPELINE, - SGIMGUI_CMD_DEALLOC_ATTACHMENTS, - SGIMGUI_CMD_INIT_BUFFER, - SGIMGUI_CMD_INIT_IMAGE, - SGIMGUI_CMD_INIT_SAMPLER, - SGIMGUI_CMD_INIT_SHADER, - SGIMGUI_CMD_INIT_PIPELINE, - SGIMGUI_CMD_INIT_ATTACHMENTS, - SGIMGUI_CMD_UNINIT_BUFFER, - SGIMGUI_CMD_UNINIT_IMAGE, - SGIMGUI_CMD_UNINIT_SAMPLER, - SGIMGUI_CMD_UNINIT_SHADER, - SGIMGUI_CMD_UNINIT_PIPELINE, - SGIMGUI_CMD_UNINIT_ATTACHMENTS, - SGIMGUI_CMD_FAIL_BUFFER, - SGIMGUI_CMD_FAIL_IMAGE, - SGIMGUI_CMD_FAIL_SAMPLER, - SGIMGUI_CMD_FAIL_SHADER, - SGIMGUI_CMD_FAIL_PIPELINE, - SGIMGUI_CMD_FAIL_ATTACHMENTS, - SGIMGUI_CMD_PUSH_DEBUG_GROUP, - SGIMGUI_CMD_POP_DEBUG_GROUP, -} sgimgui_cmd_t; - -typedef struct sgimgui_args_make_buffer_t { - sg_buffer result; -} sgimgui_args_make_buffer_t; - -typedef struct sgimgui_args_make_image_t { - sg_image result; -} sgimgui_args_make_image_t; - -typedef struct sgimgui_args_make_sampler_t { - sg_sampler result; -} sgimgui_args_make_sampler_t; - -typedef struct sgimgui_args_make_shader_t { - sg_shader result; -} sgimgui_args_make_shader_t; - -typedef struct sgimgui_args_make_pipeline_t { - sg_pipeline result; -} sgimgui_args_make_pipeline_t; - -typedef struct sgimgui_args_make_attachments_t { - sg_attachments result; -} sgimgui_args_make_attachments_t; - -typedef struct sgimgui_args_destroy_buffer_t { - sg_buffer buffer; -} sgimgui_args_destroy_buffer_t; - -typedef struct sgimgui_args_destroy_image_t { - sg_image image; -} sgimgui_args_destroy_image_t; - -typedef struct sgimgui_args_destroy_sampler_t { - sg_sampler sampler; -} sgimgui_args_destroy_sampler_t; - -typedef struct sgimgui_args_destroy_shader_t { - sg_shader shader; -} sgimgui_args_destroy_shader_t; - -typedef struct sgimgui_args_destroy_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_destroy_pipeline_t; - -typedef struct sgimgui_args_destroy_attachments_t { - sg_attachments attachments; -} sgimgui_args_destroy_attachments_t; - -typedef struct sgimgui_args_update_buffer_t { - sg_buffer buffer; - size_t data_size; -} sgimgui_args_update_buffer_t; - -typedef struct sgimgui_args_update_image_t { - sg_image image; -} sgimgui_args_update_image_t; - -typedef struct sgimgui_args_append_buffer_t { - sg_buffer buffer; - size_t data_size; - int result; -} sgimgui_args_append_buffer_t; - -typedef struct sgimgui_args_begin_pass_t { - sg_pass pass; -} sgimgui_args_begin_pass_t; - -typedef struct sgimgui_args_apply_viewport_t { - int x, y, width, height; - bool origin_top_left; -} sgimgui_args_apply_viewport_t; - -typedef struct sgimgui_args_apply_scissor_rect_t { - int x, y, width, height; - bool origin_top_left; -} sgimgui_args_apply_scissor_rect_t; - -typedef struct sgimgui_args_apply_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_apply_pipeline_t; - -typedef struct sgimgui_args_apply_bindings_t { - sg_bindings bindings; -} sgimgui_args_apply_bindings_t; - -typedef struct sgimgui_args_apply_uniforms_t { - sg_shader_stage stage; - int ub_index; - size_t data_size; - sg_pipeline pipeline; /* the pipeline which was active at this call */ - size_t ubuf_pos; /* start of copied data in capture buffer */ -} sgimgui_args_apply_uniforms_t; - -typedef struct sgimgui_args_draw_t { - int base_element; - int num_elements; - int num_instances; -} sgimgui_args_draw_t; - -typedef struct sgimgui_args_alloc_buffer_t { - sg_buffer result; -} sgimgui_args_alloc_buffer_t; - -typedef struct sgimgui_args_alloc_image_t { - sg_image result; -} sgimgui_args_alloc_image_t; - -typedef struct sgimgui_args_alloc_sampler_t { - sg_sampler result; -} sgimgui_args_alloc_sampler_t; - -typedef struct sgimgui_args_alloc_shader_t { - sg_shader result; -} sgimgui_args_alloc_shader_t; - -typedef struct sgimgui_args_alloc_pipeline_t { - sg_pipeline result; -} sgimgui_args_alloc_pipeline_t; - -typedef struct sgimgui_args_alloc_attachments_t { - sg_attachments result; -} sgimgui_args_alloc_attachments_t; - -typedef struct sgimgui_args_dealloc_buffer_t { - sg_buffer buffer; -} sgimgui_args_dealloc_buffer_t; - -typedef struct sgimgui_args_dealloc_image_t { - sg_image image; -} sgimgui_args_dealloc_image_t; - -typedef struct sgimgui_args_dealloc_sampler_t { - sg_sampler sampler; -} sgimgui_args_dealloc_sampler_t; - -typedef struct sgimgui_args_dealloc_shader_t { - sg_shader shader; -} sgimgui_args_dealloc_shader_t; - -typedef struct sgimgui_args_dealloc_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_dealloc_pipeline_t; - -typedef struct sgimgui_args_dealloc_attachments_t { - sg_attachments attachments; -} sgimgui_args_dealloc_attachments_t; - -typedef struct sgimgui_args_init_buffer_t { - sg_buffer buffer; -} sgimgui_args_init_buffer_t; - -typedef struct sgimgui_args_init_image_t { - sg_image image; -} sgimgui_args_init_image_t; - -typedef struct sgimgui_args_init_sampler_t { - sg_sampler sampler; -} sgimgui_args_init_sampler_t; - -typedef struct sgimgui_args_init_shader_t { - sg_shader shader; -} sgimgui_args_init_shader_t; - -typedef struct sgimgui_args_init_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_init_pipeline_t; - -typedef struct sgimgui_args_init_attachments_t { - sg_attachments attachments; -} sgimgui_args_init_attachments_t; - -typedef struct sgimgui_args_uninit_buffer_t { - sg_buffer buffer; -} sgimgui_args_uninit_buffer_t; - -typedef struct sgimgui_args_uninit_image_t { - sg_image image; -} sgimgui_args_uninit_image_t; - -typedef struct sgimgui_args_uninit_sampler_t { - sg_sampler sampler; -} sgimgui_args_uninit_sampler_t; - -typedef struct sgimgui_args_uninit_shader_t { - sg_shader shader; -} sgimgui_args_uninit_shader_t; - -typedef struct sgimgui_args_uninit_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_uninit_pipeline_t; - -typedef struct sgimgui_args_uninit_attachments_t { - sg_attachments attachments; -} sgimgui_args_uninit_attachments_t; - -typedef struct sgimgui_args_fail_buffer_t { - sg_buffer buffer; -} sgimgui_args_fail_buffer_t; - -typedef struct sgimgui_args_fail_image_t { - sg_image image; -} sgimgui_args_fail_image_t; - -typedef struct sgimgui_args_fail_sampler_t { - sg_sampler sampler; -} sgimgui_args_fail_sampler_t; - -typedef struct sgimgui_args_fail_shader_t { - sg_shader shader; -} sgimgui_args_fail_shader_t; - -typedef struct sgimgui_args_fail_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_fail_pipeline_t; - -typedef struct sgimgui_args_fail_attachments_t { - sg_attachments attachments; -} sgimgui_args_fail_attachments_t; - -typedef struct sgimgui_args_push_debug_group_t { - sgimgui_str_t name; -} sgimgui_args_push_debug_group_t; - -typedef union sgimgui_args_t { - sgimgui_args_make_buffer_t make_buffer; - sgimgui_args_make_image_t make_image; - sgimgui_args_make_sampler_t make_sampler; - sgimgui_args_make_shader_t make_shader; - sgimgui_args_make_pipeline_t make_pipeline; - sgimgui_args_make_attachments_t make_attachments; - sgimgui_args_destroy_buffer_t destroy_buffer; - sgimgui_args_destroy_image_t destroy_image; - sgimgui_args_destroy_sampler_t destroy_sampler; - sgimgui_args_destroy_shader_t destroy_shader; - sgimgui_args_destroy_pipeline_t destroy_pipeline; - sgimgui_args_destroy_attachments_t destroy_attachments; - sgimgui_args_update_buffer_t update_buffer; - sgimgui_args_update_image_t update_image; - sgimgui_args_append_buffer_t append_buffer; - sgimgui_args_begin_pass_t begin_pass; - sgimgui_args_apply_viewport_t apply_viewport; - sgimgui_args_apply_scissor_rect_t apply_scissor_rect; - sgimgui_args_apply_pipeline_t apply_pipeline; - sgimgui_args_apply_bindings_t apply_bindings; - sgimgui_args_apply_uniforms_t apply_uniforms; - sgimgui_args_draw_t draw; - sgimgui_args_alloc_buffer_t alloc_buffer; - sgimgui_args_alloc_image_t alloc_image; - sgimgui_args_alloc_sampler_t alloc_sampler; - sgimgui_args_alloc_shader_t alloc_shader; - sgimgui_args_alloc_pipeline_t alloc_pipeline; - sgimgui_args_alloc_attachments_t alloc_attachments; - sgimgui_args_dealloc_buffer_t dealloc_buffer; - sgimgui_args_dealloc_image_t dealloc_image; - sgimgui_args_dealloc_sampler_t dealloc_sampler; - sgimgui_args_dealloc_shader_t dealloc_shader; - sgimgui_args_dealloc_pipeline_t dealloc_pipeline; - sgimgui_args_dealloc_attachments_t dealloc_attachments; - sgimgui_args_init_buffer_t init_buffer; - sgimgui_args_init_image_t init_image; - sgimgui_args_init_sampler_t init_sampler; - sgimgui_args_init_shader_t init_shader; - sgimgui_args_init_pipeline_t init_pipeline; - sgimgui_args_init_attachments_t init_attachments; - sgimgui_args_uninit_buffer_t uninit_buffer; - sgimgui_args_uninit_image_t uninit_image; - sgimgui_args_uninit_sampler_t uninit_sampler; - sgimgui_args_uninit_shader_t uninit_shader; - sgimgui_args_uninit_pipeline_t uninit_pipeline; - sgimgui_args_uninit_attachments_t uninit_attachments; - sgimgui_args_fail_buffer_t fail_buffer; - sgimgui_args_fail_image_t fail_image; - sgimgui_args_fail_sampler_t fail_sampler; - sgimgui_args_fail_shader_t fail_shader; - sgimgui_args_fail_pipeline_t fail_pipeline; - sgimgui_args_fail_attachments_t fail_attachments; - sgimgui_args_push_debug_group_t push_debug_group; -} sgimgui_args_t; - -typedef struct sgimgui_capture_item_t { - sgimgui_cmd_t cmd; - uint32_t color; - sgimgui_args_t args; -} sgimgui_capture_item_t; - -typedef struct sgimgui_capture_bucket_t { - size_t ubuf_size; /* size of uniform capture buffer in bytes */ - size_t ubuf_pos; /* current uniform buffer pos */ - uint8_t* ubuf; /* buffer for capturing uniform updates */ - int num_items; - sgimgui_capture_item_t items[sgimgui_MAX_FRAMECAPTURE_ITEMS]; -} sgimgui_capture_bucket_t; - -/* double-buffered call-capture buckets, one bucket is currently recorded, - the previous bucket is displayed -*/ -typedef struct sgimgui_capture_window_t { - bool open; - int bucket_index; /* which bucket to record to, 0 or 1 */ - int sel_item; /* currently selected capture item by index */ - sgimgui_capture_bucket_t bucket[2]; -} sgimgui_capture_window_t; - -typedef struct sgimgui_caps_window_t { - bool open; -} sgimgui_caps_window_t; - -typedef struct sgimgui_frame_stats_window_t { - bool open; - bool disable_sokol_imgui_stats; - bool in_sokol_imgui; - sg_frame_stats stats; - // FIXME: add a ringbuffer for a stats history here -} sgimgui_frame_stats_window_t; - -/* - sgimgui_allocator_t - - Used in sgimgui_desc_t to provide custom memory-alloc and -free functions - to sokol_gfx_imgui.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sgimgui_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sgimgui_allocator_t; - -/* - sgimgui_desc_t - - Initialization options for sgimgui_init(). -*/ -typedef struct sgimgui_desc_t { - sgimgui_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) -} sgimgui_desc_t; - -typedef struct sgimgui_t { - uint32_t init_tag; - sgimgui_desc_t desc; - sgimgui_buffer_window_t buffer_window; - sgimgui_image_window_t image_window; - sgimgui_sampler_window_t sampler_window; - sgimgui_shader_window_t shader_window; - sgimgui_pipeline_window_t pipeline_window; - sgimgui_attachments_window_t attachments_window; - sgimgui_capture_window_t capture_window; - sgimgui_caps_window_t caps_window; - sgimgui_frame_stats_window_t frame_stats_window; - sg_pipeline cur_pipeline; - sg_trace_hooks hooks; -} sgimgui_t; - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_init(sgimgui_t* ctx, const sgimgui_desc_t* desc); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_discard(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw(sgimgui_t* ctx); - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_menu(sgimgui_t* ctx, const char* title); - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_buffer_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_image_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_sampler_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_shader_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_pipeline_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_attachments_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capture_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capabilities_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_frame_stats_window_content(sgimgui_t* ctx); - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_buffer_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_image_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_sampler_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_shader_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_pipeline_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_attachments_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capture_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capabilities_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_frame_stats_window(sgimgui_t* ctx); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif -#endif /* SOKOL_GFX_IMGUI_INCLUDED */ - -/*=== IMPLEMENTATION =========================================================*/ -#ifdef SOKOL_GFX_IMGUI_IMPL -#define SOKOL_GFX_IMGUI_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sgimgui_desc_t.allocator to override memory allocation functions" -#endif - -#if defined(__cplusplus) - #if !defined(IMGUI_VERSION) - #error "Please include imgui.h before the sokol_imgui.h implementation" - #endif -#else - #if !defined(CIMGUI_INCLUDED) - #error "Please include cimgui.h before the sokol_imgui.h implementation" - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif -#ifndef _SOKOL_UNUSED -#define _SOKOL_UNUSED(x) (void)(x) -#endif -#ifndef SOKOL_API_IMPL -#define SOKOL_API_IMPL -#endif - -#include -#include // snprintf -#include // malloc, free - -#define _SGIMGUI_SLOT_MASK (0xFFFF) -#define _SGIMGUI_LIST_WIDTH (192) -#define _SGIMGUI_COLOR_OTHER 0xFFCCCCCC -#define _SGIMGUI_COLOR_RSRC 0xFF00FFFF -#define _SGIMGUI_COLOR_PASS 0xFFFFFF00 -#define _SGIMGUI_COLOR_APPLY 0xFFCCCC00 -#define _SGIMGUI_COLOR_DRAW 0xFF00FF00 -#define _SGIMGUI_COLOR_ERR 0xFF8888FF - -/*--- C => C++ layer ---------------------------------------------------------*/ -#if defined(__cplusplus) -#define IMVEC2(x,y) ImVec2(x,y) -#define IMVEC4(x,y,z,w) ImVec4(x,y,z,w) -_SOKOL_PRIVATE void igText(const char* fmt,...) { - va_list args; - va_start(args, fmt); - ImGui::TextV(fmt, args); - va_end(args); -} -_SOKOL_PRIVATE void igSeparator() { - return ImGui::Separator(); -} -_SOKOL_PRIVATE void igSameLine(float offset_from_start_x, float spacing) { - return ImGui::SameLine(offset_from_start_x,spacing); -} -_SOKOL_PRIVATE void igPushID_Int(int int_id) { - return ImGui::PushID(int_id); -} -_SOKOL_PRIVATE void igPopID() { - return ImGui::PopID(); -} -_SOKOL_PRIVATE bool igSelectable_Bool(const char* label,bool selected,ImGuiSelectableFlags flags,const ImVec2 size) { - return ImGui::Selectable(label,selected,flags,size); -} -_SOKOL_PRIVATE bool igSmallButton(const char* label) { - return ImGui::SmallButton(label); -} -_SOKOL_PRIVATE bool igBeginChild_Str(const char* str_id,const ImVec2 size,bool border,ImGuiWindowFlags flags) { - return ImGui::BeginChild(str_id,size,border,flags); -} -_SOKOL_PRIVATE void igEndChild() { - return ImGui::EndChild(); -} -_SOKOL_PRIVATE void igPushStyleColor_U32(ImGuiCol idx, ImU32 col) { - return ImGui::PushStyleColor(idx,col); -} -_SOKOL_PRIVATE void igPopStyleColor(int count) { - return ImGui::PopStyleColor(count); -} -_SOKOL_PRIVATE bool igTreeNode_StrStr(const char* str_id,const char* fmt,...) { - va_list args; - va_start(args, fmt); - bool ret = ImGui::TreeNodeV(str_id,fmt,args); - va_end(args); - return ret; -} -_SOKOL_PRIVATE bool igTreeNode_Str(const char* label) { - return ImGui::TreeNode(label); -} -_SOKOL_PRIVATE void igTreePop() { - return ImGui::TreePop(); -} -_SOKOL_PRIVATE bool igIsItemHovered(ImGuiHoveredFlags flags) { - return ImGui::IsItemHovered(flags); -} -_SOKOL_PRIVATE void igSetTooltip(const char* fmt,...) { - va_list args; - va_start(args, fmt); - ImGui::SetTooltipV(fmt,args); - va_end(args); -} -_SOKOL_PRIVATE bool igSliderFloat(const char* label,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) { - return ImGui::SliderFloat(label,v,v_min,v_max,format,flags); -} -_SOKOL_PRIVATE void igImage(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec4 tint_col,const ImVec4 border_col) { - return ImGui::Image(user_texture_id,size,uv0,uv1,tint_col,border_col); -} -_SOKOL_PRIVATE void igSetNextWindowSize(const ImVec2 size,ImGuiCond cond) { - return ImGui::SetNextWindowSize(size,cond); -} -_SOKOL_PRIVATE bool igBegin(const char* name,bool* p_open,ImGuiWindowFlags flags) { - return ImGui::Begin(name,p_open,flags); -} -_SOKOL_PRIVATE void igEnd() { - return ImGui::End(); -} -_SOKOL_PRIVATE bool igBeginMenu(const char* label, bool enabled) { - return ImGui::BeginMenu(label, enabled); -} -_SOKOL_PRIVATE void igEndMenu(void) { - ImGui::EndMenu(); -} -_SOKOL_PRIVATE bool igMenuItem_BoolPtr(const char* label, const char* shortcut, bool* p_selected, bool enabled) { - return ImGui::MenuItem(label, shortcut, p_selected, enabled); -} -_SOKOL_PRIVATE bool igBeginTable(const char* str_id, int column, ImGuiTableFlags flags, const ImVec2 outer_size, float inner_width) { - return ImGui::BeginTable(str_id, column, flags, outer_size, inner_width); -} -_SOKOL_PRIVATE void igEndTable(void) { - ImGui::EndTable(); -} -_SOKOL_PRIVATE void igTableSetupScrollFreeze(int cols, int rows) { - ImGui::TableSetupScrollFreeze(cols, rows); -} -_SOKOL_PRIVATE void igTableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) { - ImGui::TableSetupColumn(label, flags, init_width_or_weight, user_id); -} -_SOKOL_PRIVATE void igTableHeadersRow(void) { - ImGui::TableHeadersRow(); -} -_SOKOL_PRIVATE void igTableNextRow(ImGuiTableRowFlags row_flags, float min_row_height) { - ImGui::TableNextRow(row_flags, min_row_height); -} -_SOKOL_PRIVATE bool igTableSetColumnIndex(int column_n) { - return ImGui::TableSetColumnIndex(column_n); -} -_SOKOL_PRIVATE bool igCheckbox(const char* label, bool* v) { - return ImGui::Checkbox(label, v); -} -#else -#define IMVEC2(x,y) (ImVec2){x,y} -#define IMVEC4(x,y,z,w) (ImVec4){x,y,z,w} -#endif - -/*--- UTILS ------------------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _sgimgui_malloc(const sgimgui_allocator_t* allocator, size_t size) { - SOKOL_ASSERT(allocator && (size > 0)); - void* ptr; - if (allocator->alloc_fn) { - ptr = allocator->alloc_fn(size, allocator->user_data); - } else { - ptr = malloc(size); - } - SOKOL_ASSERT(ptr); - return ptr; -} - -_SOKOL_PRIVATE void* _sgimgui_malloc_clear(const sgimgui_allocator_t* allocator, size_t size) { - void* ptr = _sgimgui_malloc(allocator, size); - _sgimgui_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _sgimgui_free(const sgimgui_allocator_t* allocator, void* ptr) { - SOKOL_ASSERT(allocator); - if (allocator->free_fn) { - allocator->free_fn(ptr, allocator->user_data); - } else { - free(ptr); - } -} - - _SOKOL_PRIVATE void* _sgimgui_realloc(const sgimgui_allocator_t* allocator, void* old_ptr, size_t old_size, size_t new_size) { - SOKOL_ASSERT(allocator && (new_size > 0) && (new_size > old_size)); - void* new_ptr = _sgimgui_malloc(allocator, new_size); - if (old_ptr) { - if (old_size > 0) { - memcpy(new_ptr, old_ptr, old_size); - } - _sgimgui_free(allocator, old_ptr); - } - return new_ptr; -} - -_SOKOL_PRIVATE int _sgimgui_slot_index(uint32_t id) { - int slot_index = (int) (id & _SGIMGUI_SLOT_MASK); - SOKOL_ASSERT(0 != slot_index); - return slot_index; -} - -_SOKOL_PRIVATE uint32_t _sgimgui_align_u32(uint32_t val, uint32_t align) { - SOKOL_ASSERT((align > 0) && ((align & (align - 1)) == 0)); - return (val + (align - 1)) & ~(align - 1); -} - -_SOKOL_PRIVATE uint32_t _sgimgui_std140_uniform_alignment(sg_uniform_type type, int array_count) { - SOKOL_ASSERT(array_count > 0); - if (array_count == 1) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT3: - case SG_UNIFORMTYPE_INT4: - return 16; - case SG_UNIFORMTYPE_MAT4: - return 16; - default: - SOKOL_UNREACHABLE; - return 1; - } - } else { - return 16; - } -} - -_SOKOL_PRIVATE uint32_t _sgimgui_std140_uniform_size(sg_uniform_type type, int array_count) { - SOKOL_ASSERT(array_count > 0); - if (array_count == 1) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_INT3: - return 12; - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT4: - return 16; - case SG_UNIFORMTYPE_MAT4: - return 64; - default: - SOKOL_UNREACHABLE; - return 0; - } - } else { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT: - case SG_UNIFORMTYPE_INT2: - case SG_UNIFORMTYPE_INT3: - case SG_UNIFORMTYPE_INT4: - return 16 * (uint32_t)array_count; - case SG_UNIFORMTYPE_MAT4: - return 64 * (uint32_t)array_count; - default: - SOKOL_UNREACHABLE; - return 0; - } - } -} - -_SOKOL_PRIVATE void _sgimgui_strcpy(sgimgui_str_t* dst, const char* src) { - SOKOL_ASSERT(dst); - if (src) { - #if defined(_MSC_VER) - strncpy_s(dst->buf, sgimgui_STRBUF_LEN, src, (sgimgui_STRBUF_LEN-1)); - #else - strncpy(dst->buf, src, sgimgui_STRBUF_LEN); - #endif - dst->buf[sgimgui_STRBUF_LEN-1] = 0; - } else { - _sgimgui_clear(dst->buf, sgimgui_STRBUF_LEN); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_make_str(const char* str) { - sgimgui_str_t res; - _sgimgui_strcpy(&res, str); - return res; -} - -_SOKOL_PRIVATE const char* _sgimgui_str_dup(const sgimgui_allocator_t* allocator, const char* src) { - SOKOL_ASSERT(allocator && src); - size_t len = strlen(src) + 1; - char* dst = (char*) _sgimgui_malloc(allocator, len); - memcpy(dst, src, len); - return (const char*) dst; -} - -_SOKOL_PRIVATE const void* _sgimgui_bin_dup(const sgimgui_allocator_t* allocator, const void* src, size_t num_bytes) { - SOKOL_ASSERT(allocator && src && (num_bytes > 0)); - void* dst = _sgimgui_malloc(allocator, num_bytes); - memcpy(dst, src, num_bytes); - return (const void*) dst; -} - -_SOKOL_PRIVATE void _sgimgui_snprintf(sgimgui_str_t* dst, const char* fmt, ...) { - SOKOL_ASSERT(dst); - va_list args; - va_start(args, fmt); - vsnprintf(dst->buf, sizeof(dst->buf), fmt, args); - dst->buf[sizeof(dst->buf)-1] = 0; - va_end(args); -} - -/*--- STRING CONVERSION ------------------------------------------------------*/ -_SOKOL_PRIVATE const char* _sgimgui_resourcestate_string(sg_resource_state s) { - switch (s) { - case SG_RESOURCESTATE_INITIAL: return "SG_RESOURCESTATE_INITIAL"; - case SG_RESOURCESTATE_ALLOC: return "SG_RESOURCESTATE_ALLOC"; - case SG_RESOURCESTATE_VALID: return "SG_RESOURCESTATE_VALID"; - case SG_RESOURCESTATE_FAILED: return "SG_RESOURCESTATE_FAILED"; - default: return "SG_RESOURCESTATE_INVALID"; - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_resource_slot(const sg_slot_info* slot) { - igText("ResId: %08X", slot->res_id); - igText("State: %s", _sgimgui_resourcestate_string(slot->state)); -} - -_SOKOL_PRIVATE const char* _sgimgui_backend_string(sg_backend b) { - switch (b) { - case SG_BACKEND_GLCORE33: return "SG_BACKEND_GLCORE33"; - case SG_BACKEND_GLES3: return "SG_BACKEND_GLES3"; - case SG_BACKEND_D3D11: return "SG_BACKEND_D3D11"; - case SG_BACKEND_METAL_IOS: return "SG_BACKEND_METAL_IOS"; - case SG_BACKEND_METAL_MACOS: return "SG_BACKEND_METAL_MACOS"; - case SG_BACKEND_METAL_SIMULATOR: return "SG_BACKEND_METAL_SIMULATOR"; - case SG_BACKEND_WGPU: return "SG_BACKEND_WGPU"; - case SG_BACKEND_DUMMY: return "SG_BACKEND_DUMMY"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_buffertype_string(sg_buffer_type t) { - switch (t) { - case SG_BUFFERTYPE_VERTEXBUFFER: return "SG_BUFFERTYPE_VERTEXBUFFER"; - case SG_BUFFERTYPE_INDEXBUFFER: return "SG_BUFFERTYPE_INDEXBUFFER"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_usage_string(sg_usage u) { - switch (u) { - case SG_USAGE_IMMUTABLE: return "SG_USAGE_IMMUTABLE"; - case SG_USAGE_DYNAMIC: return "SG_USAGE_DYNAMIC"; - case SG_USAGE_STREAM: return "SG_USAGE_STREAM"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_imagetype_string(sg_image_type t) { - switch (t) { - case SG_IMAGETYPE_2D: return "SG_IMAGETYPE_2D"; - case SG_IMAGETYPE_CUBE: return "SG_IMAGETYPE_CUBE"; - case SG_IMAGETYPE_3D: return "SG_IMAGETYPE_3D"; - case SG_IMAGETYPE_ARRAY: return "SG_IMAGETYPE_ARRAY"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_imagesampletype_string(sg_image_sample_type t) { - switch (t) { - case SG_IMAGESAMPLETYPE_FLOAT: return "SG_IMAGESAMPLETYPE_FLOAT"; - case SG_IMAGESAMPLETYPE_DEPTH: return "SG_IMAGESAMPLETYPE_DEPTH"; - case SG_IMAGESAMPLETYPE_SINT: return "SG_IMAGESAMPLETYPE_SINT"; - case SG_IMAGESAMPLETYPE_UINT: return "SG_IMAGESAMPLETYPE_UINT"; - case SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT: return "SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_samplertype_string(sg_sampler_type t) { - switch (t) { - case SG_SAMPLERTYPE_FILTERING: return "SG_SAMPLERTYPE_FILTERING"; - case SG_SAMPLERTYPE_COMPARISON: return "SG_SAMPLERTYPE_COMPARISON"; - case SG_SAMPLERTYPE_NONFILTERING: return "SG_SAMPLERTYPE_NONFILTERING"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_uniformlayout_string(sg_uniform_layout l) { - switch (l) { - case SG_UNIFORMLAYOUT_NATIVE: return "SG_UNIFORMLAYOUT_NATIVE"; - case SG_UNIFORMLAYOUT_STD140: return "SG_UNIFORMLAYOUT_STD140"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_pixelformat_string(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_NONE: return "SG_PIXELFORMAT_NONE"; - case SG_PIXELFORMAT_R8: return "SG_PIXELFORMAT_R8"; - case SG_PIXELFORMAT_R8SN: return "SG_PIXELFORMAT_R8SN"; - case SG_PIXELFORMAT_R8UI: return "SG_PIXELFORMAT_R8UI"; - case SG_PIXELFORMAT_R8SI: return "SG_PIXELFORMAT_R8SI"; - case SG_PIXELFORMAT_R16: return "SG_PIXELFORMAT_R16"; - case SG_PIXELFORMAT_R16SN: return "SG_PIXELFORMAT_R16SN"; - case SG_PIXELFORMAT_R16UI: return "SG_PIXELFORMAT_R16UI"; - case SG_PIXELFORMAT_R16SI: return "SG_PIXELFORMAT_R16SI"; - case SG_PIXELFORMAT_R16F: return "SG_PIXELFORMAT_R16F"; - case SG_PIXELFORMAT_RG8: return "SG_PIXELFORMAT_RG8"; - case SG_PIXELFORMAT_RG8SN: return "SG_PIXELFORMAT_RG8SN"; - case SG_PIXELFORMAT_RG8UI: return "SG_PIXELFORMAT_RG8UI"; - case SG_PIXELFORMAT_RG8SI: return "SG_PIXELFORMAT_RG8SI"; - case SG_PIXELFORMAT_R32UI: return "SG_PIXELFORMAT_R32UI"; - case SG_PIXELFORMAT_R32SI: return "SG_PIXELFORMAT_R32SI"; - case SG_PIXELFORMAT_R32F: return "SG_PIXELFORMAT_R32F"; - case SG_PIXELFORMAT_RG16: return "SG_PIXELFORMAT_RG16"; - case SG_PIXELFORMAT_RG16SN: return "SG_PIXELFORMAT_RG16SN"; - case SG_PIXELFORMAT_RG16UI: return "SG_PIXELFORMAT_RG16UI"; - case SG_PIXELFORMAT_RG16SI: return "SG_PIXELFORMAT_RG16SI"; - case SG_PIXELFORMAT_RG16F: return "SG_PIXELFORMAT_RG16F"; - case SG_PIXELFORMAT_RGBA8: return "SG_PIXELFORMAT_RGBA8"; - case SG_PIXELFORMAT_SRGB8A8: return "SG_PIXELFORMAT_SRGB8A8"; - case SG_PIXELFORMAT_RGBA8SN: return "SG_PIXELFORMAT_RGBA8SN"; - case SG_PIXELFORMAT_RGBA8UI: return "SG_PIXELFORMAT_RGBA8UI"; - case SG_PIXELFORMAT_RGBA8SI: return "SG_PIXELFORMAT_RGBA8SI"; - case SG_PIXELFORMAT_BGRA8: return "SG_PIXELFORMAT_BGRA8"; - case SG_PIXELFORMAT_RGB10A2: return "SG_PIXELFORMAT_RGB10A2"; - case SG_PIXELFORMAT_RG11B10F: return "SG_PIXELFORMAT_RG11B10F"; - case SG_PIXELFORMAT_RG32UI: return "SG_PIXELFORMAT_RG32UI"; - case SG_PIXELFORMAT_RG32SI: return "SG_PIXELFORMAT_RG32SI"; - case SG_PIXELFORMAT_RG32F: return "SG_PIXELFORMAT_RG32F"; - case SG_PIXELFORMAT_RGBA16: return "SG_PIXELFORMAT_RGBA16"; - case SG_PIXELFORMAT_RGBA16SN: return "SG_PIXELFORMAT_RGBA16SN"; - case SG_PIXELFORMAT_RGBA16UI: return "SG_PIXELFORMAT_RGBA16UI"; - case SG_PIXELFORMAT_RGBA16SI: return "SG_PIXELFORMAT_RGBA16SI"; - case SG_PIXELFORMAT_RGBA16F: return "SG_PIXELFORMAT_RGBA16F"; - case SG_PIXELFORMAT_RGBA32UI: return "SG_PIXELFORMAT_RGBA32UI"; - case SG_PIXELFORMAT_RGBA32SI: return "SG_PIXELFORMAT_RGBA32SI"; - case SG_PIXELFORMAT_RGBA32F: return "SG_PIXELFORMAT_RGBA32F"; - case SG_PIXELFORMAT_DEPTH: return "SG_PIXELFORMAT_DEPTH"; - case SG_PIXELFORMAT_DEPTH_STENCIL: return "SG_PIXELFORMAT_DEPTH_STENCIL"; - case SG_PIXELFORMAT_BC1_RGBA: return "SG_PIXELFORMAT_BC1_RGBA"; - case SG_PIXELFORMAT_BC2_RGBA: return "SG_PIXELFORMAT_BC2_RGBA"; - case SG_PIXELFORMAT_BC3_RGBA: return "SG_PIXELFORMAT_BC3_RGBA"; - case SG_PIXELFORMAT_BC4_R: return "SG_PIXELFORMAT_BC4_R"; - case SG_PIXELFORMAT_BC4_RSN: return "SG_PIXELFORMAT_BC4_RSN"; - case SG_PIXELFORMAT_BC5_RG: return "SG_PIXELFORMAT_BC5_RG"; - case SG_PIXELFORMAT_BC5_RGSN: return "SG_PIXELFORMAT_BC5_RGSN"; - case SG_PIXELFORMAT_BC6H_RGBF: return "SG_PIXELFORMAT_BC6H_RGBF"; - case SG_PIXELFORMAT_BC6H_RGBUF: return "SG_PIXELFORMAT_BC6H_RGBUF"; - case SG_PIXELFORMAT_BC7_RGBA: return "SG_PIXELFORMAT_BC7_RGBA"; - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return "SG_PIXELFORMAT_PVRTC_RGB_2BPP"; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return "SG_PIXELFORMAT_PVRTC_RGB_4BPP"; - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return "SG_PIXELFORMAT_PVRTC_RGBA_2BPP"; - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return "SG_PIXELFORMAT_PVRTC_RGBA_4BPP"; - case SG_PIXELFORMAT_ETC2_RGB8: return "SG_PIXELFORMAT_ETC2_RGB8"; - case SG_PIXELFORMAT_ETC2_RGB8A1: return "SG_PIXELFORMAT_ETC2_RGB8A1"; - case SG_PIXELFORMAT_ETC2_RGBA8: return "SG_PIXELFORMAT_ETC2_RGBA8"; - case SG_PIXELFORMAT_ETC2_RG11: return "SG_PIXELFORMAT_ETC2_RG11"; - case SG_PIXELFORMAT_ETC2_RG11SN: return "SG_PIXELFORMAT_ETC2_RG11SN"; - case SG_PIXELFORMAT_RGB9E5: return "SG_PIXELFORMAT_RGB9E5"; - case SG_PIXELFORMAT_BC3_SRGBA: return "SG_PIXELFORMAT_BC3_SRGBA"; - case SG_PIXELFORMAT_BC7_SRGBA: return "SG_PIXELFORMAT_BC7_SRGBA"; - case SG_PIXELFORMAT_ETC2_SRGB8: return "SG_PIXELFORMAT_ETC2_SRGB8"; - case SG_PIXELFORMAT_ETC2_SRGB8A8: return "SG_PIXELFORMAT_ETC2_SRGB8A8"; - case SG_PIXELFORMAT_ASTC_4x4_RGBA: return "SG_PIXELFORMAT_ASTC_4x4_RGBA"; - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return "SG_PIXELFORMAT_ASTC_4x4_SRGBA"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_filter_string(sg_filter f) { - switch (f) { - case SG_FILTER_NONE: return "SG_FILTER_NONE"; - case SG_FILTER_NEAREST: return "SG_FILTER_NEAREST"; - case SG_FILTER_LINEAR: return "SG_FILTER_LINEAR"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_wrap_string(sg_wrap w) { - switch (w) { - case SG_WRAP_REPEAT: return "SG_WRAP_REPEAT"; - case SG_WRAP_CLAMP_TO_EDGE: return "SG_WRAP_CLAMP_TO_EDGE"; - case SG_WRAP_CLAMP_TO_BORDER: return "SG_WRAP_CLAMP_TO_BORDER"; - case SG_WRAP_MIRRORED_REPEAT: return "SG_WRAP_MIRRORED_REPEAT"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_bordercolor_string(sg_border_color bc) { - switch (bc) { - case SG_BORDERCOLOR_TRANSPARENT_BLACK: return "SG_BORDERCOLOR_TRANSPARENT_BLACK"; - case SG_BORDERCOLOR_OPAQUE_BLACK: return "SG_BORDERCOLOR_OPAQUE_BLACK"; - case SG_BORDERCOLOR_OPAQUE_WHITE: return "SG_BORDERCOLOR_OPAQUE_WHITE"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_uniformtype_string(sg_uniform_type t) { - switch (t) { - case SG_UNIFORMTYPE_FLOAT: return "SG_UNIFORMTYPE_FLOAT"; - case SG_UNIFORMTYPE_FLOAT2: return "SG_UNIFORMTYPE_FLOAT2"; - case SG_UNIFORMTYPE_FLOAT3: return "SG_UNIFORMTYPE_FLOAT3"; - case SG_UNIFORMTYPE_FLOAT4: return "SG_UNIFORMTYPE_FLOAT4"; - case SG_UNIFORMTYPE_INT: return "SG_UNIFORMTYPE_INT"; - case SG_UNIFORMTYPE_INT2: return "SG_UNIFORMTYPE_INT2"; - case SG_UNIFORMTYPE_INT3: return "SG_UNIFORMTYPE_INT3"; - case SG_UNIFORMTYPE_INT4: return "SG_UNIFORMTYPE_INT4"; - case SG_UNIFORMTYPE_MAT4: return "SG_UNIFORMTYPE_MAT4"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_vertexstep_string(sg_vertex_step s) { - switch (s) { - case SG_VERTEXSTEP_PER_VERTEX: return "SG_VERTEXSTEP_PER_VERTEX"; - case SG_VERTEXSTEP_PER_INSTANCE: return "SG_VERTEXSTEP_PER_INSTANCE"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_vertexformat_string(sg_vertex_format f) { - switch (f) { - case SG_VERTEXFORMAT_FLOAT: return "SG_VERTEXFORMAT_FLOAT"; - case SG_VERTEXFORMAT_FLOAT2: return "SG_VERTEXFORMAT_FLOAT2"; - case SG_VERTEXFORMAT_FLOAT3: return "SG_VERTEXFORMAT_FLOAT3"; - case SG_VERTEXFORMAT_FLOAT4: return "SG_VERTEXFORMAT_FLOAT4"; - case SG_VERTEXFORMAT_BYTE4: return "SG_VERTEXFORMAT_BYTE4"; - case SG_VERTEXFORMAT_BYTE4N: return "SG_VERTEXFORMAT_BYTE4N"; - case SG_VERTEXFORMAT_UBYTE4: return "SG_VERTEXFORMAT_UBYTE4"; - case SG_VERTEXFORMAT_UBYTE4N: return "SG_VERTEXFORMAT_UBYTE4N"; - case SG_VERTEXFORMAT_SHORT2: return "SG_VERTEXFORMAT_SHORT2"; - case SG_VERTEXFORMAT_SHORT2N: return "SG_VERTEXFORMAT_SHORT2N"; - case SG_VERTEXFORMAT_USHORT2N: return "SG_VERTEXFORMAT_USHORT2N"; - case SG_VERTEXFORMAT_SHORT4: return "SG_VERTEXFORMAT_SHORT4"; - case SG_VERTEXFORMAT_SHORT4N: return "SG_VERTEXFORMAT_SHORT4N"; - case SG_VERTEXFORMAT_USHORT4N: return "SG_VERTEXFORMAT_USHORT4N"; - case SG_VERTEXFORMAT_UINT10_N2: return "SG_VERTEXFORMAT_UINT10_N2"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_primitivetype_string(sg_primitive_type t) { - switch (t) { - case SG_PRIMITIVETYPE_POINTS: return "SG_PRIMITIVETYPE_POINTS"; - case SG_PRIMITIVETYPE_LINES: return "SG_PRIMITIVETYPE_LINES"; - case SG_PRIMITIVETYPE_LINE_STRIP: return "SG_PRIMITIVETYPE_LINE_STRIP"; - case SG_PRIMITIVETYPE_TRIANGLES: return "SG_PRIMITIVETYPE_TRIANGLES"; - case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return "SG_PRIMITIVETYPE_TRIANGLE_STRIP"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_indextype_string(sg_index_type t) { - switch (t) { - case SG_INDEXTYPE_NONE: return "SG_INDEXTYPE_NONE"; - case SG_INDEXTYPE_UINT16: return "SG_INDEXTYPE_UINT16"; - case SG_INDEXTYPE_UINT32: return "SG_INDEXTYPE_UINT32"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_stencilop_string(sg_stencil_op op) { - switch (op) { - case SG_STENCILOP_KEEP: return "SG_STENCILOP_KEEP"; - case SG_STENCILOP_ZERO: return "SG_STENCILOP_ZERO"; - case SG_STENCILOP_REPLACE: return "SG_STENCILOP_REPLACE"; - case SG_STENCILOP_INCR_CLAMP: return "SG_STENCILOP_INCR_CLAMP"; - case SG_STENCILOP_DECR_CLAMP: return "SG_STENCILOP_DECR_CLAMP"; - case SG_STENCILOP_INVERT: return "SG_STENCILOP_INVERT"; - case SG_STENCILOP_INCR_WRAP: return "SG_STENCILOP_INCR_WRAP"; - case SG_STENCILOP_DECR_WRAP: return "SG_STENCILOP_DECR_WRAP"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_comparefunc_string(sg_compare_func f) { - switch (f) { - case SG_COMPAREFUNC_NEVER: return "SG_COMPAREFUNC_NEVER"; - case SG_COMPAREFUNC_LESS: return "SG_COMPAREFUNC_LESS"; - case SG_COMPAREFUNC_EQUAL: return "SG_COMPAREFUNC_EQUAL"; - case SG_COMPAREFUNC_LESS_EQUAL: return "SG_COMPAREFUNC_LESS_EQUAL"; - case SG_COMPAREFUNC_GREATER: return "SG_COMPAREFUNC_GREATER"; - case SG_COMPAREFUNC_NOT_EQUAL: return "SG_COMPAREFUNC_NOT_EQUAL"; - case SG_COMPAREFUNC_GREATER_EQUAL: return "SG_COMPAREFUNC_GREATER_EQUAL"; - case SG_COMPAREFUNC_ALWAYS: return "SG_COMPAREFUNC_ALWAYS"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_blendfactor_string(sg_blend_factor f) { - switch (f) { - case SG_BLENDFACTOR_ZERO: return "SG_BLENDFACTOR_ZERO"; - case SG_BLENDFACTOR_ONE: return "SG_BLENDFACTOR_ONE"; - case SG_BLENDFACTOR_SRC_COLOR: return "SG_BLENDFACTOR_SRC_COLOR"; - case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return "SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR"; - case SG_BLENDFACTOR_SRC_ALPHA: return "SG_BLENDFACTOR_SRC_ALPHA"; - case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return "SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA"; - case SG_BLENDFACTOR_DST_COLOR: return "SG_BLENDFACTOR_DST_COLOR"; - case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return "SG_BLENDFACTOR_ONE_MINUS_DST_COLOR"; - case SG_BLENDFACTOR_DST_ALPHA: return "SG_BLENDFACTOR_DST_ALPHA"; - case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return "SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA"; - case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return "SG_BLENDFACTOR_SRC_ALPHA_SATURATED"; - case SG_BLENDFACTOR_BLEND_COLOR: return "SG_BLENDFACTOR_BLEND_COLOR"; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return "SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR"; - case SG_BLENDFACTOR_BLEND_ALPHA: return "SG_BLENDFACTOR_BLEND_ALPHA"; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return "SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_blendop_string(sg_blend_op op) { - switch (op) { - case SG_BLENDOP_ADD: return "SG_BLENDOP_ADD"; - case SG_BLENDOP_SUBTRACT: return "SG_BLENDOP_SUBTRACT"; - case SG_BLENDOP_REVERSE_SUBTRACT: return "SG_BLENDOP_REVERSE_SUBTRACT"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_colormask_string(sg_color_mask m) { - static const char* str[] = { - "NONE", - "R", - "G", - "RG", - "B", - "RB", - "GB", - "RGB", - "A", - "RA", - "GA", - "RGA", - "BA", - "RBA", - "GBA", - "RGBA", - }; - return str[m & 0xF]; -} - -_SOKOL_PRIVATE const char* _sgimgui_cullmode_string(sg_cull_mode cm) { - switch (cm) { - case SG_CULLMODE_NONE: return "SG_CULLMODE_NONE"; - case SG_CULLMODE_FRONT: return "SG_CULLMODE_FRONT"; - case SG_CULLMODE_BACK: return "SG_CULLMODE_BACK"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_facewinding_string(sg_face_winding fw) { - switch (fw) { - case SG_FACEWINDING_CCW: return "SG_FACEWINDING_CCW"; - case SG_FACEWINDING_CW: return "SG_FACEWINDING_CW"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_shaderstage_string(sg_shader_stage stage) { - switch (stage) { - case SG_SHADERSTAGE_VS: return "SG_SHADERSTAGE_VS"; - case SG_SHADERSTAGE_FS: return "SG_SHADERSTAGE_FS"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_bool_string(bool b) { - return b ? "true" : "false"; -} - -_SOKOL_PRIVATE const char* _sgimgui_color_string(sgimgui_str_t* dst_str, sg_color color) { - _sgimgui_snprintf(dst_str, "%.3f %.3f %.3f %.3f", color.r, color.g, color.b, color.a); - return dst_str->buf; -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_res_id_string(uint32_t res_id, const char* label) { - SOKOL_ASSERT(label); - sgimgui_str_t res; - if (label[0]) { - _sgimgui_snprintf(&res, "'%s'", label); - } else { - _sgimgui_snprintf(&res, "0x%08X", res_id); - } - return res; -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_buffer_id_string(sgimgui_t* ctx, sg_buffer buf_id) { - if (buf_id.id != SG_INVALID_ID) { - const sgimgui_buffer_t* buf_ui = &ctx->buffer_window.slots[_sgimgui_slot_index(buf_id.id)]; - return _sgimgui_res_id_string(buf_id.id, buf_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_image_id_string(sgimgui_t* ctx, sg_image img_id) { - if (img_id.id != SG_INVALID_ID) { - const sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img_id.id)]; - return _sgimgui_res_id_string(img_id.id, img_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_sampler_id_string(sgimgui_t* ctx, sg_sampler smp_id) { - if (smp_id.id != SG_INVALID_ID) { - const sgimgui_sampler_t* smp_ui = &ctx->sampler_window.slots[_sgimgui_slot_index(smp_id.id)]; - return _sgimgui_res_id_string(smp_id.id, smp_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_shader_id_string(sgimgui_t* ctx, sg_shader shd_id) { - if (shd_id.id != SG_INVALID_ID) { - const sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(shd_id.id)]; - return _sgimgui_res_id_string(shd_id.id, shd_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_pipeline_id_string(sgimgui_t* ctx, sg_pipeline pip_id) { - if (pip_id.id != SG_INVALID_ID) { - const sgimgui_pipeline_t* pip_ui = &ctx->pipeline_window.slots[_sgimgui_slot_index(pip_id.id)]; - return _sgimgui_res_id_string(pip_id.id, pip_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_attachments_id_string(sgimgui_t* ctx, sg_attachments atts_id) { - if (atts_id.id != SG_INVALID_ID) { - const sgimgui_attachments_t* atts_ui = &ctx->attachments_window.slots[_sgimgui_slot_index(atts_id.id)]; - return _sgimgui_res_id_string(atts_id.id, atts_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -/*--- RESOURCE HELPERS -------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_buffer_created(sgimgui_t* ctx, sg_buffer res_id, int slot_index, const sg_buffer_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->buffer_window.num_slots)); - sgimgui_buffer_t* buf = &ctx->buffer_window.slots[slot_index]; - buf->res_id = res_id; - buf->desc = *desc; - buf->label = _sgimgui_make_str(desc->label); -} - -_SOKOL_PRIVATE void _sgimgui_buffer_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->buffer_window.num_slots)); - sgimgui_buffer_t* buf = &ctx->buffer_window.slots[slot_index]; - buf->res_id.id = SG_INVALID_ID; -} - -_SOKOL_PRIVATE void _sgimgui_image_created(sgimgui_t* ctx, sg_image res_id, int slot_index, const sg_image_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->image_window.num_slots)); - sgimgui_image_t* img = &ctx->image_window.slots[slot_index]; - img->res_id = res_id; - img->desc = *desc; - img->ui_scale = 1.0f; - img->label = _sgimgui_make_str(desc->label); - simgui_image_desc_t simgui_img_desc; - _sgimgui_clear(&simgui_img_desc, sizeof(simgui_img_desc)); - simgui_img_desc.image = res_id; - // keep sampler at default, which will use sokol_imgui.h's default nearest-filtering sampler - img->simgui_img = simgui_make_image(&simgui_img_desc); -} - -_SOKOL_PRIVATE void _sgimgui_image_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->image_window.num_slots)); - sgimgui_image_t* img = &ctx->image_window.slots[slot_index]; - img->res_id.id = SG_INVALID_ID; - simgui_destroy_image(img->simgui_img); -} - -_SOKOL_PRIVATE void _sgimgui_sampler_created(sgimgui_t* ctx, sg_sampler res_id, int slot_index, const sg_sampler_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->sampler_window.num_slots)); - sgimgui_sampler_t* smp = &ctx->sampler_window.slots[slot_index]; - smp->res_id = res_id; - smp->desc = *desc; - smp->label = _sgimgui_make_str(desc->label); -} - -_SOKOL_PRIVATE void _sgimgui_sampler_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->sampler_window.num_slots)); - sgimgui_sampler_t* smp = &ctx->sampler_window.slots[slot_index]; - smp->res_id.id = SG_INVALID_ID; -} - -_SOKOL_PRIVATE void _sgimgui_shader_created(sgimgui_t* ctx, sg_shader res_id, int slot_index, const sg_shader_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->shader_window.num_slots)); - sgimgui_shader_t* shd = &ctx->shader_window.slots[slot_index]; - shd->res_id = res_id; - shd->desc = *desc; - shd->label = _sgimgui_make_str(desc->label); - if (shd->desc.vs.entry) { - shd->vs_entry = _sgimgui_make_str(shd->desc.vs.entry); - shd->desc.vs.entry = shd->vs_entry.buf; - } - if (shd->desc.fs.entry) { - shd->fs_entry = _sgimgui_make_str(shd->desc.fs.entry); - shd->desc.fs.entry = shd->fs_entry.buf; - } - if (shd->desc.vs.d3d11_target) { - shd->vs_d3d11_target = _sgimgui_make_str(shd->desc.vs.d3d11_target); - shd->desc.fs.d3d11_target = shd->vs_d3d11_target.buf; - } - if (shd->desc.fs.d3d11_target) { - shd->fs_d3d11_target = _sgimgui_make_str(shd->desc.fs.d3d11_target); - shd->desc.fs.d3d11_target = shd->fs_d3d11_target.buf; - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - sg_shader_uniform_desc* ud = &shd->desc.vs.uniform_blocks[i].uniforms[j]; - if (ud->name) { - shd->vs_uniform_name[i][j] = _sgimgui_make_str(ud->name); - ud->name = shd->vs_uniform_name[i][j].buf; - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - sg_shader_uniform_desc* ud = &shd->desc.fs.uniform_blocks[i].uniforms[j]; - if (ud->name) { - shd->fs_uniform_name[i][j] = _sgimgui_make_str(ud->name); - ud->name = shd->fs_uniform_name[i][j].buf; - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; i++) { - if (shd->desc.vs.image_sampler_pairs[i].glsl_name) { - shd->vs_image_sampler_name[i] = _sgimgui_make_str(shd->desc.vs.image_sampler_pairs[i].glsl_name); - shd->desc.vs.image_sampler_pairs[i].glsl_name = shd->vs_image_sampler_name[i].buf; - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; i++) { - if (shd->desc.fs.image_sampler_pairs[i].glsl_name) { - shd->fs_image_sampler_name[i] = _sgimgui_make_str(shd->desc.fs.image_sampler_pairs[i].glsl_name); - shd->desc.fs.image_sampler_pairs[i].glsl_name = shd->fs_image_sampler_name[i].buf; - } - } - if (shd->desc.vs.source) { - shd->desc.vs.source = _sgimgui_str_dup(&ctx->desc.allocator, shd->desc.vs.source); - } - if (shd->desc.vs.bytecode.ptr) { - shd->desc.vs.bytecode.ptr = _sgimgui_bin_dup(&ctx->desc.allocator, shd->desc.vs.bytecode.ptr, shd->desc.vs.bytecode.size); - } - if (shd->desc.fs.source) { - shd->desc.fs.source = _sgimgui_str_dup(&ctx->desc.allocator, shd->desc.fs.source); - } - if (shd->desc.fs.bytecode.ptr) { - shd->desc.fs.bytecode.ptr = _sgimgui_bin_dup(&ctx->desc.allocator, shd->desc.fs.bytecode.ptr, shd->desc.fs.bytecode.size); - } - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - sg_shader_attr_desc* ad = &shd->desc.attrs[i]; - if (ad->name) { - shd->attr_name[i] = _sgimgui_make_str(ad->name); - ad->name = shd->attr_name[i].buf; - } - if (ad->sem_name) { - shd->attr_sem_name[i] = _sgimgui_make_str(ad->sem_name); - ad->sem_name = shd->attr_sem_name[i].buf; - } - } -} - -_SOKOL_PRIVATE void _sgimgui_shader_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->shader_window.num_slots)); - sgimgui_shader_t* shd = &ctx->shader_window.slots[slot_index]; - shd->res_id.id = SG_INVALID_ID; - if (shd->desc.vs.source) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.vs.source); - shd->desc.vs.source = 0; - } - if (shd->desc.vs.bytecode.ptr) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.vs.bytecode.ptr); - shd->desc.vs.bytecode.ptr = 0; - } - if (shd->desc.fs.source) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.fs.source); - shd->desc.fs.source = 0; - } - if (shd->desc.fs.bytecode.ptr) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.fs.bytecode.ptr); - shd->desc.fs.bytecode.ptr = 0; - } -} - -_SOKOL_PRIVATE void _sgimgui_pipeline_created(sgimgui_t* ctx, sg_pipeline res_id, int slot_index, const sg_pipeline_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->pipeline_window.num_slots)); - sgimgui_pipeline_t* pip = &ctx->pipeline_window.slots[slot_index]; - pip->res_id = res_id; - pip->label = _sgimgui_make_str(desc->label); - pip->desc = *desc; - -} - -_SOKOL_PRIVATE void _sgimgui_pipeline_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->pipeline_window.num_slots)); - sgimgui_pipeline_t* pip = &ctx->pipeline_window.slots[slot_index]; - pip->res_id.id = SG_INVALID_ID; -} - -_SOKOL_PRIVATE void _sgimgui_attachments_created(sgimgui_t* ctx, sg_attachments res_id, int slot_index, const sg_attachments_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->attachments_window.num_slots)); - sgimgui_attachments_t* atts = &ctx->attachments_window.slots[slot_index]; - atts->res_id = res_id; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - atts->color_image_scale[i] = 0.25f; - atts->resolve_image_scale[i] = 0.25f; - } - atts->ds_image_scale = 0.25f; - atts->label = _sgimgui_make_str(desc->label); - atts->desc = *desc; -} - -_SOKOL_PRIVATE void _sgimgui_attachments_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->attachments_window.num_slots)); - sgimgui_attachments_t* atts = &ctx->attachments_window.slots[slot_index]; - atts->res_id.id = SG_INVALID_ID; -} - -/*--- COMMAND CAPTURING ------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_capture_init(sgimgui_t* ctx) { - const size_t ubuf_initial_size = 256 * 1024; - for (int i = 0; i < 2; i++) { - sgimgui_capture_bucket_t* bucket = &ctx->capture_window.bucket[i]; - bucket->ubuf_size = ubuf_initial_size; - bucket->ubuf = (uint8_t*) _sgimgui_malloc(&ctx->desc.allocator, bucket->ubuf_size); - } -} - -_SOKOL_PRIVATE void _sgimgui_capture_discard(sgimgui_t* ctx) { - for (int i = 0; i < 2; i++) { - sgimgui_capture_bucket_t* bucket = &ctx->capture_window.bucket[i]; - SOKOL_ASSERT(bucket->ubuf); - _sgimgui_free(&ctx->desc.allocator, bucket->ubuf); - bucket->ubuf = 0; - } -} - -_SOKOL_PRIVATE sgimgui_capture_bucket_t* _sgimgui_capture_get_write_bucket(sgimgui_t* ctx) { - return &ctx->capture_window.bucket[ctx->capture_window.bucket_index & 1]; -} - -_SOKOL_PRIVATE sgimgui_capture_bucket_t* _sgimgui_capture_get_read_bucket(sgimgui_t* ctx) { - return &ctx->capture_window.bucket[(ctx->capture_window.bucket_index + 1) & 1]; -} - -_SOKOL_PRIVATE void _sgimgui_capture_next_frame(sgimgui_t* ctx) { - ctx->capture_window.bucket_index = (ctx->capture_window.bucket_index + 1) & 1; - sgimgui_capture_bucket_t* bucket = &ctx->capture_window.bucket[ctx->capture_window.bucket_index]; - bucket->num_items = 0; - bucket->ubuf_pos = 0; -} - -_SOKOL_PRIVATE void _sgimgui_capture_grow_ubuf(sgimgui_t* ctx, size_t required_size) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_write_bucket(ctx); - SOKOL_ASSERT(required_size > bucket->ubuf_size); - size_t old_size = bucket->ubuf_size; - size_t new_size = required_size + (required_size>>1); /* allocate a bit ahead */ - bucket->ubuf_size = new_size; - bucket->ubuf = (uint8_t*) _sgimgui_realloc(&ctx->desc.allocator, bucket->ubuf, old_size, new_size); -} - -_SOKOL_PRIVATE sgimgui_capture_item_t* _sgimgui_capture_next_write_item(sgimgui_t* ctx) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_write_bucket(ctx); - if (bucket->num_items < sgimgui_MAX_FRAMECAPTURE_ITEMS) { - sgimgui_capture_item_t* item = &bucket->items[bucket->num_items++]; - return item; - } else { - return 0; - } -} - -_SOKOL_PRIVATE int _sgimgui_capture_num_read_items(sgimgui_t* ctx) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_read_bucket(ctx); - return bucket->num_items; -} - -_SOKOL_PRIVATE sgimgui_capture_item_t* _sgimgui_capture_read_item_at(sgimgui_t* ctx, int index) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_read_bucket(ctx); - SOKOL_ASSERT(index < bucket->num_items); - return &bucket->items[index]; -} - -_SOKOL_PRIVATE size_t _sgimgui_capture_uniforms(sgimgui_t* ctx, const sg_range* data) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_write_bucket(ctx); - const size_t required_size = bucket->ubuf_pos + data->size; - if (required_size > bucket->ubuf_size) { - _sgimgui_capture_grow_ubuf(ctx, required_size); - } - SOKOL_ASSERT(required_size <= bucket->ubuf_size); - memcpy(bucket->ubuf + bucket->ubuf_pos, data->ptr, data->size); - const size_t pos = bucket->ubuf_pos; - bucket->ubuf_pos += data->size; - SOKOL_ASSERT(bucket->ubuf_pos <= bucket->ubuf_size); - return pos; -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_capture_item_string(sgimgui_t* ctx, int index, const sgimgui_capture_item_t* item) { - sgimgui_str_t str = _sgimgui_make_str(0); - switch (item->cmd) { - case SGIMGUI_CMD_RESET_STATE_CACHE: - _sgimgui_snprintf(&str, "%d: sg_reset_state_cache()", index); - break; - - case SGIMGUI_CMD_MAKE_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.make_buffer.result); - _sgimgui_snprintf(&str, "%d: sg_make_buffer(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.make_image.result); - _sgimgui_snprintf(&str, "%d: sg_make_image(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.make_sampler.result); - _sgimgui_snprintf(&str, "%d: sg_make_sampler(desc=..) => %s", index, res_id.buf); - } - break; - case SGIMGUI_CMD_MAKE_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.make_shader.result); - _sgimgui_snprintf(&str, "%d: sg_make_shader(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.make_pipeline.result); - _sgimgui_snprintf(&str, "%d: sg_make_pipeline(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.make_attachments.result); - _sgimgui_snprintf(&str, "%d: sg_make_attachments(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.destroy_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_destroy_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.destroy_image.image); - _sgimgui_snprintf(&str, "%d: sg_destroy_image(img=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.destroy_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_destroy_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.destroy_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_destroy_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.destroy_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_destroy_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.destroy_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_destroy_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UPDATE_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.update_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_update_buffer(buf=%s, data.size=%d)", - index, res_id.buf, - item->args.update_buffer.data_size); - } - break; - - case SGIMGUI_CMD_UPDATE_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.update_image.image); - _sgimgui_snprintf(&str, "%d: sg_update_image(img=%s, data=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_APPEND_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.append_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_append_buffer(buf=%s, data.size=%d) => %d", - index, res_id.buf, - item->args.append_buffer.data_size, - item->args.append_buffer.result); - } - break; - - case SGIMGUI_CMD_BEGIN_PASS: - { - _sgimgui_snprintf(&str, "%d: sg_begin_pass(pass=...)", index); - } - break; - - case SGIMGUI_CMD_APPLY_VIEWPORT: - _sgimgui_snprintf(&str, "%d: sg_apply_viewport(x=%d, y=%d, width=%d, height=%d, origin_top_left=%s)", - index, - item->args.apply_viewport.x, - item->args.apply_viewport.y, - item->args.apply_viewport.width, - item->args.apply_viewport.height, - _sgimgui_bool_string(item->args.apply_viewport.origin_top_left)); - break; - - case SGIMGUI_CMD_APPLY_SCISSOR_RECT: - _sgimgui_snprintf(&str, "%d: sg_apply_scissor_rect(x=%d, y=%d, width=%d, height=%d, origin_top_left=%s)", - index, - item->args.apply_scissor_rect.x, - item->args.apply_scissor_rect.y, - item->args.apply_scissor_rect.width, - item->args.apply_scissor_rect.height, - _sgimgui_bool_string(item->args.apply_scissor_rect.origin_top_left)); - break; - - case SGIMGUI_CMD_APPLY_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.apply_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_apply_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_APPLY_BINDINGS: - _sgimgui_snprintf(&str, "%d: sg_apply_bindings(bindings=..)", index); - break; - - case SGIMGUI_CMD_APPLY_UNIFORMS: - _sgimgui_snprintf(&str, "%d: sg_apply_uniforms(stage=%s, ub_index=%d, data.size=%d)", - index, - _sgimgui_shaderstage_string(item->args.apply_uniforms.stage), - item->args.apply_uniforms.ub_index, - item->args.apply_uniforms.data_size); - break; - - case SGIMGUI_CMD_DRAW: - _sgimgui_snprintf(&str, "%d: sg_draw(base_element=%d, num_elements=%d, num_instances=%d)", - index, - item->args.draw.base_element, - item->args.draw.num_elements, - item->args.draw.num_instances); - break; - - case SGIMGUI_CMD_END_PASS: - _sgimgui_snprintf(&str, "%d: sg_end_pass()", index); - break; - - case SGIMGUI_CMD_COMMIT: - _sgimgui_snprintf(&str, "%d: sg_commit()", index); - break; - - case SGIMGUI_CMD_ALLOC_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.alloc_buffer.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_buffer() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.alloc_image.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_image() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.alloc_sampler.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_sampler() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.alloc_shader.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_shader() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.alloc_pipeline.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_pipeline() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.alloc_attachments.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_attachments() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.dealloc_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_dealloc_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.dealloc_image.image); - _sgimgui_snprintf(&str, "%d: sg_dealloc_image(img=%d)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.dealloc_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_dealloc_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.dealloc_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_dealloc_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.dealloc_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_dealloc_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.dealloc_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_dealloc_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.init_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_init_buffer(buf=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.init_image.image); - _sgimgui_snprintf(&str, "%d: sg_init_image(img=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.init_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_init_sampler(smp=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.init_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_init_shader(shd=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.init_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_init_pipeline(pip=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.init_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_init_attachments(atts=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.uninit_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_uninit_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.uninit_image.image); - _sgimgui_snprintf(&str, "%d: sg_uninit_image(img=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.uninit_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_uninit_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.uninit_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_uninit_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.uninit_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_uninit_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.uninit_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_uninit_attachemnts(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.fail_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_fail_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.fail_image.image); - _sgimgui_snprintf(&str, "%d: sg_fail_image(img=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.fail_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_fail_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.fail_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_fail_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.fail_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_fail_pipeline(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.fail_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_fail_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_PUSH_DEBUG_GROUP: - _sgimgui_snprintf(&str, "%d: sg_push_debug_group(name=%s)", index, - item->args.push_debug_group.name.buf); - break; - - case SGIMGUI_CMD_POP_DEBUG_GROUP: - _sgimgui_snprintf(&str, "%d: sg_pop_debug_group()", index); - break; - - default: - _sgimgui_snprintf(&str, "%d: ???", index); - break; - } - return str; -} - -/*--- CAPTURE CALLBACKS ------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_reset_state_cache(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_RESET_STATE_CACHE; - item->color = _SGIMGUI_COLOR_OTHER; - } - if (ctx->hooks.reset_state_cache) { - ctx->hooks.reset_state_cache(ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_buffer(const sg_buffer_desc* desc, sg_buffer buf_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_buffer.result = buf_id; - } - if (ctx->hooks.make_buffer) { - ctx->hooks.make_buffer(desc, buf_id, ctx->hooks.user_data); - } - if (buf_id.id != SG_INVALID_ID) { - _sgimgui_buffer_created(ctx, buf_id, _sgimgui_slot_index(buf_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_image(const sg_image_desc* desc, sg_image img_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_image.result = img_id; - } - if (ctx->hooks.make_image) { - ctx->hooks.make_image(desc, img_id, ctx->hooks.user_data); - } - if (img_id.id != SG_INVALID_ID) { - _sgimgui_image_created(ctx, img_id, _sgimgui_slot_index(img_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_sampler(const sg_sampler_desc* desc, sg_sampler smp_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_sampler.result = smp_id; - } - if (ctx->hooks.make_sampler) { - ctx->hooks.make_sampler(desc, smp_id, ctx->hooks.user_data); - } - if (smp_id.id != SG_INVALID_ID) { - _sgimgui_sampler_created(ctx, smp_id, _sgimgui_slot_index(smp_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_shader(const sg_shader_desc* desc, sg_shader shd_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_shader.result = shd_id; - } - if (ctx->hooks.make_shader) { - ctx->hooks.make_shader(desc, shd_id, ctx->hooks.user_data); - } - if (shd_id.id != SG_INVALID_ID) { - _sgimgui_shader_created(ctx, shd_id, _sgimgui_slot_index(shd_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_pipeline(const sg_pipeline_desc* desc, sg_pipeline pip_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_pipeline.result = pip_id; - } - if (ctx->hooks.make_pipeline) { - ctx->hooks.make_pipeline(desc, pip_id, ctx->hooks.user_data); - } - if (pip_id.id != SG_INVALID_ID) { - _sgimgui_pipeline_created(ctx, pip_id, _sgimgui_slot_index(pip_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_attachments(const sg_attachments_desc* desc, sg_attachments atts_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_attachments.result = atts_id; - } - if (ctx->hooks.make_attachments) { - ctx->hooks.make_attachments(desc, atts_id, ctx->hooks.user_data); - } - if (atts_id.id != SG_INVALID_ID) { - _sgimgui_attachments_created(ctx, atts_id, _sgimgui_slot_index(atts_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_buffer(sg_buffer buf, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_buffer.buffer = buf; - } - if (ctx->hooks.destroy_buffer) { - ctx->hooks.destroy_buffer(buf, ctx->hooks.user_data); - } - if (buf.id != SG_INVALID_ID) { - _sgimgui_buffer_destroyed(ctx, _sgimgui_slot_index(buf.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_image(sg_image img, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_image.image = img; - } - if (ctx->hooks.destroy_image) { - ctx->hooks.destroy_image(img, ctx->hooks.user_data); - } - if (img.id != SG_INVALID_ID) { - _sgimgui_image_destroyed(ctx, _sgimgui_slot_index(img.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_sampler(sg_sampler smp, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_sampler.sampler = smp; - } - if (ctx->hooks.destroy_sampler) { - ctx->hooks.destroy_sampler(smp, ctx->hooks.user_data); - } - if (smp.id != SG_INVALID_ID) { - _sgimgui_sampler_destroyed(ctx, _sgimgui_slot_index(smp.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_shader(sg_shader shd, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_shader.shader = shd; - } - if (ctx->hooks.destroy_shader) { - ctx->hooks.destroy_shader(shd, ctx->hooks.user_data); - } - if (shd.id != SG_INVALID_ID) { - _sgimgui_shader_destroyed(ctx, _sgimgui_slot_index(shd.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_pipeline(sg_pipeline pip, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_pipeline.pipeline = pip; - } - if (ctx->hooks.destroy_pipeline) { - ctx->hooks.destroy_pipeline(pip, ctx->hooks.user_data); - } - if (pip.id != SG_INVALID_ID) { - _sgimgui_pipeline_destroyed(ctx, _sgimgui_slot_index(pip.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_attachments(sg_attachments atts, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_attachments.attachments = atts; - } - if (ctx->hooks.destroy_attachments) { - ctx->hooks.destroy_attachments(atts, ctx->hooks.user_data); - } - if (atts.id != SG_INVALID_ID) { - _sgimgui_attachments_destroyed(ctx, _sgimgui_slot_index(atts.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_update_buffer(sg_buffer buf, const sg_range* data, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UPDATE_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.update_buffer.buffer = buf; - item->args.update_buffer.data_size = data->size; - } - if (ctx->hooks.update_buffer) { - ctx->hooks.update_buffer(buf, data, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_update_image(sg_image img, const sg_image_data* data, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UPDATE_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.update_image.image = img; - } - if (ctx->hooks.update_image) { - ctx->hooks.update_image(img, data, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_append_buffer(sg_buffer buf, const sg_range* data, int result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPEND_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.append_buffer.buffer = buf; - item->args.append_buffer.data_size = data->size; - item->args.append_buffer.result = result; - } - if (ctx->hooks.append_buffer) { - ctx->hooks.append_buffer(buf, data, result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_begin_pass(const sg_pass* pass, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - SOKOL_ASSERT(pass); - item->cmd = SGIMGUI_CMD_BEGIN_PASS; - item->color = _SGIMGUI_COLOR_PASS; - item->args.begin_pass.pass = *pass; - } - if (ctx->hooks.begin_pass) { - ctx->hooks.begin_pass(pass, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_viewport(int x, int y, int width, int height, bool origin_top_left, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_VIEWPORT; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_viewport.x = x; - item->args.apply_viewport.y = y; - item->args.apply_viewport.width = width; - item->args.apply_viewport.height = height; - item->args.apply_viewport.origin_top_left = origin_top_left; - } - if (ctx->hooks.apply_viewport) { - ctx->hooks.apply_viewport(x, y, width, height, origin_top_left, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_SCISSOR_RECT; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_scissor_rect.x = x; - item->args.apply_scissor_rect.y = y; - item->args.apply_scissor_rect.width = width; - item->args.apply_scissor_rect.height = height; - item->args.apply_scissor_rect.origin_top_left = origin_top_left; - } - if (ctx->hooks.apply_scissor_rect) { - ctx->hooks.apply_scissor_rect(x, y, width, height, origin_top_left, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_pipeline(sg_pipeline pip, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - ctx->cur_pipeline = pip; /* stored for _sgimgui_apply_uniforms */ - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_PIPELINE; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_pipeline.pipeline = pip; - } - if (ctx->hooks.apply_pipeline) { - ctx->hooks.apply_pipeline(pip, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_bindings(const sg_bindings* bindings, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - SOKOL_ASSERT(bindings); - item->cmd = SGIMGUI_CMD_APPLY_BINDINGS; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_bindings.bindings = *bindings; - } - if (ctx->hooks.apply_bindings) { - ctx->hooks.apply_bindings(bindings, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - SOKOL_ASSERT(data); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_UNIFORMS; - item->color = _SGIMGUI_COLOR_APPLY; - sgimgui_args_apply_uniforms_t* args = &item->args.apply_uniforms; - args->stage = stage; - args->ub_index = ub_index; - args->data_size = data->size; - args->pipeline = ctx->cur_pipeline; - args->ubuf_pos = _sgimgui_capture_uniforms(ctx, data); - } - if (ctx->hooks.apply_uniforms) { - ctx->hooks.apply_uniforms(stage, ub_index, data, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw(int base_element, int num_elements, int num_instances, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DRAW; - item->color = _SGIMGUI_COLOR_DRAW; - item->args.draw.base_element = base_element; - item->args.draw.num_elements = num_elements; - item->args.draw.num_instances = num_instances; - } - if (ctx->hooks.draw) { - ctx->hooks.draw(base_element, num_elements, num_instances, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_end_pass(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - ctx->cur_pipeline.id = SG_INVALID_ID; - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_END_PASS; - item->color = _SGIMGUI_COLOR_PASS; - } - if (ctx->hooks.end_pass) { - ctx->hooks.end_pass(ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_commit(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_COMMIT; - item->color = _SGIMGUI_COLOR_OTHER; - } - _sgimgui_capture_next_frame(ctx); - if (ctx->hooks.commit) { - ctx->hooks.commit(ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_buffer(sg_buffer result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_buffer.result = result; - } - if (ctx->hooks.alloc_buffer) { - ctx->hooks.alloc_buffer(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_image(sg_image result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_image.result = result; - } - if (ctx->hooks.alloc_image) { - ctx->hooks.alloc_image(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_sampler(sg_sampler result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_sampler.result = result; - } - if (ctx->hooks.alloc_sampler) { - ctx->hooks.alloc_sampler(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_shader(sg_shader result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_shader.result = result; - } - if (ctx->hooks.alloc_shader) { - ctx->hooks.alloc_shader(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_pipeline(sg_pipeline result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_pipeline.result = result; - } - if (ctx->hooks.alloc_pipeline) { - ctx->hooks.alloc_pipeline(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_attachments(sg_attachments result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_attachments.result = result; - } - if (ctx->hooks.alloc_attachments) { - ctx->hooks.alloc_attachments(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_buffer(sg_buffer buf_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_buffer.buffer = buf_id; - } - if (ctx->hooks.dealloc_buffer) { - ctx->hooks.dealloc_buffer(buf_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_image(sg_image img_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_image.image = img_id; - } - if (ctx->hooks.dealloc_image) { - ctx->hooks.dealloc_image(img_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_sampler(sg_sampler smp_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_sampler.sampler = smp_id; - } - if (ctx->hooks.dealloc_sampler) { - ctx->hooks.dealloc_sampler(smp_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_shader(sg_shader shd_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_shader.shader = shd_id; - } - if (ctx->hooks.dealloc_shader) { - ctx->hooks.dealloc_shader(shd_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_pipeline(sg_pipeline pip_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_pipeline.pipeline = pip_id; - } - if (ctx->hooks.dealloc_pipeline) { - ctx->hooks.dealloc_pipeline(pip_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_attachments(sg_attachments atts_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_attachments.attachments = atts_id; - } - if (ctx->hooks.dealloc_attachments) { - ctx->hooks.dealloc_attachments(atts_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_buffer.buffer = buf_id; - } - if (ctx->hooks.init_buffer) { - ctx->hooks.init_buffer(buf_id, desc, ctx->hooks.user_data); - } - if (buf_id.id != SG_INVALID_ID) { - _sgimgui_buffer_created(ctx, buf_id, _sgimgui_slot_index(buf_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_image(sg_image img_id, const sg_image_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_image.image = img_id; - } - if (ctx->hooks.init_image) { - ctx->hooks.init_image(img_id, desc, ctx->hooks.user_data); - } - if (img_id.id != SG_INVALID_ID) { - _sgimgui_image_created(ctx, img_id, _sgimgui_slot_index(img_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_sampler(sg_sampler smp_id, const sg_sampler_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_sampler.sampler = smp_id; - } - if (ctx->hooks.init_sampler) { - ctx->hooks.init_sampler(smp_id, desc, ctx->hooks.user_data); - } - if (smp_id.id != SG_INVALID_ID) { - _sgimgui_sampler_created(ctx, smp_id, _sgimgui_slot_index(smp_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_shader(sg_shader shd_id, const sg_shader_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_shader.shader = shd_id; - } - if (ctx->hooks.init_shader) { - ctx->hooks.init_shader(shd_id, desc, ctx->hooks.user_data); - } - if (shd_id.id != SG_INVALID_ID) { - _sgimgui_shader_created(ctx, shd_id, _sgimgui_slot_index(shd_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_pipeline.pipeline = pip_id; - } - if (ctx->hooks.init_pipeline) { - ctx->hooks.init_pipeline(pip_id, desc, ctx->hooks.user_data); - } - if (pip_id.id != SG_INVALID_ID) { - _sgimgui_pipeline_created(ctx, pip_id, _sgimgui_slot_index(pip_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_attachments(sg_attachments atts_id, const sg_attachments_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_attachments.attachments = atts_id; - } - if (ctx->hooks.init_attachments) { - ctx->hooks.init_attachments(atts_id, desc, ctx->hooks.user_data); - } - if (atts_id.id != SG_INVALID_ID) { - _sgimgui_attachments_created(ctx, atts_id, _sgimgui_slot_index(atts_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_buffer(sg_buffer buf, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_buffer.buffer = buf; - } - if (ctx->hooks.uninit_buffer) { - ctx->hooks.uninit_buffer(buf, ctx->hooks.user_data); - } - if (buf.id != SG_INVALID_ID) { - _sgimgui_buffer_destroyed(ctx, _sgimgui_slot_index(buf.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_image(sg_image img, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_image.image = img; - } - if (ctx->hooks.uninit_image) { - ctx->hooks.uninit_image(img, ctx->hooks.user_data); - } - if (img.id != SG_INVALID_ID) { - _sgimgui_image_destroyed(ctx, _sgimgui_slot_index(img.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_sampler(sg_sampler smp, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_sampler.sampler = smp; - } - if (ctx->hooks.uninit_sampler) { - ctx->hooks.uninit_sampler(smp, ctx->hooks.user_data); - } - if (smp.id != SG_INVALID_ID) { - _sgimgui_sampler_destroyed(ctx, _sgimgui_slot_index(smp.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_shader(sg_shader shd, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_shader.shader = shd; - } - if (ctx->hooks.uninit_shader) { - ctx->hooks.uninit_shader(shd, ctx->hooks.user_data); - } - if (shd.id != SG_INVALID_ID) { - _sgimgui_shader_destroyed(ctx, _sgimgui_slot_index(shd.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_pipeline(sg_pipeline pip, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_pipeline.pipeline = pip; - } - if (ctx->hooks.uninit_pipeline) { - ctx->hooks.uninit_pipeline(pip, ctx->hooks.user_data); - } - if (pip.id != SG_INVALID_ID) { - _sgimgui_pipeline_destroyed(ctx, _sgimgui_slot_index(pip.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_attachments(sg_attachments atts, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_attachments.attachments = atts; - } - if (ctx->hooks.uninit_attachments) { - ctx->hooks.uninit_attachments(atts, ctx->hooks.user_data); - } - if (atts.id != SG_INVALID_ID) { - _sgimgui_attachments_destroyed(ctx, _sgimgui_slot_index(atts.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_buffer(sg_buffer buf_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_buffer.buffer = buf_id; - } - if (ctx->hooks.fail_buffer) { - ctx->hooks.fail_buffer(buf_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_image(sg_image img_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_image.image = img_id; - } - if (ctx->hooks.fail_image) { - ctx->hooks.fail_image(img_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_sampler(sg_sampler smp_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_sampler.sampler = smp_id; - } - if (ctx->hooks.fail_sampler) { - ctx->hooks.fail_sampler(smp_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_shader(sg_shader shd_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_shader.shader = shd_id; - } - if (ctx->hooks.fail_shader) { - ctx->hooks.fail_shader(shd_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_pipeline(sg_pipeline pip_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_pipeline.pipeline = pip_id; - } - if (ctx->hooks.fail_pipeline) { - ctx->hooks.fail_pipeline(pip_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_attachments(sg_attachments atts_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_attachments.attachments = atts_id; - } - if (ctx->hooks.fail_attachments) { - ctx->hooks.fail_attachments(atts_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_push_debug_group(const char* name, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - if (0 == strcmp(name, "sokol-imgui")) { - ctx->frame_stats_window.in_sokol_imgui = true; - if (ctx->frame_stats_window.disable_sokol_imgui_stats) { - sg_disable_frame_stats(); - } - } - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_PUSH_DEBUG_GROUP; - item->color = _SGIMGUI_COLOR_OTHER; - item->args.push_debug_group.name = _sgimgui_make_str(name); - } - if (ctx->hooks.push_debug_group) { - ctx->hooks.push_debug_group(name, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_pop_debug_group(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - if (ctx->frame_stats_window.in_sokol_imgui) { - ctx->frame_stats_window.in_sokol_imgui = false; - if (ctx->frame_stats_window.disable_sokol_imgui_stats) { - sg_enable_frame_stats(); - } - } - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_POP_DEBUG_GROUP; - item->color = _SGIMGUI_COLOR_OTHER; - } - if (ctx->hooks.pop_debug_group) { - ctx->hooks.pop_debug_group(ctx->hooks.user_data); - } -} - -/*--- IMGUI HELPERS ----------------------------------------------------------*/ -_SOKOL_PRIVATE bool _sgimgui_draw_resid_list_item(uint32_t res_id, const char* label, bool selected) { - igPushID_Int((int)res_id); - bool res; - if (label[0]) { - res = igSelectable_Bool(label, selected, 0, IMVEC2(0,0)); - } else { - sgimgui_str_t str; - _sgimgui_snprintf(&str, "0x%08X", res_id); - res = igSelectable_Bool(str.buf, selected, 0, IMVEC2(0,0)); - } - igPopID(); - return res; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_resid_link(uint32_t res_type, uint32_t res_id, const char* label) { - SOKOL_ASSERT(label); - sgimgui_str_t str_buf; - const char* str; - if (label[0]) { - str = label; - } else { - _sgimgui_snprintf(&str_buf, "0x%08X", res_id); - str = str_buf.buf; - } - igPushID_Int((int)((res_type<<24)|res_id)); - bool res = igSmallButton(str); - igPopID(); - return res; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_buffer_link(sgimgui_t* ctx, sg_buffer buf) { - bool retval = false; - if (buf.id != SG_INVALID_ID) { - const sgimgui_buffer_t* buf_ui = &ctx->buffer_window.slots[_sgimgui_slot_index(buf.id)]; - retval = _sgimgui_draw_resid_link(1, buf.id, buf_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_image_link(sgimgui_t* ctx, sg_image img) { - bool retval = false; - if (img.id != SG_INVALID_ID) { - const sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img.id)]; - retval = _sgimgui_draw_resid_link(2, img.id, img_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_sampler_link(sgimgui_t* ctx, sg_sampler smp) { - bool retval = false; - if (smp.id != SG_INVALID_ID) { - const sgimgui_sampler_t* smp_ui = &ctx->sampler_window.slots[_sgimgui_slot_index(smp.id)]; - retval = _sgimgui_draw_resid_link(2, smp.id, smp_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_shader_link(sgimgui_t* ctx, sg_shader shd) { - bool retval = false; - if (shd.id != SG_INVALID_ID) { - const sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(shd.id)]; - retval = _sgimgui_draw_resid_link(3, shd.id, shd_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE void _sgimgui_show_buffer(sgimgui_t* ctx, sg_buffer buf) { - ctx->buffer_window.open = true; - ctx->buffer_window.sel_buf = buf; -} - -_SOKOL_PRIVATE void _sgimgui_show_image(sgimgui_t* ctx, sg_image img) { - ctx->image_window.open = true; - ctx->image_window.sel_img = img; -} - -_SOKOL_PRIVATE void _sgimgui_show_sampler(sgimgui_t* ctx, sg_sampler smp) { - ctx->sampler_window.open = true; - ctx->sampler_window.sel_smp = smp; -} - -_SOKOL_PRIVATE void _sgimgui_show_shader(sgimgui_t* ctx, sg_shader shd) { - ctx->shader_window.open = true; - ctx->shader_window.sel_shd = shd; -} - -_SOKOL_PRIVATE void _sgimgui_draw_buffer_list(sgimgui_t* ctx) { - igBeginChild_Str("buffer_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->buffer_window.num_slots; i++) { - sg_buffer buf = ctx->buffer_window.slots[i].res_id; - sg_resource_state state = sg_query_buffer_state(buf); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->buffer_window.sel_buf.id == buf.id; - if (_sgimgui_draw_resid_list_item(buf.id, ctx->buffer_window.slots[i].label.buf, selected)) { - ctx->buffer_window.sel_buf.id = buf.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_image_list(sgimgui_t* ctx) { - igBeginChild_Str("image_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->image_window.num_slots; i++) { - sg_image img = ctx->image_window.slots[i].res_id; - sg_resource_state state = sg_query_image_state(img); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->image_window.sel_img.id == img.id; - if (_sgimgui_draw_resid_list_item(img.id, ctx->image_window.slots[i].label.buf, selected)) { - ctx->image_window.sel_img.id = img.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_sampler_list(sgimgui_t* ctx) { - igBeginChild_Str("sampler_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->sampler_window.num_slots; i++) { - sg_sampler smp = ctx->sampler_window.slots[i].res_id; - sg_resource_state state = sg_query_sampler_state(smp); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->sampler_window.sel_smp.id == smp.id; - if (_sgimgui_draw_resid_list_item(smp.id, ctx->sampler_window.slots[i].label.buf, selected)) { - ctx->sampler_window.sel_smp.id = smp.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_shader_list(sgimgui_t* ctx) { - igBeginChild_Str("shader_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->shader_window.num_slots; i++) { - sg_shader shd = ctx->shader_window.slots[i].res_id; - sg_resource_state state = sg_query_shader_state(shd); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->shader_window.sel_shd.id == shd.id; - if (_sgimgui_draw_resid_list_item(shd.id, ctx->shader_window.slots[i].label.buf, selected)) { - ctx->shader_window.sel_shd.id = shd.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_pipeline_list(sgimgui_t* ctx) { - igBeginChild_Str("pipeline_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 1; i < ctx->pipeline_window.num_slots; i++) { - sg_pipeline pip = ctx->pipeline_window.slots[i].res_id; - sg_resource_state state = sg_query_pipeline_state(pip); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->pipeline_window.sel_pip.id == pip.id; - if (_sgimgui_draw_resid_list_item(pip.id, ctx->pipeline_window.slots[i].label.buf, selected)) { - ctx->pipeline_window.sel_pip.id = pip.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_attachments_list(sgimgui_t* ctx) { - igBeginChild_Str("pass_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 1; i < ctx->attachments_window.num_slots; i++) { - sg_attachments atts = ctx->attachments_window.slots[i].res_id; - sg_resource_state state = sg_query_attachments_state(atts); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->attachments_window.sel_atts.id == atts.id; - if (_sgimgui_draw_resid_list_item(atts.id, ctx->attachments_window.slots[i].label.buf, selected)) { - ctx->attachments_window.sel_atts.id = atts.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_capture_list(sgimgui_t* ctx) { - igBeginChild_Str("capture_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - const int num_items = _sgimgui_capture_num_read_items(ctx); - uint64_t group_stack = 1; /* bit set: group unfolded, cleared: folded */ - for (int i = 0; i < num_items; i++) { - const sgimgui_capture_item_t* item = _sgimgui_capture_read_item_at(ctx, i); - sgimgui_str_t item_string = _sgimgui_capture_item_string(ctx, i, item); - igPushStyleColor_U32(ImGuiCol_Text, item->color); - igPushID_Int(i); - if (item->cmd == SGIMGUI_CMD_PUSH_DEBUG_GROUP) { - if (group_stack & 1) { - group_stack <<= 1; - const char* group_name = item->args.push_debug_group.name.buf; - if (igTreeNode_StrStr(group_name, "Group: %s", group_name)) { - group_stack |= 1; - } - } else { - group_stack <<= 1; - } - } else if (item->cmd == SGIMGUI_CMD_POP_DEBUG_GROUP) { - if (group_stack & 1) { - igTreePop(); - } - group_stack >>= 1; - } else if (group_stack & 1) { - if (igSelectable_Bool(item_string.buf, ctx->capture_window.sel_item == i, 0, IMVEC2(0,0))) { - ctx->capture_window.sel_item = i; - } - if (igIsItemHovered(0)) { - igSetTooltip("%s", item_string.buf); - } - } - igPopID(); - igPopStyleColor(1); - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_buffer_panel(sgimgui_t* ctx, sg_buffer buf) { - if (buf.id != SG_INVALID_ID) { - igBeginChild_Str("buffer", IMVEC2(0,0), false, 0); - sg_buffer_info info = sg_query_buffer_info(buf); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - const sgimgui_buffer_t* buf_ui = &ctx->buffer_window.slots[_sgimgui_slot_index(buf.id)]; - igText("Label: %s", buf_ui->label.buf[0] ? buf_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - igText("Type: %s", _sgimgui_buffertype_string(buf_ui->desc.type)); - igText("Usage: %s", _sgimgui_usage_string(buf_ui->desc.usage)); - igText("Size: %d", buf_ui->desc.size); - if (buf_ui->desc.usage != SG_USAGE_IMMUTABLE) { - igSeparator(); - igText("Num Slots: %d", info.num_slots); - igText("Active Slot: %d", info.active_slot); - igText("Update Frame Index: %d", info.update_frame_index); - igText("Append Frame Index: %d", info.append_frame_index); - igText("Append Pos: %d", info.append_pos); - igText("Append Overflow: %s", _sgimgui_bool_string(info.append_overflow)); - } - } else { - igText("Buffer 0x%08X not valid.", buf.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE bool _sgimgui_image_renderable(sg_image_type type, sg_pixel_format fmt, int sample_count) { - return (type == SG_IMAGETYPE_2D) - && sg_query_pixelformat(fmt).sample - && sample_count == 1; -} - -_SOKOL_PRIVATE void _sgimgui_draw_embedded_image(sgimgui_t* ctx, sg_image img, float* scale) { - if (sg_query_image_state(img) == SG_RESOURCESTATE_VALID) { - sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img.id)]; - if (_sgimgui_image_renderable(img_ui->desc.type, img_ui->desc.pixel_format, img_ui->desc.sample_count)) { - igPushID_Int((int)img.id); - igSliderFloat("Scale", scale, 0.125f, 8.0f, "%.3f", ImGuiSliderFlags_Logarithmic); - float w = (float)img_ui->desc.width * (*scale); - float h = (float)img_ui->desc.height * (*scale); - igImage(simgui_imtextureid(img_ui->simgui_img), IMVEC2(w, h), IMVEC2(0,0), IMVEC2(1,1), IMVEC4(1,1,1,1), IMVEC4(0,0,0,0)); - igPopID(); - } else { - igText("Image not renderable."); - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_image_panel(sgimgui_t* ctx, sg_image img) { - if (img.id != SG_INVALID_ID) { - igBeginChild_Str("image", IMVEC2(0,0), false, 0); - sg_image_info info = sg_query_image_info(img); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img.id)]; - const sg_image_desc* desc = &img_ui->desc; - igText("Label: %s", img_ui->label.buf[0] ? img_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - _sgimgui_draw_embedded_image(ctx, img, &img_ui->ui_scale); - igSeparator(); - igText("Type: %s", _sgimgui_imagetype_string(desc->type)); - igText("Usage: %s", _sgimgui_usage_string(desc->usage)); - igText("Render Target: %s", _sgimgui_bool_string(desc->render_target)); - igText("Width: %d", desc->width); - igText("Height: %d", desc->height); - igText("Num Slices: %d", desc->num_slices); - igText("Num Mipmaps: %d", desc->num_mipmaps); - igText("Pixel Format: %s", _sgimgui_pixelformat_string(desc->pixel_format)); - igText("Sample Count: %d", desc->sample_count); - if (desc->usage != SG_USAGE_IMMUTABLE) { - igSeparator(); - igText("Num Slots: %d", info.num_slots); - igText("Active Slot: %d", info.active_slot); - igText("Update Frame Index: %d", info.upd_frame_index); - } - } else { - igText("Image 0x%08X not valid.", img.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_sampler_panel(sgimgui_t* ctx, sg_sampler smp) { - if (smp.id != SG_INVALID_ID) { - igBeginChild_Str("sampler", IMVEC2(0,0), false, 0); - sg_sampler_info info = sg_query_sampler_info(smp); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - sgimgui_sampler_t* smp_ui = &ctx->sampler_window.slots[_sgimgui_slot_index(smp.id)]; - const sg_sampler_desc* desc = &smp_ui->desc; - igText("Label: %s", smp_ui->label.buf[0] ? smp_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - igText("Min Filter: %s", _sgimgui_filter_string(desc->min_filter)); - igText("Mag Filter: %s", _sgimgui_filter_string(desc->mag_filter)); - igText("Mipmap Filter: %s", _sgimgui_filter_string(desc->mipmap_filter)); - igText("Wrap U: %s", _sgimgui_wrap_string(desc->wrap_u)); - igText("Wrap V: %s", _sgimgui_wrap_string(desc->wrap_v)); - igText("Wrap W: %s", _sgimgui_wrap_string(desc->wrap_w)); - igText("Min LOD: %.3f", desc->min_lod); - igText("Max LOD: %.3f", desc->max_lod); - igText("Border Color: %s", _sgimgui_bordercolor_string(desc->border_color)); - igText("Compare: %s", _sgimgui_comparefunc_string(desc->compare)); - igText("Max Anisotropy: %d", desc->max_anisotropy); - } else { - igText("Sampler 0x%08X not valid.", smp.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_shader_stage(const sg_shader_stage_desc* stage) { - int num_valid_ubs = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - const sg_shader_uniform_block_desc* ub = &stage->uniform_blocks[i]; - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - const sg_shader_uniform_desc* u = &ub->uniforms[j]; - if (SG_UNIFORMTYPE_INVALID != u->type) { - num_valid_ubs++; - break; - } - } - } - int num_valid_images = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - if (stage->images[i].used) { - num_valid_images++; - } else { - break; - } - } - int num_valid_samplers = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - if (stage->samplers[i].used) { - num_valid_samplers++; - } else { - break; - } - } - int num_valid_image_sampler_pairs = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; i++) { - if (stage->image_sampler_pairs[i].used) { - num_valid_image_sampler_pairs++; - } else { - break; - } - } - if (num_valid_ubs > 0) { - if (igTreeNode_Str("Uniform Blocks")) { - for (int i = 0; i < num_valid_ubs; i++) { - const sg_shader_uniform_block_desc* ub = &stage->uniform_blocks[i]; - igText("#%d: (size: %d layout: %s)\n", i, ub->size, _sgimgui_uniformlayout_string(ub->layout)); - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - const sg_shader_uniform_desc* u = &ub->uniforms[j]; - if (SG_UNIFORMTYPE_INVALID != u->type) { - if (u->array_count <= 1) { - igText(" %s %s", _sgimgui_uniformtype_string(u->type), u->name ? u->name : ""); - } else { - igText(" %s[%d] %s", _sgimgui_uniformtype_string(u->type), u->array_count, u->name ? u->name : ""); - } - } - } - } - igTreePop(); - } - } - if (num_valid_images > 0) { - if (igTreeNode_Str("Images")) { - for (int i = 0; i < num_valid_images; i++) { - const sg_shader_image_desc* sid = &stage->images[i]; - igText("slot: %d\n multisampled: %s\n image_type: %s\n sample_type: %s", - i, - sid->multisampled ? "true" : "false", - _sgimgui_imagetype_string(sid->image_type), - _sgimgui_imagesampletype_string(sid->sample_type)); - } - igTreePop(); - } - } - if (num_valid_samplers > 0) { - if (igTreeNode_Str("Samplers")) { - for (int i = 0; i < num_valid_samplers; i++) { - const sg_shader_sampler_desc* ssd = &stage->samplers[i]; - igText("slot: %d\n sampler_type: %s", i, _sgimgui_samplertype_string(ssd->sampler_type)); - } - igTreePop(); - } - } - if (num_valid_image_sampler_pairs > 0) { - if (igTreeNode_Str("Image Sampler Pairs")) { - for (int i = 0; i < num_valid_image_sampler_pairs; i++) { - const sg_shader_image_sampler_pair_desc* sispd = &stage->image_sampler_pairs[i]; - igText("slot: %d\n image_slot: %d\n sampler_slot: %d\n glsl_name: %s\n", - i, - sispd->image_slot, - sispd->sampler_slot, - sispd->glsl_name ? sispd->glsl_name : "---"); - } - igTreePop(); - } - } - if (stage->entry) { - igText("Entry: %s", stage->entry); - } - if (stage->d3d11_target) { - igText("D3D11 Target: %s", stage->d3d11_target); - } - if (stage->source) { - if (igTreeNode_Str("Source")) { - igText("%s", stage->source); - igTreePop(); - } - } else if (stage->bytecode.ptr) { - if (igTreeNode_Str("Byte Code")) { - igText("Byte-code display currently not supported."); - igTreePop(); - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { - if (shd.id != SG_INVALID_ID) { - igBeginChild_Str("shader", IMVEC2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); - sg_shader_info info = sg_query_shader_info(shd); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - const sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(shd.id)]; - igText("Label: %s", shd_ui->label.buf[0] ? shd_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - if (igTreeNode_Str("Attrs")) { - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - const sg_shader_attr_desc* a_desc = &shd_ui->desc.attrs[i]; - if (a_desc->name || a_desc->sem_index) { - igText("#%d:", i); - igText(" Name: %s", a_desc->name ? a_desc->name : "---"); - igText(" Sem Name: %s", a_desc->sem_name ? a_desc->sem_name : "---"); - igText(" Sem Index: %d", a_desc->sem_index); - } - } - igTreePop(); - } - if (igTreeNode_Str("Vertex Shader Stage")) { - _sgimgui_draw_shader_stage(&shd_ui->desc.vs); - igTreePop(); - } - if (igTreeNode_Str("Fragment Shader Stage")) { - _sgimgui_draw_shader_stage(&shd_ui->desc.fs); - igTreePop(); - } - } else { - igText("Shader 0x%08X not valid!", shd.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_vertex_layout_state(const sg_vertex_layout_state* layout) { - if (igTreeNode_Str("Buffers")) { - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++) { - const sg_vertex_buffer_layout_state* l_state = &layout->buffers[i]; - if (l_state->stride > 0) { - igText("#%d:", i); - igText(" Stride: %d", l_state->stride); - igText(" Step Func: %s", _sgimgui_vertexstep_string(l_state->step_func)); - igText(" Step Rate: %d", l_state->step_rate); - } - } - igTreePop(); - } - if (igTreeNode_Str("Attrs")) { - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - const sg_vertex_attr_state* a_state = &layout->attrs[i]; - if (a_state->format != SG_VERTEXFORMAT_INVALID) { - igText("#%d:", i); - igText(" Format: %s", _sgimgui_vertexformat_string(a_state->format)); - igText(" Offset: %d", a_state->offset); - igText(" Buffer Index: %d", a_state->buffer_index); - } - } - igTreePop(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_stencil_face_state(const sg_stencil_face_state* sfs) { - igText("Fail Op: %s", _sgimgui_stencilop_string(sfs->fail_op)); - igText("Depth Fail Op: %s", _sgimgui_stencilop_string(sfs->depth_fail_op)); - igText("Pass Op: %s", _sgimgui_stencilop_string(sfs->pass_op)); - igText("Compare: %s", _sgimgui_comparefunc_string(sfs->compare)); -} - -_SOKOL_PRIVATE void _sgimgui_draw_stencil_state(const sg_stencil_state* ss) { - igText("Enabled: %s", _sgimgui_bool_string(ss->enabled)); - igText("Read Mask: 0x%02X", ss->read_mask); - igText("Write Mask: 0x%02X", ss->write_mask); - igText("Ref: 0x%02X", ss->ref); - if (igTreeNode_Str("Front")) { - _sgimgui_draw_stencil_face_state(&ss->front); - igTreePop(); - } - if (igTreeNode_Str("Back")) { - _sgimgui_draw_stencil_face_state(&ss->back); - igTreePop(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_depth_state(const sg_depth_state* ds) { - igText("Pixel Format: %s", _sgimgui_pixelformat_string(ds->pixel_format)); - igText("Compare: %s", _sgimgui_comparefunc_string(ds->compare)); - igText("Write Enabled: %s", _sgimgui_bool_string(ds->write_enabled)); - igText("Bias: %f", ds->bias); - igText("Bias Slope: %f", ds->bias_slope_scale); - igText("Bias Clamp: %f", ds->bias_clamp); -} - -_SOKOL_PRIVATE void _sgimgui_draw_blend_state(const sg_blend_state* bs) { - igText("Blend Enabled: %s", _sgimgui_bool_string(bs->enabled)); - igText("Src Factor RGB: %s", _sgimgui_blendfactor_string(bs->src_factor_rgb)); - igText("Dst Factor RGB: %s", _sgimgui_blendfactor_string(bs->dst_factor_rgb)); - igText("Op RGB: %s", _sgimgui_blendop_string(bs->op_rgb)); - igText("Src Factor Alpha: %s", _sgimgui_blendfactor_string(bs->src_factor_alpha)); - igText("Dst Factor Alpha: %s", _sgimgui_blendfactor_string(bs->dst_factor_alpha)); - igText("Op Alpha: %s", _sgimgui_blendop_string(bs->op_alpha)); -} - -_SOKOL_PRIVATE void _sgimgui_draw_color_target_state(const sg_color_target_state* cs) { - igText("Pixel Format: %s", _sgimgui_pixelformat_string(cs->pixel_format)); - igText("Write Mask: %s", _sgimgui_colormask_string(cs->write_mask)); - if (igTreeNode_Str("Blend State:")) { - _sgimgui_draw_blend_state(&cs->blend); - igTreePop(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_pipeline_panel(sgimgui_t* ctx, sg_pipeline pip) { - if (pip.id != SG_INVALID_ID) { - igBeginChild_Str("pipeline", IMVEC2(0,0), false, 0); - sg_pipeline_info info = sg_query_pipeline_info(pip); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - const sgimgui_pipeline_t* pip_ui = &ctx->pipeline_window.slots[_sgimgui_slot_index(pip.id)]; - igText("Label: %s", pip_ui->label.buf[0] ? pip_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - igText("Shader: "); igSameLine(0,-1); - if (_sgimgui_draw_shader_link(ctx, pip_ui->desc.shader)) { - _sgimgui_show_shader(ctx, pip_ui->desc.shader); - } - if (igTreeNode_Str("Vertex Layout State")) { - _sgimgui_draw_vertex_layout_state(&pip_ui->desc.layout); - igTreePop(); - } - if (igTreeNode_Str("Depth State")) { - _sgimgui_draw_depth_state(&pip_ui->desc.depth); - igTreePop(); - } - if (igTreeNode_Str("Stencil State")) { - _sgimgui_draw_stencil_state(&pip_ui->desc.stencil); - igTreePop(); - } - igText("Color Count: %d", pip_ui->desc.color_count); - for (int i = 0; i < pip_ui->desc.color_count; i++) { - sgimgui_str_t str; - _sgimgui_snprintf(&str, "Color Target %d", i); - if (igTreeNode_Str(str.buf)) { - _sgimgui_draw_color_target_state(&pip_ui->desc.colors[i]); - igTreePop(); - } - } - igText("Prim Type: %s", _sgimgui_primitivetype_string(pip_ui->desc.primitive_type)); - igText("Index Type: %s", _sgimgui_indextype_string(pip_ui->desc.index_type)); - igText("Cull Mode: %s", _sgimgui_cullmode_string(pip_ui->desc.cull_mode)); - igText("Face Winding: %s", _sgimgui_facewinding_string(pip_ui->desc.face_winding)); - igText("Sample Count: %d", pip_ui->desc.sample_count); - sgimgui_str_t blend_color_str; - igText("Blend Color: %.3f %.3f %.3f %.3f", _sgimgui_color_string(&blend_color_str, pip_ui->desc.blend_color)); - igText("Alpha To Coverage: %s", _sgimgui_bool_string(pip_ui->desc.alpha_to_coverage_enabled)); - } else { - igText("Pipeline 0x%08X not valid.", pip.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_attachment(sgimgui_t* ctx, const sg_attachment_desc* att, float* img_scale) { - igText(" Image: "); igSameLine(0,-1); - if (_sgimgui_draw_image_link(ctx, att->image)) { - _sgimgui_show_image(ctx, att->image); - } - igText(" Mip Level: %d", att->mip_level); - igText(" Slice: %d", att->slice); - _sgimgui_draw_embedded_image(ctx, att->image, img_scale); -} - -_SOKOL_PRIVATE void _sgimgui_draw_attachments_panel(sgimgui_t* ctx, sg_attachments atts) { - if (atts.id != SG_INVALID_ID) { - igBeginChild_Str("attachments", IMVEC2(0,0), false, 0); - sg_attachments_info info = sg_query_attachments_info(atts); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - sgimgui_attachments_t* atts_ui = &ctx->attachments_window.slots[_sgimgui_slot_index(atts.id)]; - igText("Label: %s", atts_ui->label.buf[0] ? atts_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts_ui->desc.colors[i].image.id == SG_INVALID_ID) { - break; - } - igSeparator(); - igText("Color Image #%d:", i); - _sgimgui_draw_attachment(ctx, &atts_ui->desc.colors[i], &atts_ui->color_image_scale[i]); - } - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts_ui->desc.resolves[i].image.id == SG_INVALID_ID) { - break; - } - igSeparator(); - igText("Resolve Image #%d:", i); - _sgimgui_draw_attachment(ctx, &atts_ui->desc.resolves[i], &atts_ui->resolve_image_scale[i]); - } - if (atts_ui->desc.depth_stencil.image.id != SG_INVALID_ID) { - igSeparator(); - igText("Depth-Stencil Image:"); - _sgimgui_draw_attachment(ctx, &atts_ui->desc.depth_stencil, &atts_ui->ds_image_scale); - } - } else { - igText("Attachments 0x%08X not valid.", atts.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_bindings_panel(sgimgui_t* ctx, const sg_bindings* bnd) { - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++) { - sg_buffer buf = bnd->vertex_buffers[i]; - if (buf.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Buffer Slot #%d:", i); - igText(" Buffer: "); igSameLine(0,-1); - if (_sgimgui_draw_buffer_link(ctx, buf)) { - _sgimgui_show_buffer(ctx, buf); - } - igText(" Offset: %d", bnd->vertex_buffer_offsets[i]); - } else { - break; - } - } - if (bnd->index_buffer.id != SG_INVALID_ID) { - sg_buffer buf = bnd->index_buffer; - if (buf.id != SG_INVALID_ID) { - igSeparator(); - igText("Index Buffer Slot:"); - igText(" Buffer: "); igSameLine(0,-1); - if (_sgimgui_draw_buffer_link(ctx, buf)) { - _sgimgui_show_buffer(ctx, buf); - } - igText(" Offset: %d", bnd->index_buffer_offset); - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - sg_image img = bnd->vs.images[i]; - if (img.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Stage Image Slot #%d:", i); - igText(" Image: "); igSameLine(0,-1); - if (_sgimgui_draw_image_link(ctx, img)) { - _sgimgui_show_image(ctx, img); - } - } else { - break; - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - sg_sampler smp = bnd->vs.samplers[i]; - if (smp.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Stage Sampler Slot #%d:", i); - igText(" Sampler: "); igSameLine(0,-1); - if (_sgimgui_draw_sampler_link(ctx, smp)) { - _sgimgui_show_sampler(ctx, smp); - } - } else { - break; - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - sg_image img = bnd->fs.images[i]; - if (img.id != SG_INVALID_ID) { - igSeparator(); - igText("Fragment Stage Image Slot #%d:", i); - igText(" Image: "); igSameLine(0,-1); - if (_sgimgui_draw_image_link(ctx, img)) { - _sgimgui_show_image(ctx, img); - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - sg_sampler smp = bnd->fs.samplers[i]; - if (smp.id != SG_INVALID_ID) { - igSeparator(); - igText("Fragment Stage Sampler Slot #%d:", i); - igText(" Sampler: "); igSameLine(0,-1); - if (_sgimgui_draw_sampler_link(ctx, smp)) { - _sgimgui_show_sampler(ctx, smp); - } - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_uniforms_panel(sgimgui_t* ctx, const sgimgui_args_apply_uniforms_t* args) { - SOKOL_ASSERT(args->ub_index < SG_MAX_VERTEX_BUFFERS); - - /* check if all the required information for drawing the structured uniform block content - is available, otherwise just render a generic hexdump - */ - if (sg_query_pipeline_state(args->pipeline) != SG_RESOURCESTATE_VALID) { - igText("Pipeline object not valid!"); - return; - } - sgimgui_pipeline_t* pip_ui = &ctx->pipeline_window.slots[_sgimgui_slot_index(args->pipeline.id)]; - if (sg_query_shader_state(pip_ui->desc.shader) != SG_RESOURCESTATE_VALID) { - igText("Shader object not valid!"); - return; - } - sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(pip_ui->desc.shader.id)]; - SOKOL_ASSERT(shd_ui->res_id.id == pip_ui->desc.shader.id); - const sg_shader_uniform_block_desc* ub_desc = (args->stage == SG_SHADERSTAGE_VS) ? - &shd_ui->desc.vs.uniform_blocks[args->ub_index] : - &shd_ui->desc.fs.uniform_blocks[args->ub_index]; - SOKOL_ASSERT(args->data_size <= ub_desc->size); - bool draw_dump = false; - if (ub_desc->uniforms[0].type == SG_UNIFORMTYPE_INVALID) { - draw_dump = true; - } - - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_read_bucket(ctx); - SOKOL_ASSERT((args->ubuf_pos + args->data_size) <= bucket->ubuf_size); - const float* uptrf = (const float*) (bucket->ubuf + args->ubuf_pos); - const int32_t* uptri32 = (const int32_t*) uptrf; - if (!draw_dump) { - uint32_t u_off = 0; - for (int i = 0; i < SG_MAX_UB_MEMBERS; i++) { - const sg_shader_uniform_desc* ud = &ub_desc->uniforms[i]; - if (ud->type == SG_UNIFORMTYPE_INVALID) { - break; - } - int num_items = (ud->array_count > 1) ? ud->array_count : 1; - if (num_items > 1) { - igText("%d: %s %s[%d] =", i, _sgimgui_uniformtype_string(ud->type), ud->name?ud->name:"", ud->array_count); - } else { - igText("%d: %s %s =", i, _sgimgui_uniformtype_string(ud->type), ud->name?ud->name:""); - } - for (int item_index = 0; item_index < num_items; item_index++) { - const uint32_t u_size = _sgimgui_std140_uniform_size(ud->type, ud->array_count) / 4; - const uint32_t u_align = _sgimgui_std140_uniform_alignment(ud->type, ud->array_count) / 4; - u_off = _sgimgui_align_u32(u_off, u_align); - switch (ud->type) { - case SG_UNIFORMTYPE_FLOAT: - igText(" %.3f", uptrf[u_off]); - break; - case SG_UNIFORMTYPE_INT: - igText(" %d", uptri32[u_off]); - break; - case SG_UNIFORMTYPE_FLOAT2: - igText(" %.3f, %.3f", uptrf[u_off], uptrf[u_off+1]); - break; - case SG_UNIFORMTYPE_INT2: - igText(" %d, %d", uptri32[u_off], uptri32[u_off+1]); - break; - case SG_UNIFORMTYPE_FLOAT3: - igText(" %.3f, %.3f, %.3f", uptrf[u_off], uptrf[u_off+1], uptrf[u_off+2]); - break; - case SG_UNIFORMTYPE_INT3: - igText(" %d, %d, %d", uptri32[u_off], uptri32[u_off+1], uptri32[u_off+2]); - break; - case SG_UNIFORMTYPE_FLOAT4: - igText(" %.3f, %.3f, %.3f, %.3f", uptrf[u_off], uptrf[u_off+1], uptrf[u_off+2], uptrf[u_off+3]); - break; - case SG_UNIFORMTYPE_INT4: - igText(" %d, %d, %d, %d", uptri32[u_off], uptri32[u_off+1], uptri32[u_off+2], uptri32[u_off+3]); - break; - case SG_UNIFORMTYPE_MAT4: - igText(" %.3f, %.3f, %.3f, %.3f\n" - " %.3f, %.3f, %.3f, %.3f\n" - " %.3f, %.3f, %.3f, %.3f\n" - " %.3f, %.3f, %.3f, %.3f", - uptrf[u_off+0], uptrf[u_off+1], uptrf[u_off+2], uptrf[u_off+3], - uptrf[u_off+4], uptrf[u_off+5], uptrf[u_off+6], uptrf[u_off+7], - uptrf[u_off+8], uptrf[u_off+9], uptrf[u_off+10], uptrf[u_off+11], - uptrf[u_off+12], uptrf[u_off+13], uptrf[u_off+14], uptrf[u_off+15]); - break; - default: - igText("???"); - break; - } - u_off += u_size; - } - } - } else { - // FIXME: float vs int - const size_t num_floats = ub_desc->size / sizeof(float); - for (uint32_t i = 0; i < num_floats; i++) { - igText("%.3f, ", uptrf[i]); - if (((i + 1) % 4) != 0) { - igSameLine(0,-1); - } - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_passaction_panel(sgimgui_t* ctx, sg_attachments atts, const sg_pass_action* action) { - /* determine number of valid color attachments */ - int num_color_atts = 0; - if (SG_INVALID_ID == atts.id) { - /* a swapchain pass: one color attachment */ - num_color_atts = 1; - } else { - const sgimgui_attachments_t* atts_ui = &ctx->attachments_window.slots[_sgimgui_slot_index(atts.id)]; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts_ui->desc.colors[i].image.id != SG_INVALID_ID) { - num_color_atts++; - } - } - } - - igText("Pass Action: "); - for (int i = 0; i < num_color_atts; i++) { - const sg_color_attachment_action* c_att = &action->colors[i]; - igText(" Color Attachment %d:", i); - sgimgui_str_t color_str; - switch (c_att->load_action) { - case SG_LOADACTION_LOAD: igText(" SG_LOADACTION_LOAD"); break; - case SG_LOADACTION_DONTCARE: igText(" SG_LOADACTION_DONTCARE"); break; - case SG_LOADACTION_CLEAR: - igText(" SG_LOADACTION_CLEAR: %s", _sgimgui_color_string(&color_str, c_att->clear_value)); - break; - default: igText(" ???"); break; - } - switch (c_att->store_action) { - case SG_STOREACTION_STORE: igText(" SG_STOREACTION_STORE"); break; - case SG_STOREACTION_DONTCARE: igText(" SG_STOREACTION_DONTCARE"); break; - default: igText(" ???"); break; - } - } - const sg_depth_attachment_action* d_att = &action->depth; - igText(" Depth Attachment:"); - switch (d_att->load_action) { - case SG_LOADACTION_LOAD: igText(" SG_LOADACTION_LOAD"); break; - case SG_LOADACTION_DONTCARE: igText(" SG_LOADACTION_DONTCARE"); break; - case SG_LOADACTION_CLEAR: igText(" SG_LOADACTION_CLEAR: %.3f", d_att->clear_value); break; - default: igText(" ???"); break; - } - switch (d_att->store_action) { - case SG_STOREACTION_STORE: igText(" SG_STOREACTION_STORE"); break; - case SG_STOREACTION_DONTCARE: igText(" SG_STOREACTION_DONTCARE"); break; - default: igText(" ???"); break; - } - const sg_stencil_attachment_action* s_att = &action->stencil; - igText(" Stencil Attachment"); - switch (s_att->load_action) { - case SG_LOADACTION_LOAD: igText(" SG_LOADACTION_LOAD"); break; - case SG_LOADACTION_DONTCARE: igText(" SG_LOADACTION_DONTCARE"); break; - case SG_LOADACTION_CLEAR: igText(" SG_LOADACTION_CLEAR: 0x%02X", s_att->clear_value); break; - default: igText(" ???"); break; - } - switch (d_att->store_action) { - case SG_STOREACTION_STORE: igText(" SG_STOREACTION_STORE"); break; - case SG_STOREACTION_DONTCARE: igText(" SG_STOREACTION_DONTCARE"); break; - default: igText(" ???"); break; - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_swapchain_panel(sg_swapchain* swapchain) { - igText("Swapchain"); - igText(" Width: %d", swapchain->width); - igText(" Height: %d", swapchain->height); - igText(" Sample Count: %d", swapchain->sample_count); - igText(" Color Format: %s", _sgimgui_pixelformat_string(swapchain->color_format)); - igText(" Depth Format: %s", _sgimgui_pixelformat_string(swapchain->depth_format)); - igSeparator(); - switch (sg_query_backend()) { - case SG_BACKEND_D3D11: - igText("D3D11 Objects:"); - igText(" Render View: %p", swapchain->d3d11.render_view); - igText(" Resolve View: %p", swapchain->d3d11.resolve_view); - igText(" Depth Stencil View: %p", swapchain->d3d11.depth_stencil_view); - break; - case SG_BACKEND_WGPU: - igText("WGPU Objects:"); - igText(" Render View: %p", swapchain->wgpu.render_view); - igText(" Resolve View: %p", swapchain->wgpu.resolve_view); - igText(" Depth Stencil View: %p", swapchain->wgpu.depth_stencil_view); - break; - case SG_BACKEND_METAL_MACOS: - case SG_BACKEND_METAL_IOS: - case SG_BACKEND_METAL_SIMULATOR: - igText("Metal Objects:"); - igText(" Current Drawable: %p", swapchain->metal.current_drawable); - igText(" Depth Stencil Texture: %p", swapchain->metal.depth_stencil_texture); - igText(" MSAA Color Texture: %p", swapchain->metal.msaa_color_texture); - break; - case SG_BACKEND_GLCORE33: - case SG_BACKEND_GLES3: - igText("GL Objects:"); - igText(" Framebuffer: %d", swapchain->gl.framebuffer); - break; - default: - igText(" UNKNOWN BACKEND!"); - break; - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_capture_panel(sgimgui_t* ctx) { - int sel_item_index = ctx->capture_window.sel_item; - if (sel_item_index >= _sgimgui_capture_num_read_items(ctx)) { - return; - } - sgimgui_capture_item_t* item = _sgimgui_capture_read_item_at(ctx, sel_item_index); - igBeginChild_Str("capture_item", IMVEC2(0, 0), false, 0); - igPushStyleColor_U32(ImGuiCol_Text, item->color); - igText("%s", _sgimgui_capture_item_string(ctx, sel_item_index, item).buf); - igPopStyleColor(1); - igSeparator(); - switch (item->cmd) { - case SGIMGUI_CMD_RESET_STATE_CACHE: - break; - case SGIMGUI_CMD_MAKE_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.make_buffer.result); - break; - case SGIMGUI_CMD_MAKE_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.make_image.result); - break; - case SGIMGUI_CMD_MAKE_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.make_sampler.result); - break; - case SGIMGUI_CMD_MAKE_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.make_shader.result); - break; - case SGIMGUI_CMD_MAKE_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.make_pipeline.result); - break; - case SGIMGUI_CMD_MAKE_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.make_attachments.result); - break; - case SGIMGUI_CMD_DESTROY_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.destroy_buffer.buffer); - break; - case SGIMGUI_CMD_DESTROY_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.destroy_image.image); - break; - case SGIMGUI_CMD_DESTROY_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.destroy_sampler.sampler); - break; - case SGIMGUI_CMD_DESTROY_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.destroy_shader.shader); - break; - case SGIMGUI_CMD_DESTROY_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.destroy_pipeline.pipeline); - break; - case SGIMGUI_CMD_DESTROY_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.destroy_attachments.attachments); - break; - case SGIMGUI_CMD_UPDATE_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.update_buffer.buffer); - break; - case SGIMGUI_CMD_UPDATE_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.update_image.image); - break; - case SGIMGUI_CMD_APPEND_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.update_buffer.buffer); - break; - case SGIMGUI_CMD_BEGIN_PASS: - _sgimgui_draw_passaction_panel(ctx, item->args.begin_pass.pass.attachments, &item->args.begin_pass.pass.action); - igSeparator(); - if (item->args.begin_pass.pass.attachments.id != SG_INVALID_ID) { - _sgimgui_draw_attachments_panel(ctx, item->args.begin_pass.pass.attachments); - } else { - _sgimgui_draw_swapchain_panel(&item->args.begin_pass.pass.swapchain); - } - break; - case SGIMGUI_CMD_APPLY_VIEWPORT: - case SGIMGUI_CMD_APPLY_SCISSOR_RECT: - break; - case SGIMGUI_CMD_APPLY_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.apply_pipeline.pipeline); - break; - case SGIMGUI_CMD_APPLY_BINDINGS: - _sgimgui_draw_bindings_panel(ctx, &item->args.apply_bindings.bindings); - break; - case SGIMGUI_CMD_APPLY_UNIFORMS: - _sgimgui_draw_uniforms_panel(ctx, &item->args.apply_uniforms); - break; - case SGIMGUI_CMD_DRAW: - case SGIMGUI_CMD_END_PASS: - case SGIMGUI_CMD_COMMIT: - break; - case SGIMGUI_CMD_ALLOC_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.alloc_buffer.result); - break; - case SGIMGUI_CMD_ALLOC_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.alloc_image.result); - break; - case SGIMGUI_CMD_ALLOC_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.alloc_sampler.result); - break; - case SGIMGUI_CMD_ALLOC_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.alloc_shader.result); - break; - case SGIMGUI_CMD_ALLOC_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.alloc_pipeline.result); - break; - case SGIMGUI_CMD_ALLOC_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.alloc_attachments.result); - break; - case SGIMGUI_CMD_INIT_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.init_buffer.buffer); - break; - case SGIMGUI_CMD_INIT_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.init_image.image); - break; - case SGIMGUI_CMD_INIT_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.init_sampler.sampler); - break; - case SGIMGUI_CMD_INIT_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.init_shader.shader); - break; - case SGIMGUI_CMD_INIT_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.init_pipeline.pipeline); - break; - case SGIMGUI_CMD_INIT_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.init_attachments.attachments); - break; - case SGIMGUI_CMD_FAIL_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.fail_buffer.buffer); - break; - case SGIMGUI_CMD_FAIL_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.fail_image.image); - break; - case SGIMGUI_CMD_FAIL_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.fail_sampler.sampler); - break; - case SGIMGUI_CMD_FAIL_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.fail_shader.shader); - break; - case SGIMGUI_CMD_FAIL_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.fail_pipeline.pipeline); - break; - case SGIMGUI_CMD_FAIL_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.fail_attachments.attachments); - break; - default: - break; - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) { - igText("Backend: %s\n\n", _sgimgui_backend_string(sg_query_backend())); - sg_features f = sg_query_features(); - igText("Features:"); - igText(" origin_top_left: %s", _sgimgui_bool_string(f.origin_top_left)); - igText(" image_clamp_to_border: %s", _sgimgui_bool_string(f.image_clamp_to_border)); - igText(" mrt_independent_blend_state: %s", _sgimgui_bool_string(f.mrt_independent_blend_state)); - igText(" mrt_independent_write_mask: %s", _sgimgui_bool_string(f.mrt_independent_write_mask)); - sg_limits l = sg_query_limits(); - igText("\nLimits:\n"); - igText(" max_image_size_2d: %d", l.max_image_size_2d); - igText(" max_image_size_cube: %d", l.max_image_size_cube); - igText(" max_image_size_3d: %d", l.max_image_size_3d); - igText(" max_image_size_array: %d", l.max_image_size_array); - igText(" max_image_array_layers: %d", l.max_image_array_layers); - igText(" max_vertex_attrs: %d", l.max_vertex_attrs); - igText(" gl_max_vertex_uniform_components: %d", l.gl_max_vertex_uniform_components); - igText(" gl_max_combined_texture_image_units: %d", l.gl_max_combined_texture_image_units); - igText("\nUsable Pixelformats:"); - for (int i = (int)(SG_PIXELFORMAT_NONE+1); i < (int)_SG_PIXELFORMAT_NUM; i++) { - sg_pixel_format fmt = (sg_pixel_format)i; - sg_pixelformat_info info = sg_query_pixelformat(fmt); - if (info.sample) { - igText(" %s: %s%s%s%s%s%s", - _sgimgui_pixelformat_string(fmt), - info.sample ? "SAMPLE ":"", - info.filter ? "FILTER ":"", - info.blend ? "BLEND ":"", - info.render ? "RENDER ":"", - info.msaa ? "MSAA ":"", - info.depth ? "DEPTH ":""); - } - } -} - -_SOKOL_PRIVATE void _sgimgui_frame_add_stats_row(const char* key, uint32_t value) { - igTableNextRow(0, 0.0f); - igTableSetColumnIndex(0); - igText(key); - igTableSetColumnIndex(1); - igText("%d", value); -} - -#define _sgimgui_frame_stats(key) _sgimgui_frame_add_stats_row(#key, stats->key) - -_SOKOL_PRIVATE void _sgimgui_draw_frame_stats_panel(sgimgui_t* ctx) { - _SOKOL_UNUSED(ctx); - igCheckbox("Ignore sokol_imgui.h", &ctx->frame_stats_window.disable_sokol_imgui_stats); - const sg_frame_stats* stats = &ctx->frame_stats_window.stats; - const ImGuiTableFlags flags = - ImGuiTableFlags_Resizable | - ImGuiTableFlags_ScrollY | - ImGuiTableFlags_SizingFixedFit | - ImGuiTableFlags_Borders; - if (igBeginTable("##frame_stats_table", 2, flags, IMVEC2(0, 0), 0)) { - igTableSetupScrollFreeze(0, 2); - igTableSetupColumn("key", ImGuiTableColumnFlags_None, 0, 0); - igTableSetupColumn("value", ImGuiTableColumnFlags_None, 0, 0); - igTableHeadersRow(); - _sgimgui_frame_stats(frame_index); - _sgimgui_frame_stats(num_passes); - _sgimgui_frame_stats(num_apply_viewport); - _sgimgui_frame_stats(num_apply_scissor_rect); - _sgimgui_frame_stats(num_apply_pipeline); - _sgimgui_frame_stats(num_apply_bindings); - _sgimgui_frame_stats(num_apply_uniforms); - _sgimgui_frame_stats(num_draw); - _sgimgui_frame_stats(num_update_buffer); - _sgimgui_frame_stats(num_append_buffer); - _sgimgui_frame_stats(num_update_image); - _sgimgui_frame_stats(size_apply_uniforms); - _sgimgui_frame_stats(size_update_buffer); - _sgimgui_frame_stats(size_append_buffer); - _sgimgui_frame_stats(size_update_image); - switch (sg_query_backend()) { - case SG_BACKEND_GLCORE33: - case SG_BACKEND_GLES3: - _sgimgui_frame_stats(gl.num_bind_buffer); - _sgimgui_frame_stats(gl.num_active_texture); - _sgimgui_frame_stats(gl.num_bind_texture); - _sgimgui_frame_stats(gl.num_bind_sampler); - _sgimgui_frame_stats(gl.num_use_program); - _sgimgui_frame_stats(gl.num_render_state); - _sgimgui_frame_stats(gl.num_vertex_attrib_pointer); - _sgimgui_frame_stats(gl.num_vertex_attrib_divisor); - _sgimgui_frame_stats(gl.num_enable_vertex_attrib_array); - _sgimgui_frame_stats(gl.num_disable_vertex_attrib_array); - _sgimgui_frame_stats(gl.num_uniform); - break; - case SG_BACKEND_WGPU: - _sgimgui_frame_stats(wgpu.uniforms.num_set_bindgroup); - _sgimgui_frame_stats(wgpu.uniforms.size_write_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_set_vertex_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_skip_redundant_vertex_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_set_index_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_skip_redundant_index_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_create_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_discard_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_set_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_skip_redundant_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_hits); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_misses); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_collisions); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_hash_vs_key_mismatch); - break; - case SG_BACKEND_METAL_MACOS: - case SG_BACKEND_METAL_IOS: - case SG_BACKEND_METAL_SIMULATOR: - _sgimgui_frame_stats(metal.idpool.num_added); - _sgimgui_frame_stats(metal.idpool.num_released); - _sgimgui_frame_stats(metal.idpool.num_garbage_collected); - _sgimgui_frame_stats(metal.pipeline.num_set_blend_color); - _sgimgui_frame_stats(metal.pipeline.num_set_cull_mode); - _sgimgui_frame_stats(metal.pipeline.num_set_front_facing_winding); - _sgimgui_frame_stats(metal.pipeline.num_set_stencil_reference_value); - _sgimgui_frame_stats(metal.pipeline.num_set_depth_bias); - _sgimgui_frame_stats(metal.pipeline.num_set_render_pipeline_state); - _sgimgui_frame_stats(metal.pipeline.num_set_depth_stencil_state); - _sgimgui_frame_stats(metal.bindings.num_set_vertex_buffer); - _sgimgui_frame_stats(metal.bindings.num_set_vertex_texture); - _sgimgui_frame_stats(metal.bindings.num_set_vertex_sampler_state); - _sgimgui_frame_stats(metal.bindings.num_set_fragment_texture); - _sgimgui_frame_stats(metal.bindings.num_set_fragment_sampler_state); - _sgimgui_frame_stats(metal.uniforms.num_set_vertex_buffer_offset); - _sgimgui_frame_stats(metal.uniforms.num_set_fragment_buffer_offset); - break; - case SG_BACKEND_D3D11: - _sgimgui_frame_stats(d3d11.pass.num_om_set_render_targets); - _sgimgui_frame_stats(d3d11.pass.num_clear_render_target_view); - _sgimgui_frame_stats(d3d11.pass.num_clear_depth_stencil_view); - _sgimgui_frame_stats(d3d11.pass.num_resolve_subresource); - _sgimgui_frame_stats(d3d11.pipeline.num_rs_set_state); - _sgimgui_frame_stats(d3d11.pipeline.num_om_set_depth_stencil_state); - _sgimgui_frame_stats(d3d11.pipeline.num_om_set_blend_state); - _sgimgui_frame_stats(d3d11.pipeline.num_ia_set_primitive_topology); - _sgimgui_frame_stats(d3d11.pipeline.num_ia_set_input_layout); - _sgimgui_frame_stats(d3d11.pipeline.num_vs_set_shader); - _sgimgui_frame_stats(d3d11.pipeline.num_vs_set_constant_buffers); - _sgimgui_frame_stats(d3d11.pipeline.num_ps_set_shader); - _sgimgui_frame_stats(d3d11.pipeline.num_ps_set_constant_buffers); - _sgimgui_frame_stats(d3d11.bindings.num_ia_set_vertex_buffers); - _sgimgui_frame_stats(d3d11.bindings.num_ia_set_index_buffer); - _sgimgui_frame_stats(d3d11.bindings.num_vs_set_shader_resources); - _sgimgui_frame_stats(d3d11.bindings.num_ps_set_shader_resources); - _sgimgui_frame_stats(d3d11.bindings.num_vs_set_samplers); - _sgimgui_frame_stats(d3d11.bindings.num_ps_set_samplers); - _sgimgui_frame_stats(d3d11.uniforms.num_update_subresource); - _sgimgui_frame_stats(d3d11.draw.num_draw_indexed_instanced); - _sgimgui_frame_stats(d3d11.draw.num_draw_indexed); - _sgimgui_frame_stats(d3d11.draw.num_draw_instanced); - _sgimgui_frame_stats(d3d11.draw.num_draw); - _sgimgui_frame_stats(d3d11.num_map); - _sgimgui_frame_stats(d3d11.num_unmap); - break; - default: break; - } - igEndTable(); - } -} - -#define _sgimgui_def(val, def) (((val) == 0) ? (def) : (val)) - -_SOKOL_PRIVATE sgimgui_desc_t _sgimgui_desc_defaults(const sgimgui_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sgimgui_desc_t res = *desc; - // FIXME: any additional default overrides would go here - return res; -} - -/*--- PUBLIC FUNCTIONS -------------------------------------------------------*/ -SOKOL_API_IMPL void sgimgui_init(sgimgui_t* ctx, const sgimgui_desc_t* desc) { - SOKOL_ASSERT(ctx && desc); - _sgimgui_clear(ctx, sizeof(sgimgui_t)); - ctx->init_tag = 0xABCDABCD; - ctx->desc = _sgimgui_desc_defaults(desc); - _sgimgui_capture_init(ctx); - - /* hook into sokol_gfx functions */ - sg_trace_hooks hooks; - _sgimgui_clear(&hooks, sizeof(hooks)); - hooks.user_data = (void*) ctx; - hooks.reset_state_cache = _sgimgui_reset_state_cache; - hooks.make_buffer = _sgimgui_make_buffer; - hooks.make_image = _sgimgui_make_image; - hooks.make_sampler = _sgimgui_make_sampler; - hooks.make_shader = _sgimgui_make_shader; - hooks.make_pipeline = _sgimgui_make_pipeline; - hooks.make_attachments = _sgimgui_make_attachments; - hooks.destroy_buffer = _sgimgui_destroy_buffer; - hooks.destroy_image = _sgimgui_destroy_image; - hooks.destroy_sampler = _sgimgui_destroy_sampler; - hooks.destroy_shader = _sgimgui_destroy_shader; - hooks.destroy_pipeline = _sgimgui_destroy_pipeline; - hooks.destroy_attachments = _sgimgui_destroy_attachments; - hooks.update_buffer = _sgimgui_update_buffer; - hooks.update_image = _sgimgui_update_image; - hooks.append_buffer = _sgimgui_append_buffer; - hooks.begin_pass = _sgimgui_begin_pass; - hooks.apply_viewport = _sgimgui_apply_viewport; - hooks.apply_scissor_rect = _sgimgui_apply_scissor_rect; - hooks.apply_pipeline = _sgimgui_apply_pipeline; - hooks.apply_bindings = _sgimgui_apply_bindings; - hooks.apply_uniforms = _sgimgui_apply_uniforms; - hooks.draw = _sgimgui_draw; - hooks.end_pass = _sgimgui_end_pass; - hooks.commit = _sgimgui_commit; - hooks.alloc_buffer = _sgimgui_alloc_buffer; - hooks.alloc_image = _sgimgui_alloc_image; - hooks.alloc_sampler = _sgimgui_alloc_sampler; - hooks.alloc_shader = _sgimgui_alloc_shader; - hooks.alloc_pipeline = _sgimgui_alloc_pipeline; - hooks.alloc_attachments = _sgimgui_alloc_attachments; - hooks.dealloc_buffer = _sgimgui_dealloc_buffer; - hooks.dealloc_image = _sgimgui_dealloc_image; - hooks.dealloc_sampler = _sgimgui_dealloc_sampler; - hooks.dealloc_shader = _sgimgui_dealloc_shader; - hooks.dealloc_pipeline = _sgimgui_dealloc_pipeline; - hooks.dealloc_attachments = _sgimgui_dealloc_attachments; - hooks.init_buffer = _sgimgui_init_buffer; - hooks.init_image = _sgimgui_init_image; - hooks.init_sampler = _sgimgui_init_sampler; - hooks.init_shader = _sgimgui_init_shader; - hooks.init_pipeline = _sgimgui_init_pipeline; - hooks.init_attachments = _sgimgui_init_attachments; - hooks.uninit_buffer = _sgimgui_uninit_buffer; - hooks.uninit_image = _sgimgui_uninit_image; - hooks.uninit_sampler = _sgimgui_uninit_sampler; - hooks.uninit_shader = _sgimgui_uninit_shader; - hooks.uninit_pipeline = _sgimgui_uninit_pipeline; - hooks.uninit_attachments = _sgimgui_uninit_attachments; - hooks.fail_buffer = _sgimgui_fail_buffer; - hooks.fail_image = _sgimgui_fail_image; - hooks.fail_sampler = _sgimgui_fail_sampler; - hooks.fail_shader = _sgimgui_fail_shader; - hooks.fail_pipeline = _sgimgui_fail_pipeline; - hooks.fail_attachments = _sgimgui_fail_attachments; - hooks.push_debug_group = _sgimgui_push_debug_group; - hooks.pop_debug_group = _sgimgui_pop_debug_group; - ctx->hooks = sg_install_trace_hooks(&hooks); - - /* allocate resource debug-info slots */ - const sg_desc sgdesc = sg_query_desc(); - ctx->buffer_window.num_slots = sgdesc.buffer_pool_size; - ctx->image_window.num_slots = sgdesc.image_pool_size; - ctx->sampler_window.num_slots = sgdesc.sampler_pool_size; - ctx->shader_window.num_slots = sgdesc.shader_pool_size; - ctx->pipeline_window.num_slots = sgdesc.pipeline_pool_size; - ctx->attachments_window.num_slots = sgdesc.attachments_pool_size; - - const size_t buffer_pool_size = (size_t)ctx->buffer_window.num_slots * sizeof(sgimgui_buffer_t); - ctx->buffer_window.slots = (sgimgui_buffer_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, buffer_pool_size); - - const size_t image_pool_size = (size_t)ctx->image_window.num_slots * sizeof(sgimgui_image_t); - ctx->image_window.slots = (sgimgui_image_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, image_pool_size); - - const size_t sampler_pool_size = (size_t)ctx->sampler_window.num_slots * sizeof(sgimgui_sampler_t); - ctx->sampler_window.slots = (sgimgui_sampler_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, sampler_pool_size); - - const size_t shader_pool_size = (size_t)ctx->shader_window.num_slots * sizeof(sgimgui_shader_t); - ctx->shader_window.slots = (sgimgui_shader_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, shader_pool_size); - - const size_t pipeline_pool_size = (size_t)ctx->pipeline_window.num_slots * sizeof(sgimgui_pipeline_t); - ctx->pipeline_window.slots = (sgimgui_pipeline_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, pipeline_pool_size); - - const size_t attachments_pool_size = (size_t)ctx->attachments_window.num_slots * sizeof(sgimgui_attachments_t); - ctx->attachments_window.slots = (sgimgui_attachments_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, attachments_pool_size); -} - -SOKOL_API_IMPL void sgimgui_discard(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - /* restore original trace hooks */ - sg_install_trace_hooks(&ctx->hooks); - ctx->init_tag = 0; - _sgimgui_capture_discard(ctx); - if (ctx->buffer_window.slots) { - for (int i = 0; i < ctx->buffer_window.num_slots; i++) { - if (ctx->buffer_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_buffer_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->buffer_window.slots); - ctx->buffer_window.slots = 0; - } - if (ctx->image_window.slots) { - for (int i = 0; i < ctx->image_window.num_slots; i++) { - if (ctx->image_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_image_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->image_window.slots); - ctx->image_window.slots = 0; - } - if (ctx->sampler_window.slots) { - for (int i = 0; i < ctx->sampler_window.num_slots; i++) { - if (ctx->sampler_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_sampler_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->sampler_window.slots); - ctx->sampler_window.slots = 0; - } - if (ctx->shader_window.slots) { - for (int i = 0; i < ctx->shader_window.num_slots; i++) { - if (ctx->shader_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_shader_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->shader_window.slots); - ctx->shader_window.slots = 0; - } - if (ctx->pipeline_window.slots) { - for (int i = 0; i < ctx->pipeline_window.num_slots; i++) { - if (ctx->pipeline_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_pipeline_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->pipeline_window.slots); - ctx->pipeline_window.slots = 0; - } - if (ctx->attachments_window.slots) { - for (int i = 0; i < ctx->attachments_window.num_slots; i++) { - if (ctx->attachments_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_attachments_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->attachments_window.slots); - ctx->attachments_window.slots = 0; - } -} - -SOKOL_API_IMPL void sgimgui_draw(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - sgimgui_draw_buffer_window(ctx); - sgimgui_draw_image_window(ctx); - sgimgui_draw_sampler_window(ctx); - sgimgui_draw_shader_window(ctx); - sgimgui_draw_pipeline_window(ctx); - sgimgui_draw_attachments_window(ctx); - sgimgui_draw_capture_window(ctx); - sgimgui_draw_capabilities_window(ctx); - sgimgui_draw_frame_stats_window(ctx); -} - -SOKOL_API_IMPL void sgimgui_draw_menu(sgimgui_t* ctx, const char* title) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - SOKOL_ASSERT(title); - if (igBeginMenu(title, true)) { - igMenuItem_BoolPtr("Capabilities", 0, &ctx->caps_window.open, true); - igMenuItem_BoolPtr("Frame Stats", 0, &ctx->frame_stats_window.open, true); - igMenuItem_BoolPtr("Buffers", 0, &ctx->buffer_window.open, true); - igMenuItem_BoolPtr("Images", 0, &ctx->image_window.open, true); - igMenuItem_BoolPtr("Samplers", 0, &ctx->sampler_window.open, true); - igMenuItem_BoolPtr("Shaders", 0, &ctx->shader_window.open, true); - igMenuItem_BoolPtr("Pipelines", 0, &ctx->pipeline_window.open, true); - igMenuItem_BoolPtr("Attachments", 0, &ctx->attachments_window.open, true); - igMenuItem_BoolPtr("Calls", 0, &ctx->capture_window.open, true); - igEndMenu(); - } -} - -SOKOL_API_IMPL void sgimgui_draw_buffer_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->buffer_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 280), ImGuiCond_Once); - if (igBegin("Buffers", &ctx->buffer_window.open, 0)) { - sgimgui_draw_buffer_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_image_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->image_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Images", &ctx->image_window.open, 0)) { - sgimgui_draw_image_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_sampler_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->sampler_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Samplers", &ctx->sampler_window.open, 0)) { - sgimgui_draw_sampler_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_shader_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->shader_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Shaders", &ctx->shader_window.open, 0)) { - sgimgui_draw_shader_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_pipeline_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->pipeline_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(540, 400), ImGuiCond_Once); - if (igBegin("Pipelines", &ctx->pipeline_window.open, 0)) { - sgimgui_draw_pipeline_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_attachments_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->attachments_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Attachments", &ctx->attachments_window.open, 0)) { - sgimgui_draw_attachments_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_capture_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->capture_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(640, 400), ImGuiCond_Once); - if (igBegin("Frame Capture", &ctx->capture_window.open, 0)) { - sgimgui_draw_capture_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_capabilities_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->caps_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Capabilities", &ctx->caps_window.open, 0)) { - sgimgui_draw_capabilities_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_frame_stats_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->frame_stats_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(512, 400), ImGuiCond_Once); - if (igBegin("Frame Stats", &ctx->frame_stats_window.open, 0)) { - sgimgui_draw_frame_stats_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_buffer_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_buffer_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_buffer_panel(ctx, ctx->buffer_window.sel_buf); -} - -SOKOL_API_IMPL void sgimgui_draw_image_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_image_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_image_panel(ctx, ctx->image_window.sel_img); -} - -SOKOL_API_IMPL void sgimgui_draw_sampler_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_sampler_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_sampler_panel(ctx, ctx->sampler_window.sel_smp); -} - -SOKOL_API_IMPL void sgimgui_draw_shader_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_shader_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_shader_panel(ctx, ctx->shader_window.sel_shd); -} - -SOKOL_API_IMPL void sgimgui_draw_pipeline_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_pipeline_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_pipeline_panel(ctx, ctx->pipeline_window.sel_pip); -} - -SOKOL_API_IMPL void sgimgui_draw_attachments_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_attachments_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_attachments_panel(ctx, ctx->attachments_window.sel_atts); -} - -SOKOL_API_IMPL void sgimgui_draw_capture_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_capture_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_capture_panel(ctx); -} - -SOKOL_API_IMPL void sgimgui_draw_capabilities_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _SOKOL_UNUSED(ctx); - _sgimgui_draw_caps_panel(); -} - -SOKOL_API_IMPL void sgimgui_draw_frame_stats_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - ctx->frame_stats_window.stats = sg_query_frame_stats(); - _sgimgui_draw_frame_stats_panel(ctx); -} - -#endif /* SOKOL_GFX_IMGUI_IMPL */ diff --git a/source/engine/thirdparty/sokol/util/sokol_gl.h b/source/engine/thirdparty/sokol/util/sokol_gl.h deleted file mode 100644 index 997ddea..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_gl.h +++ /dev/null @@ -1,4254 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_GL_IMPL) -#define SOKOL_GL_IMPL -#endif -#ifndef SOKOL_GL_INCLUDED -/* - sokol_gl.h -- OpenGL 1.x style rendering on top of sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_GL_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - The following defines are used by the implementation to select the - platform-specific embedded shader code (these are the same defines as - used by sokol_gfx.h and sokol_app.h): - - SOKOL_GLCORE33 - SOKOL_GLES3 - SOKOL_D3D11 - SOKOL_METAL - SOKOL_WGPU - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_GL_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_GL_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - If sokol_gl.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_GL_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before including sokol_gl.h: - - sokol_gfx.h - - Matrix functions have been taken from MESA and Regal. - - FEATURE OVERVIEW: - ================= - sokol_gl.h implements a subset of the OpenGLES 1.x feature set useful for - when you just want to quickly render a bunch of triangles or - lines without having to mess with buffers and shaders. - - The current feature set is mostly useful for debug visualizations - and simple UI-style 2D rendering: - - What's implemented: - - vertex components: - - position (x, y, z) - - 2D texture coords (u, v) - - color (r, g, b, a) - - primitive types: - - triangle list and strip - - line list and strip - - quad list (TODO: quad strips) - - point list - - one texture layer (no multi-texturing) - - viewport and scissor-rect with selectable origin (top-left or bottom-left) - - all GL 1.x matrix stack functions, and additionally equivalent - functions for gluPerspective and gluLookat - - Notable GLES 1.x features that are *NOT* implemented: - - vertex lighting (this is the most likely GL feature that might be added later) - - vertex arrays (although providing whole chunks of vertex data at once - might be a useful feature for a later version) - - texture coordinate generation - - line width - - all pixel store functions - - no ALPHA_TEST - - no clear functions (clearing is handled by the sokol-gfx render pass) - - fog - - Notable differences to GL: - - No "enum soup" for render states etc, instead there's a - 'pipeline stack', this is similar to GL's matrix stack, - but for pipeline-state-objects. The pipeline object at - the top of the pipeline stack defines the active set of render states - - All angles are in radians, not degrees (note the sgl_rad() and - sgl_deg() conversion functions) - - No enable/disable state for scissor test, this is always enabled - - STEP BY STEP: - ============= - --- To initialize sokol-gl, call: - - sgl_setup(const sgl_desc_t* desc) - - NOTE that sgl_setup() must be called *after* initializing sokol-gfx - (via sg_setup). This is because sgl_setup() needs to create - sokol-gfx resource objects. - - If you're intending to render to the default pass, and also don't - want to tweak memory usage, and don't want any logging output you can - just keep sgl_desc_t zero-initialized: - - sgl_setup(&(sgl_desc_t*){ 0 }); - - In this case, sokol-gl will create internal sg_pipeline objects that - are compatible with the sokol-app default framebuffer. - - I would recommend to at least install a logging callback so that - you'll see any warnings and errors. The easiest way is through - sokol_log.h: - - #include "sokol_log.h" - - sgl_setup(&(sgl_desc_t){ - .logger.func = slog_func. - }); - - If you want to render into a framebuffer with different pixel-format - and MSAA attributes you need to provide the matching attributes in the - sgl_setup() call: - - sgl_setup(&(sgl_desc_t*){ - .color_format = SG_PIXELFORMAT_..., - .depth_format = SG_PIXELFORMAT_..., - .sample_count = ..., - }); - - To reduce memory usage, or if you need to create more then the default number of - contexts, pipelines, vertices or draw commands, set the following sgl_desc_t - members: - - .context_pool_size (default: 4) - .pipeline_pool_size (default: 64) - .max_vertices (default: 64k) - .max_commands (default: 16k) - - Finally you can change the face winding for front-facing triangles - and quads: - - .face_winding - default is SG_FACEWINDING_CCW - - The default winding for front faces is counter-clock-wise. This is - the same as OpenGL's default, but different from sokol-gfx. - - --- Optionally create additional context objects if you want to render into - multiple sokol-gfx render passes (or generally if you want to - use multiple independent sokol-gl "state buckets") - - sgl_context ctx = sgl_make_context(const sgl_context_desc_t* desc) - - For details on rendering with sokol-gl contexts, search below for - WORKING WITH CONTEXTS. - - --- Optionally create pipeline-state-objects if you need render state - that differs from sokol-gl's default state: - - sgl_pipeline pip = sgl_make_pipeline(const sg_pipeline_desc* desc) - - ...this creates a pipeline object that's compatible with the currently - active context, alternatively call: - - sgl_pipeline_pip = sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc* desc) - - ...to create a pipeline object that's compatible with an explicitly - provided context. - - The similarity with sokol_gfx.h's sg_pipeline type and sg_make_pipeline() - function is intended. sgl_make_pipeline() also takes a standard - sokol-gfx sg_pipeline_desc object to describe the render state, but - without: - - shader - - vertex layout - - color- and depth-pixel-formats - - primitive type (lines, triangles, ...) - - MSAA sample count - Those will be filled in by sgl_make_pipeline(). Note that each - call to sgl_make_pipeline() needs to create several sokol-gfx - pipeline objects (one for each primitive type). - - 'depth.write_enabled' will be forced to 'false' if the context this - pipeline object is intended for has its depth pixel format set to - SG_PIXELFORMAT_NONE (which means the framebuffer this context is used - with doesn't have a depth-stencil surface). - - --- if you need to destroy sgl_pipeline objects before sgl_shutdown(): - - sgl_destroy_pipeline(sgl_pipeline pip) - - --- After sgl_setup() you can call any of the sokol-gl functions anywhere - in a frame, *except* sgl_draw(). The 'vanilla' functions - will only change internal sokol-gl state, and not call any sokol-gfx - functions. - - --- Unlike OpenGL, sokol-gl has a function to reset internal state to - a known default. This is useful at the start of a sequence of - rendering operations: - - void sgl_defaults(void) - - This will set the following default state: - - - current texture coordinate to u=0.0f, v=0.0f - - current color to white (rgba all 1.0f) - - current point size to 1.0f - - unbind the current texture and texturing will be disabled - - *all* matrices will be set to identity (also the projection matrix) - - the default render state will be set by loading the 'default pipeline' - into the top of the pipeline stack - - The current matrix- and pipeline-stack-depths will not be changed by - sgl_defaults(). - - --- change the currently active renderstate through the - pipeline-stack functions, this works similar to the - traditional GL matrix stack: - - ...load the default pipeline state on the top of the pipeline stack: - - sgl_load_default_pipeline() - - ...load a specific pipeline on the top of the pipeline stack: - - sgl_load_pipeline(sgl_pipeline pip) - - ...push and pop the pipeline stack: - sgl_push_pipeline() - sgl_pop_pipeline() - - --- control texturing with: - - sgl_enable_texture() - sgl_disable_texture() - sgl_texture(sg_image img, sg_sampler smp) - - NOTE: the img and smp handles can be invalid (SG_INVALID_ID), in this - case, sokol-gl will fall back to the internal default (white) texture - and sampler. - - --- set the current viewport and scissor rect with: - - sgl_viewport(int x, int y, int w, int h, bool origin_top_left) - sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left) - - ...or call these alternatives which take float arguments (this might allow - to avoid casting between float and integer in more strongly typed languages - when floating point pixel coordinates are used): - - sgl_viewportf(float x, float y, float w, float h, bool origin_top_left) - sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left) - - ...these calls add a new command to the internal command queue, so - that the viewport or scissor rect are set at the right time relative - to other sokol-gl calls. - - --- adjust the transform matrices, matrix manipulation works just like - the OpenGL matrix stack: - - ...set the current matrix mode: - - sgl_matrix_mode_modelview() - sgl_matrix_mode_projection() - sgl_matrix_mode_texture() - - ...load the identity matrix into the current matrix: - - sgl_load_identity() - - ...translate, rotate and scale the current matrix: - - sgl_translate(float x, float y, float z) - sgl_rotate(float angle_rad, float x, float y, float z) - sgl_scale(float x, float y, float z) - - NOTE that all angles in sokol-gl are in radians, not in degree. - Convert between radians and degree with the helper functions: - - float sgl_rad(float deg) - degrees to radians - float sgl_deg(float rad) - radians to degrees - - ...directly load the current matrix from a float[16] array: - - sgl_load_matrix(const float m[16]) - sgl_load_transpose_matrix(const float m[16]) - - ...directly multiply the current matrix from a float[16] array: - - sgl_mult_matrix(const float m[16]) - sgl_mult_transpose_matrix(const float m[16]) - - The memory layout of those float[16] arrays is the same as in OpenGL. - - ...more matrix functions: - - sgl_frustum(float left, float right, float bottom, float top, float near, float far) - sgl_ortho(float left, float right, float bottom, float top, float near, float far) - sgl_perspective(float fov_y, float aspect, float near, float far) - sgl_lookat(float eye_x, float eye_y, float eye_z, float center_x, float center_y, float center_z, float up_x, float up_y, float up_z) - - These functions work the same as glFrustum(), glOrtho(), gluPerspective() - and gluLookAt(). - - ...and finally to push / pop the current matrix stack: - - sgl_push_matrix(void) - sgl_pop_matrix(void) - - Again, these work the same as glPushMatrix() and glPopMatrix(). - - --- perform primitive rendering: - - ...set the current texture coordinate and color 'registers' with or - point size with: - - sgl_t2f(float u, float v) - set current texture coordinate - sgl_c*(...) - set current color - sgl_point_size(float size) - set current point size - - There are several functions for setting the color (as float values, - unsigned byte values, packed as unsigned 32-bit integer, with - and without alpha). - - NOTE that these are the only functions that can be called both inside - sgl_begin_*() / sgl_end() and outside. - - Also NOTE that point size is currently hardwired to 1.0f if the D3D11 - backend is used. - - ...start a primitive vertex sequence with: - - sgl_begin_points() - sgl_begin_lines() - sgl_begin_line_strip() - sgl_begin_triangles() - sgl_begin_triangle_strip() - sgl_begin_quads() - - ...after sgl_begin_*() specify vertices: - - sgl_v*(...) - sgl_v*_t*(...) - sgl_v*_c*(...) - sgl_v*_t*_c*(...) - - These functions write a new vertex to sokol-gl's internal vertex buffer, - optionally with texture-coords and color. If the texture coordinate - and/or color is missing, it will be taken from the current texture-coord - and color 'register'. - - ...finally, after specifying vertices, call: - - sgl_end() - - This will record a new draw command in sokol-gl's internal command - list, or it will extend the previous draw command if no relevant - state has changed since the last sgl_begin/end pair. - - --- inside a sokol-gfx rendering pass, call the sgl_draw() function - to render the currently active context: - - sgl_draw() - - ...or alternatively call: - - sgl_context_draw(ctx) - - ...to render an explicitly provided context. - - This will render everything that has been recorded in the context since - the last call to sgl_draw() through sokol-gfx, and will 'rewind' the internal - vertex-, uniform- and command-buffers. - - --- each sokol-gl context tracks an internal error code, to query the - current error code for the currently active context call: - - sgl_error_t sgl_error() - - ...alternatively with an explicit context argument: - - sgl_error_t sgl_context_error(ctx); - - ...which can return the following error codes: - - SGL_NO_ERROR - all OK, no error occurred since last sgl_draw() - SGL_ERROR_VERTICES_FULL - internal vertex buffer is full (checked in sgl_end()) - SGL_ERROR_UNIFORMS_FULL - the internal uniforms buffer is full (checked in sgl_end()) - SGL_ERROR_COMMANDS_FULL - the internal command buffer is full (checked in sgl_end()) - SGL_ERROR_STACK_OVERFLOW - matrix- or pipeline-stack overflow - SGL_ERROR_STACK_UNDERFLOW - matrix- or pipeline-stack underflow - SGL_ERROR_NO_CONTEXT - the active context no longer exists - - ...if sokol-gl is in an error-state, sgl_draw() will skip any rendering, - and reset the error code to SGL_NO_ERROR. - - RENDER LAYERS - ============= - Render layers allow to split sokol-gl rendering into separate draw-command - groups which can then be rendered separately in a sokol-gfx draw pass. This - allows to mix/interleave sokol-gl rendering with other render operations. - - Layered rendering is controlled through two functions: - - sgl_layer(int layer_id) - sgl_draw_layer(int layer_id) - - (and the context-variant sgl_draw_layer(): sgl_context_draw_layer() - - The sgl_layer() function sets the 'current layer', any sokol-gl calls - which internally record draw commands will also store the current layer - in the draw command, and later in a sokol-gfx render pass, a call - to sgl_draw_layer() will only render the draw commands that have - a matching layer. - - The default layer is '0', this is active after sokol-gl setup, and - is also restored at the start of a new frame (but *not* by calling - sgl_defaults()). - - NOTE that calling sgl_draw() is equivalent with sgl_draw_layer(0) - (in general you should either use either use sgl_draw() or - sgl_draw_layer() in an application, but not both). - - WORKING WITH CONTEXTS: - ====================== - If you want to render to more than one sokol-gfx render pass you need to - work with additional sokol-gl context objects (one context object for - each offscreen rendering pass, in addition to the implicitly created - 'default context'. - - All sokol-gl state is tracked per context, and there is always a "current - context" (with the notable exception that the currently set context is - destroyed, more on that later). - - Using multiple contexts can also be useful if you only render in - a single pass, but want to maintain multiple independent "state buckets". - - To create new context object, call: - - sgl_context ctx = sgl_make_context(&(sgl_context_desc){ - .max_vertices = ..., // default: 64k - .max_commands = ..., // default: 16k - .color_format = ..., - .depth_format = ..., - .sample_count = ..., - }); - - The color_format, depth_format and sample_count items must be compatible - with the render pass the sgl_draw() or sgL_context_draw() function - will be called in. - - Creating a context does *not* make the context current. To do this, call: - - sgl_set_context(ctx); - - The currently active context will implicitly be used by most sokol-gl functions - which don't take an explicit context handle as argument. - - To switch back to the default context, pass the global constant SGL_DEFAULT_CONTEXT: - - sgl_set_context(SGL_DEFAULT_CONTEXT); - - ...or alternatively use the function sgl_default_context() instead of the - global constant: - - sgl_set_context(sgl_default_context()); - - To get the currently active context, call: - - sgl_context cur_ctx = sgl_get_context(); - - The following functions exist in two variants, one which use the currently - active context (set with sgl_set_context()), and another version which - takes an explicit context handle instead: - - sgl_make_pipeline() vs sgl_context_make_pipeline() - sgl_error() vs sgl_context_error(); - sgl_draw() vs sgl_context_draw(); - - Except for using the currently active context versus a provided context - handle, the two variants are exactlyidentical, e.g. the following - code sequences do the same thing: - - sgl_set_context(ctx); - sgl_pipeline pip = sgl_make_pipeline(...); - sgl_error_t err = sgl_error(); - sgl_draw(); - - vs - - sgl_pipeline pip = sgl_context_make_pipeline(ctx, ...); - sgl_error_t err = sgl_context_error(ctx); - sgl_context_draw(ctx); - - Destroying the currently active context is a 'soft error'. All following - calls which require a currently active context will silently fail, - and sgl_error() will return SGL_ERROR_NO_CONTEXT. - - UNDER THE HOOD: - =============== - sokol_gl.h works by recording vertex data and rendering commands into - memory buffers, and then drawing the recorded commands via sokol_gfx.h - - The only functions which call into sokol_gfx.h are: - - sgl_setup() - - sgl_shutdown() - - sgl_draw() (and variants) - - sgl_setup() must be called after initializing sokol-gfx. - sgl_shutdown() must be called before shutting down sokol-gfx. - sgl_draw() must be called once per frame inside a sokol-gfx render pass. - - All other sokol-gl function can be called anywhere in a frame, since - they just record data into memory buffers owned by sokol-gl. - - What happens in: - - sgl_setup(): - Unique resources shared by all contexts are created: - - a shader object (using embedded shader source or byte code) - - an 8x8 white default texture - The default context is created, which involves: - - 3 memory buffers are created, one for vertex data, - one for uniform data, and one for commands - - a dynamic vertex buffer is created - - the default sgl_pipeline object is created, which involves - creating 5 sg_pipeline objects - - One vertex is 24 bytes: - - float3 position - - float2 texture coords - - uint32_t color - - One uniform block is 128 bytes: - - mat4 model-view-projection matrix - - mat4 texture matrix - - One draw command is ca. 24 bytes for the actual - command code plus command arguments. - - Each sgl_end() consumes one command, and one uniform block - (only when the matrices have changed). - The required size for one sgl_begin/end pair is (at most): - - (152 + 24 * num_verts) bytes - - sgl_shutdown(): - - all sokol-gfx resources (buffer, shader, default-texture and - all pipeline objects) are destroyed - - the 3 memory buffers are freed - - sgl_draw() (and variants) - - copy all recorded vertex data into the dynamic sokol-gfx buffer - via a call to sg_update_buffer() - - for each recorded command: - - if the layer number stored in the command doesn't match - the layer that's to be rendered, skip to the next - command - - if it's a viewport command, call sg_apply_viewport() - - if it's a scissor-rect command, call sg_apply_scissor_rect() - - if it's a draw command: - - depending on what has changed since the last draw command, - call sg_apply_pipeline(), sg_apply_bindings() and - sg_apply_uniforms() - - finally call sg_draw() - - All other functions only modify the internally tracked state, add - data to the vertex, uniform and command buffers, or manipulate - the matrix stack. - - ON DRAW COMMAND MERGING - ======================= - Not every call to sgl_end() will automatically record a new draw command. - If possible, the previous draw command will simply be extended, - resulting in fewer actual draw calls later in sgl_draw(). - - A draw command will be merged with the previous command if "no relevant - state has changed" since the last sgl_end(), meaning: - - - no calls to sgl_viewport() and sgl_scissor_rect() - - the primitive type hasn't changed - - the primitive type isn't a 'strip type' (no line or triangle strip) - - the pipeline state object hasn't changed - - the current layer hasn't changed - - none of the matrices has changed - - none of the texture state has changed - - Merging a draw command simply means that the number of vertices - to render in the previous draw command will be incremented by the - number of vertices in the new draw command. - - MEMORY ALLOCATION OVERRIDE - ========================== - You can override the memory allocation functions at initialization time - like this: - - void* my_alloc(size_t size, void* user_data) { - return malloc(size); - } - - void my_free(void* ptr, void* user_data) { - free(ptr); - } - - ... - sgl_setup(&(sgl_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - - ERROR REPORTING AND LOGGING - =========================== - To get any logging information at all you need to provide a logging callback in the setup call, - the easiest way is to use sokol_log.h: - - #include "sokol_log.h" - - sgl_setup(&(sgl_desc_t){ - // ... - .logger.func = slog_func - }); - - To override logging with your own callback, first write a logging function like this: - - void my_log(const char* tag, // e.g. 'sgl' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SGL_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_gl.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-gl like this: - - sgl_setup(&(sgl_desc_t){ - .logger = { - .func = my_log, - .user_data = my_user_data, - } - }); - - The provided logging function must be reentrant (e.g. be callable from - different threads). - - If you don't want to provide your own custom logger it is highly recommended to use - the standard logger in sokol_log.h instead, otherwise you won't see any warnings or - errors. - - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2018 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_GL_INCLUDED (1) -#include -#include -#include // size_t, offsetof - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_gl.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL) -#define SOKOL_GL_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_GL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GL_IMPL) -#define SOKOL_GL_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_GL_API_DECL __declspec(dllimport) -#else -#define SOKOL_GL_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sgl_log_item_t - - Log items are defined via X-Macros, and expanded to an - enum 'sgl_log_item' - and in debug mode only - corresponding strings. - - Used as parameter in the logging callback. -*/ -#define _SGL_LOG_ITEMS \ - _SGL_LOGITEM_XMACRO(OK, "Ok") \ - _SGL_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SGL_LOGITEM_XMACRO(MAKE_PIPELINE_FAILED, "sg_make_pipeline() failed") \ - _SGL_LOGITEM_XMACRO(PIPELINE_POOL_EXHAUSTED, "pipeline pool exhausted (use sgl_desc_t.pipeline_pool_size to adjust)") \ - _SGL_LOGITEM_XMACRO(ADD_COMMIT_LISTENER_FAILED, "sg_add_commit_listener() failed") \ - _SGL_LOGITEM_XMACRO(CONTEXT_POOL_EXHAUSTED, "context pool exhausted (use sgl_desc_t.context_pool_size to adjust)") \ - _SGL_LOGITEM_XMACRO(CANNOT_DESTROY_DEFAULT_CONTEXT, "cannot destroy default context") \ - -#define _SGL_LOGITEM_XMACRO(item,msg) SGL_LOGITEM_##item, -typedef enum sgl_log_item_t { - _SGL_LOG_ITEMS -} sgl_log_item_t; -#undef _SGL_LOGITEM_XMACRO - -/* - sgl_logger_t - - Used in sgl_desc_t to provide a custom logging and error reporting - callback to sokol-gl. -*/ -typedef struct sgl_logger_t { - void (*func)( - const char* tag, // always "sgl" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SGL_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_gl.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sgl_logger_t; - -/* sokol_gl pipeline handle (created with sgl_make_pipeline()) */ -typedef struct sgl_pipeline { uint32_t id; } sgl_pipeline; - -/* a context handle (created with sgl_make_context()) */ -typedef struct sgl_context { uint32_t id; } sgl_context; - -/* - sgl_error_t - - Errors are reset each frame after calling sgl_draw(), - get the last error code with sgl_error() -*/ -typedef enum sgl_error_t { - SGL_NO_ERROR = 0, - SGL_ERROR_VERTICES_FULL, - SGL_ERROR_UNIFORMS_FULL, - SGL_ERROR_COMMANDS_FULL, - SGL_ERROR_STACK_OVERFLOW, - SGL_ERROR_STACK_UNDERFLOW, - SGL_ERROR_NO_CONTEXT, -} sgl_error_t; - -/* - sgl_context_desc_t - - Describes the initialization parameters of a rendering context. - Creating additional contexts is useful if you want to render - in separate sokol-gfx passes. -*/ -typedef struct sgl_context_desc_t { - int max_vertices; // default: 64k - int max_commands; // default: 16k - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; -} sgl_context_desc_t; - -/* - sgl_allocator_t - - Used in sgl_desc_t to provide custom memory-alloc and -free functions - to sokol_gl.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sgl_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sgl_allocator_t; - -typedef struct sgl_desc_t { - int max_vertices; // default: 64k - int max_commands; // default: 16k - int context_pool_size; // max number of contexts (including default context), default: 4 - int pipeline_pool_size; // size of internal pipeline pool, default: 64 - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_face_winding face_winding; // default: SG_FACEWINDING_CCW - sgl_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - sgl_logger_t logger; // optional log function override (default: NO LOGGING) -} sgl_desc_t; - -/* the default context handle */ -static const sgl_context SGL_DEFAULT_CONTEXT = { 0x00010001 }; - -/* setup/shutdown/misc */ -SOKOL_GL_API_DECL void sgl_setup(const sgl_desc_t* desc); -SOKOL_GL_API_DECL void sgl_shutdown(void); -SOKOL_GL_API_DECL float sgl_rad(float deg); -SOKOL_GL_API_DECL float sgl_deg(float rad); -SOKOL_GL_API_DECL sgl_error_t sgl_error(void); -SOKOL_GL_API_DECL sgl_error_t sgl_context_error(sgl_context ctx); - -/* context functions */ -SOKOL_GL_API_DECL sgl_context sgl_make_context(const sgl_context_desc_t* desc); -SOKOL_GL_API_DECL void sgl_destroy_context(sgl_context ctx); -SOKOL_GL_API_DECL void sgl_set_context(sgl_context ctx); -SOKOL_GL_API_DECL sgl_context sgl_get_context(void); -SOKOL_GL_API_DECL sgl_context sgl_default_context(void); - -/* draw recorded commands (call inside a sokol-gfx render pass) */ -SOKOL_GL_API_DECL void sgl_draw(void); -SOKOL_GL_API_DECL void sgl_context_draw(sgl_context ctx); -SOKOL_GL_API_DECL void sgl_draw_layer(int layer_id); -SOKOL_GL_API_DECL void sgl_context_draw_layer(sgl_context ctx, int layer_id); - -/* create and destroy pipeline objects */ -SOKOL_GL_API_DECL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc); -SOKOL_GL_API_DECL sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc* desc); -SOKOL_GL_API_DECL void sgl_destroy_pipeline(sgl_pipeline pip); - -/* render state functions */ -SOKOL_GL_API_DECL void sgl_defaults(void); -SOKOL_GL_API_DECL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_viewportf(float x, float y, float w, float h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_enable_texture(void); -SOKOL_GL_API_DECL void sgl_disable_texture(void); -SOKOL_GL_API_DECL void sgl_texture(sg_image img, sg_sampler smp); -SOKOL_GL_API_DECL void sgl_layer(int layer_id); - -/* pipeline stack functions */ -SOKOL_GL_API_DECL void sgl_load_default_pipeline(void); -SOKOL_GL_API_DECL void sgl_load_pipeline(sgl_pipeline pip); -SOKOL_GL_API_DECL void sgl_push_pipeline(void); -SOKOL_GL_API_DECL void sgl_pop_pipeline(void); - -/* matrix stack functions */ -SOKOL_GL_API_DECL void sgl_matrix_mode_modelview(void); -SOKOL_GL_API_DECL void sgl_matrix_mode_projection(void); -SOKOL_GL_API_DECL void sgl_matrix_mode_texture(void); -SOKOL_GL_API_DECL void sgl_load_identity(void); -SOKOL_GL_API_DECL void sgl_load_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_load_transpose_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_mult_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_mult_transpose_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_rotate(float angle_rad, float x, float y, float z); -SOKOL_GL_API_DECL void sgl_scale(float x, float y, float z); -SOKOL_GL_API_DECL void sgl_translate(float x, float y, float z); -SOKOL_GL_API_DECL void sgl_frustum(float l, float r, float b, float t, float n, float f); -SOKOL_GL_API_DECL void sgl_ortho(float l, float r, float b, float t, float n, float f); -SOKOL_GL_API_DECL void sgl_perspective(float fov_y, float aspect, float z_near, float z_far); -SOKOL_GL_API_DECL void sgl_lookat(float eye_x, float eye_y, float eye_z, float center_x, float center_y, float center_z, float up_x, float up_y, float up_z); -SOKOL_GL_API_DECL void sgl_push_matrix(void); -SOKOL_GL_API_DECL void sgl_pop_matrix(void); - -/* these functions only set the internal 'current texcoord / color / point size' (valid inside or outside begin/end) */ -SOKOL_GL_API_DECL void sgl_t2f(float u, float v); -SOKOL_GL_API_DECL void sgl_c3f(float r, float g, float b); -SOKOL_GL_API_DECL void sgl_c4f(float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_c3b(uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_c4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_c1i(uint32_t rgba); -SOKOL_GL_API_DECL void sgl_point_size(float s); - -/* define primitives, each begin/end is one draw command */ -SOKOL_GL_API_DECL void sgl_begin_points(void); -SOKOL_GL_API_DECL void sgl_begin_lines(void); -SOKOL_GL_API_DECL void sgl_begin_line_strip(void); -SOKOL_GL_API_DECL void sgl_begin_triangles(void); -SOKOL_GL_API_DECL void sgl_begin_triangle_strip(void); -SOKOL_GL_API_DECL void sgl_begin_quads(void); -SOKOL_GL_API_DECL void sgl_v2f(float x, float y); -SOKOL_GL_API_DECL void sgl_v3f(float x, float y, float z); -SOKOL_GL_API_DECL void sgl_v2f_t2f(float x, float y, float u, float v); -SOKOL_GL_API_DECL void sgl_v3f_t2f(float x, float y, float z, float u, float v); -SOKOL_GL_API_DECL void sgl_v2f_c3f(float x, float y, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v2f_c3b(float x, float y, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v2f_c4f(float x, float y, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v2f_c4b(float x, float y, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v2f_c1i(float x, float y, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_v3f_c3f(float x, float y, float z, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v3f_c3b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v3f_c4f(float x, float y, float z, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v3f_c4b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v3f_c1i(float x, float y, float z, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c3f(float x, float y, float u, float v, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c3b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c4f(float x, float y, float u, float v, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c4b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c1i(float x, float y, float u, float v, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c3f(float x, float y, float z, float u, float v, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c3b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c4f(float x, float y, float z, float u, float v, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_end(void); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for C++ */ -inline void sgl_setup(const sgl_desc_t& desc) { return sgl_setup(&desc); } -inline sgl_context sgl_make_context(const sgl_context_desc_t& desc) { return sgl_make_context(&desc); } -inline sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc& desc) { return sgl_make_pipeline(&desc); } -inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc& desc) { return sgl_context_make_pipeline(ctx, &desc); } -#endif -#endif /* SOKOL_GL_INCLUDED */ - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_GL_IMPL -#define SOKOL_GL_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sgl_desc_t.allocator to override memory allocation functions" -#endif - -#include // malloc/free -#include // memset -#include // M_PI, sqrtf, sinf, cosf - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327 -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#define _sgl_def(val, def) (((val) == 0) ? (def) : (val)) -#define _SGL_INIT_COOKIE (0xABCDABCD) - -/* - Embedded source code compiled with: - - sokol-shdc -i sgl.glsl -o sgl.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - mat4 mvp; - mat4 tm; - }; - in vec4 position; - in vec2 texcoord0; - in vec4 color0; - in float psize; - out vec4 uv; - out vec4 color; - void main() { - gl_Position = mvp * position; - #ifndef SOKOL_WGSL - gl_PointSize = psize; - #endif - uv = tm * vec4(texcoord0, 0.0, 1.0); - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec4 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv.xy) * color; - } - @end - - @program sgl vs fs -*/ - -#if defined(SOKOL_GLCORE33) -static const char _sgl_vs_source_glsl330[478] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69, - 0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30, - 0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a, - 0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34, - 0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sgl_fs_source_glsl330[180] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74, - 0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20, - 0x75,0x76,0x2e,0x78,0x79,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const char _sgl_vs_source_glsl300es[481] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x20,0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74, - 0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b, - 0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20, - 0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70, - 0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d, - 0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65, - 0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e, - 0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -static const char _sgl_fs_source_glsl300es[253] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e,0x78,0x79,0x29,0x20, - 0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sgl_vs_bytecode_metal_macos[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x76,0x25,0x5f,0x37,0x22,0xd0,0x3f, - 0x64,0xef,0xff,0xc3,0x45,0x1a,0x3d,0xb7,0x5e,0x83,0x13,0x96,0xd3,0x09,0xec,0x53, - 0x25,0xd5,0x7e,0x0c,0xed,0xb9,0x58,0x34,0x02,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc4,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xee,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x81,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x18,0x42, - 0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40, - 0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04,0x60,0x89,0x10,0x02, - 0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2,0x50,0x0f,0xe3,0x40, - 0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0,0x07,0xed,0x10,0x0e, - 0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x49, - 0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28,0x86,0x08,0x23,0x80, - 0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80,0xc2,0x20,0x42,0x20, - 0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0xc8,0x02,0x01,0x00,0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18, - 0x50,0x08,0x65,0x50,0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x34, - 0x01,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32, - 0x28,0x00,0xb3,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0x81,0x22,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25, - 0x58,0x90,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82, - 0x45,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04, - 0x65,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba, - 0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61, - 0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde, - 0xc2,0xe8,0x68,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95, - 0x51,0xa8,0xb3,0x1b,0xc2,0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9, - 0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26, - 0x37,0x84,0x51,0x1e,0xc5,0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7, - 0x02,0xf7,0x36,0x97,0x46,0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e, - 0x8d,0x2e,0xed,0xcd,0x6d,0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2, - 0xd2,0xe4,0x5c,0xe0,0xde,0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1, - 0xbd,0x85,0xd1,0x91,0x39,0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b, - 0x1b,0xa2,0x28,0x9c,0x12,0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9, - 0x94,0x8f,0x50,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b, - 0x5c,0x1d,0x1d,0xa5,0xb0,0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7, - 0xaf,0x34,0x37,0xb2,0x32,0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64, - 0x28,0x5f,0x5f,0x61,0x69,0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64, - 0x65,0x72,0x5f,0x5f,0x29,0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50, - 0x8b,0xa0,0x84,0x81,0x22,0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93, - 0x42,0x06,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd, - 0xc9,0x91,0xc1,0x0c,0xa1,0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31, - 0x50,0x22,0xc5,0x0c,0x94,0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43, - 0xa8,0x65,0x50,0xc2,0x40,0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94, - 0x49,0x49,0x03,0x16,0x70,0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11, - 0x83,0xc5,0x58,0x02,0x65,0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69, - 0x72,0x2e,0x62,0x75,0x66,0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc, - 0xcc,0xca,0xe4,0xbe,0xe6,0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85, - 0x91,0x91,0x0a,0x4b,0x93,0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83, - 0x2b,0xfb,0x4a,0x73,0x33,0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3, - 0xa1,0xcd,0x0e,0x8e,0x02,0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50, - 0xe4,0x60,0x21,0x16,0x62,0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b, - 0x98,0xdc,0xd9,0x17,0x5d,0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34, - 0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7, - 0xaf,0xb9,0x34,0xbd,0x32,0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c, - 0xbe,0x62,0x72,0x86,0x90,0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0, - 0x08,0x4b,0xa0,0xbc,0x81,0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c, - 0x89,0x12,0x29,0x77,0xa0,0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51, - 0x03,0x85,0x0d,0x94,0x3c,0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b, - 0x73,0x4b,0x83,0x7b,0xa3,0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95, - 0xd6,0x06,0xc7,0x56,0x06,0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50, - 0xfa,0x60,0x88,0xa1,0xf0,0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83, - 0x46,0x19,0x11,0xb1,0x03,0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4, - 0x03,0x3b,0x94,0x83,0x1b,0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18, - 0x46,0x28,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40, - 0x0f,0x53,0x82,0x62,0xc4,0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f, - 0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e, - 0xc0,0x0e,0xe1,0xe0,0x0e,0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50, - 0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e, - 0xf2,0xe0,0x06,0xe3,0xf0,0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef, - 0x00,0x0f,0xf4,0x90,0x0e,0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12, - 0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25, - 0xd8,0x03,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00, - 0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22, - 0x86,0x61,0x18,0xc6,0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40, - 0x19,0x14,0x01,0xbd,0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00, - 0x00,0xe3,0x15,0x4b,0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9, - 0x8c,0x57,0x3c,0x55,0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63, - 0x41,0x01,0x9f,0xf1,0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43, - 0x99,0x10,0xc8,0xc7,0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50, - 0x06,0x19,0xbe,0x48,0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68, - 0x03,0x36,0x20,0x03,0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b, - 0xc4,0x00,0x0d,0xe2,0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42, - 0x20,0x1f,0x0b,0x0a,0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05, - 0xc5,0x86,0x00,0x3e,0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d, - 0xc1,0x23,0xcc,0x36,0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00, - 0x00,0x5b,0x86,0x20,0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61, - 0xcb,0xf0,0x04,0xa0,0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19, - 0xba,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_fs_bytecode_metal_macos[2825] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xb9,0x65,0x80,0x88,0xa2,0xc8,0x18, - 0x8d,0x2a,0x38,0xc1,0x87,0xa4,0x7f,0x35,0x83,0x69,0xdc,0x8c,0xcb,0x7b,0x11,0x67, - 0x89,0xc7,0xf0,0x8a,0x99,0x36,0x06,0xc5,0x90,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x10,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x81,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x41,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81,0x00,0x00,0x00, - 0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70, - 0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb7,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42, - 0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45, - 0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84, - 0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0, - 0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32, - 0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe, - 0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d, - 0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c, - 0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e, - 0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34, - 0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72, - 0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x14,0xea,0xec,0x86,0x48,0xcb,0xf0,0x58, - 0xcf,0xf5,0x60,0x4f,0xf6,0x40,0x4f,0xf4,0x48,0x8f,0xc6,0xa5,0x6e,0xae,0x4c,0x0e, - 0x85,0xed,0x6d,0xcc,0x2d,0x26,0x85,0xc5,0xd8,0x1b,0xdb,0x9b,0xdc,0x10,0x69,0x11, - 0x1e,0xeb,0xe1,0x1e,0xec,0xc9,0x1e,0xe8,0x89,0x1e,0xe9,0xe9,0xb8,0x84,0xa5,0xc9, - 0xb9,0xd0,0x95,0xe1,0xd1,0xd5,0xc9,0x95,0x51,0x0a,0x4b,0x93,0x73,0x61,0x7b,0x1b, - 0x0b,0xa3,0x4b,0x7b,0x73,0xfb,0x4a,0x73,0x23,0x2b,0xc3,0xa3,0x12,0x96,0x26,0xe7, - 0x32,0x17,0xd6,0x06,0xc7,0x56,0x46,0x8c,0xae,0x0c,0x8f,0xae,0x4e,0xae,0x4c,0x86, - 0x8c,0xc7,0x8c,0xed,0x2d,0x8c,0x8e,0x05,0x64,0x2e,0xac,0x0d,0x8e,0xad,0xcc,0x87, - 0x03,0x5d,0x19,0xde,0x10,0x6a,0x21,0x9e,0xef,0x01,0x83,0x65,0x58,0x84,0x27,0x0c, - 0x1e,0xe8,0x11,0x83,0x47,0x7a,0xc6,0x80,0x4b,0x58,0x9a,0x9c,0xcb,0x5c,0x58,0x1b, - 0x1c,0x5b,0x99,0x1c,0x8f,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39,0x0e,0x73,0x6d,0x70, - 0x43,0xa4,0xe5,0x78,0xca,0xe0,0x01,0x83,0x65,0x58,0x84,0x07,0x7a,0xcc,0xe0,0x91, - 0x9e,0x33,0x18,0x82,0x3c,0xdb,0xe3,0x3d,0x64,0xf0,0xa0,0xc1,0x10,0x03,0x01,0x9e, - 0xea,0x49,0x83,0x11,0x11,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xb4,0xc3,0x3b,0x90, - 0x43,0x3d,0xb0,0x43,0x39,0xb8,0x81,0x39,0xb0,0x43,0x38,0x9c,0xc3,0x3c,0x4c,0x11, - 0x82,0x61,0x84,0xc2,0x0e,0xec,0x60,0x0f,0xed,0xe0,0x06,0xe9,0x40,0x0e,0xe5,0xe0, - 0x0e,0xf4,0x30,0x25,0x28,0x46,0x2c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xf6,0x50,0x0e, - 0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x30,0x46,0x50,0xe1,0x90,0x0e,0xf2, - 0xe0,0x06,0xec,0x10,0x0e,0xee,0x70,0x0e,0xf5,0x10,0x0e,0xe7,0x50,0x0e,0xbf,0x60, - 0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x64,0xc4,0x14,0x0e, - 0xe9,0x20,0x0f,0x6e,0x30,0x0e,0xef,0xd0,0x0e,0xf0,0x90,0x0e,0xec,0x50,0x0e,0xbf, - 0xf0,0x0e,0xf0,0x40,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x0f,0x53,0x06,0x85,0x71,0x46, - 0x30,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe6,0x20,0x0f,0xe1,0x70,0x0e,0xed,0x50,0x0e, - 0xee,0x40,0x0f,0x53,0x02,0x35,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0f,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0xc4,0x46,0x00,0xc6,0x12,0x80,0x80, - 0xd4,0x08,0x40,0x0d,0x90,0x98,0x01,0xa0,0x30,0x03,0x40,0x60,0x04,0x00,0x00,0x00, - 0x00,0x83,0x0c,0x8b,0x60,0x8c,0x18,0x28,0x42,0x40,0x29,0x49,0x50,0x20,0x86,0x60, - 0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_vs_bytecode_metal_ios[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x17,0x11,0x57,0x16,0x94,0x42,0x52, - 0xfb,0x1e,0xd0,0x32,0xfd,0x87,0x16,0xb0,0xa4,0xd0,0xc2,0x43,0xbe,0x93,0x8c,0xe0, - 0x2d,0x7a,0x5c,0x3e,0x06,0x4c,0x57,0xeb,0x4b,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc0,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xed,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x82,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x20,0x42, - 0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00, - 0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48, - 0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90, - 0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04, - 0x60,0x89,0x10,0x02,0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2, - 0x50,0x0f,0xe3,0x40,0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0, - 0x07,0xed,0x10,0x0e,0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44, - 0x09,0x93,0x5f,0x49,0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28, - 0x86,0x08,0x23,0x80,0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80, - 0xc2,0x20,0x42,0x20,0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18,0x50,0x08,0x65,0x50, - 0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x40,0x02,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28,0x00,0xb3,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0x81,0x22,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58,0x90,0x45,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d, - 0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6, - 0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79, - 0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x68,0xc8,0x84, - 0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2, - 0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61, - 0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26,0x37,0x84,0x51,0x1e,0xc5, - 0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7,0x02,0xf7,0x36,0x97,0x46, - 0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x6d, - 0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2,0xd2,0xe4,0x5c,0xe0,0xde, - 0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1,0xbd,0x85,0xd1,0x91,0x39, - 0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b,0x1b,0xa2,0x28,0x9c,0x12, - 0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9,0x94,0x8f,0x50,0x58,0x9a, - 0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b,0x5c,0x1d,0x1d,0xa5,0xb0, - 0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7,0xaf,0x34,0x37,0xb2,0x32, - 0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x28,0x5f,0x5f,0x61,0x69, - 0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,0x5f,0x5f,0x29, - 0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50,0x8b,0xa0,0x84,0x81,0x22, - 0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93,0x42,0x06,0x34,0xcc,0xd8, - 0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd,0xc9,0x91,0xc1,0x0c,0xa1, - 0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31,0x50,0x22,0xc5,0x0c,0x94, - 0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65,0x50,0xc2,0x40, - 0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94,0x49,0x49,0x03,0x16,0x70, - 0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11,0x83,0xc5,0x58,0x02,0x65, - 0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69,0x72,0x2e,0x62,0x75,0x66, - 0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc,0xcc,0xca,0xe4,0xbe,0xe6, - 0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85,0x91,0x91,0x0a,0x4b,0x93, - 0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83,0x2b,0xfb,0x4a,0x73,0x33, - 0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3,0xa1,0xcd,0x0e,0x8e,0x02, - 0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50,0xe4,0x60,0x21,0x16,0x62, - 0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b,0x98,0xdc,0xd9,0x17,0x5d, - 0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3, - 0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7,0xaf,0xb9,0x34,0xbd,0x32, - 0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c,0xbe,0x62,0x72,0x86,0x90, - 0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0,0x08,0x4b,0xa0,0xbc,0x81, - 0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c,0x89,0x12,0x29,0x77,0xa0, - 0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51,0x03,0x85,0x0d,0x94,0x3c, - 0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b,0x73,0x4b,0x83,0x7b,0xa3, - 0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95,0xd6,0x06,0xc7,0x56,0x06, - 0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50,0xfa,0x60,0x88,0xa1,0xf0, - 0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83,0x46,0x19,0x11,0xb1,0x03, - 0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4,0x03,0x3b,0x94,0x83,0x1b, - 0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18,0x46,0x28,0xec,0xc0,0x0e, - 0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40,0x0f,0x53,0x82,0x62,0xc4, - 0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0, - 0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e,0xc0,0x0e,0xe1,0xe0,0x0e, - 0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9, - 0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe3,0xf0, - 0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef,0x00,0x0f,0xf4,0x90,0x0e, - 0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12,0x0e,0xe9,0x20,0x0f,0x6e, - 0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25,0xd8,0x03,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30, - 0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22,0x86,0x61,0x18,0xc6, - 0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40,0x19,0x14,0x01,0xbd, - 0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00,0x00,0xe3,0x15,0x4b, - 0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9,0x8c,0x57,0x3c,0x55, - 0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1, - 0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43,0x99,0x10,0xc8,0xc7, - 0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50,0x06,0x19,0xbe,0x48, - 0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68,0x03,0x36,0x20,0x03, - 0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b,0xc4,0x00,0x0d,0xe2, - 0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42,0x20,0x1f,0x0b,0x0a, - 0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05,0xc5,0x86,0x00,0x3e, - 0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d,0xc1,0x23,0xcc,0x36, - 0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00,0x00,0x5b,0x86,0x20, - 0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61,0xcb,0xf0,0x04,0xa0, - 0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19,0xba,0x00,0x14,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_fs_bytecode_metal_ios[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xc1,0x98,0x28,0x2b,0x2b,0x1f,0x36, - 0x7c,0x5c,0xb0,0x69,0x3f,0xc3,0xd1,0x80,0x4b,0xcf,0xa1,0x10,0xfc,0x19,0x31,0x58, - 0xad,0x45,0xd3,0x5a,0x81,0x72,0x0d,0x8f,0x85,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x08,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x7f,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87, - 0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9, - 0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07, - 0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20, - 0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72, - 0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07, - 0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10, - 0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07, - 0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x18, - 0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03,0x04,0x80,0x00,0x00, - 0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98, - 0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02, - 0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00,0x00,0x79,0x18,0x00, - 0x00,0xb7,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d, - 0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c, - 0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2, - 0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d, - 0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9, - 0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc, - 0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb, - 0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e, - 0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x14, - 0xea,0xec,0x86,0x48,0xcb,0xf0,0x58,0xcf,0xf5,0x60,0x4f,0xf6,0x40,0x4f,0xf4,0x48, - 0x8f,0xc6,0xa5,0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x2d,0x26,0x85,0xc5,0xd8, - 0x1b,0xdb,0x9b,0xdc,0x10,0x69,0x11,0x1e,0xeb,0xe1,0x1e,0xec,0xc9,0x1e,0xe8,0x89, - 0x1e,0xe9,0xe9,0xb8,0x84,0xa5,0xc9,0xb9,0xd0,0x95,0xe1,0xd1,0xd5,0xc9,0x95,0x51, - 0x0a,0x4b,0x93,0x73,0x61,0x7b,0x1b,0x0b,0xa3,0x4b,0x7b,0x73,0xfb,0x4a,0x73,0x23, - 0x2b,0xc3,0xa3,0x12,0x96,0x26,0xe7,0x32,0x17,0xd6,0x06,0xc7,0x56,0x46,0x8c,0xae, - 0x0c,0x8f,0xae,0x4e,0xae,0x4c,0x86,0x8c,0xc7,0x8c,0xed,0x2d,0x8c,0x8e,0x05,0x64, - 0x2e,0xac,0x0d,0x8e,0xad,0xcc,0x87,0x03,0x5d,0x19,0xde,0x10,0x6a,0x21,0x9e,0xef, - 0x01,0x83,0x65,0x58,0x84,0x27,0x0c,0x1e,0xe8,0x11,0x83,0x47,0x7a,0xc6,0x80,0x4b, - 0x58,0x9a,0x9c,0xcb,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x8f,0xb9,0xb0,0x36,0x38, - 0xb6,0x32,0x39,0x0e,0x73,0x6d,0x70,0x43,0xa4,0xe5,0x78,0xca,0xe0,0x01,0x83,0x65, - 0x58,0x84,0x07,0x7a,0xcc,0xe0,0x91,0x9e,0x33,0x18,0x82,0x3c,0xdb,0xe3,0x3d,0x64, - 0xf0,0xa0,0xc1,0x10,0x03,0x01,0x9e,0xea,0x49,0x83,0x11,0x11,0x3b,0xb0,0x83,0x3d, - 0xb4,0x83,0x1b,0xb4,0xc3,0x3b,0x90,0x43,0x3d,0xb0,0x43,0x39,0xb8,0x81,0x39,0xb0, - 0x43,0x38,0x9c,0xc3,0x3c,0x4c,0x11,0x82,0x61,0x84,0xc2,0x0e,0xec,0x60,0x0f,0xed, - 0xe0,0x06,0xe9,0x40,0x0e,0xe5,0xe0,0x0e,0xf4,0x30,0x25,0x28,0x46,0x2c,0xe1,0x90, - 0x0e,0xf2,0xe0,0x06,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25, - 0x30,0x46,0x50,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xec,0x10,0x0e,0xee,0x70,0x0e,0xf5, - 0x10,0x0e,0xe7,0x50,0x0e,0xbf,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0, - 0x0e,0x53,0x02,0x64,0xc4,0x14,0x0e,0xe9,0x20,0x0f,0x6e,0x30,0x0e,0xef,0xd0,0x0e, - 0xf0,0x90,0x0e,0xec,0x50,0x0e,0xbf,0xf0,0x0e,0xf0,0x40,0x0f,0xe9,0xf0,0x0e,0xee, - 0x30,0x0f,0x53,0x06,0x85,0x71,0x46,0x30,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe6,0x20, - 0x0f,0xe1,0x70,0x0e,0xed,0x50,0x0e,0xee,0x40,0x0f,0x53,0x02,0x35,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00, - 0x00,0x0f,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x06,0x00,0x00, - 0x00,0xc4,0x46,0x00,0xc6,0x12,0x80,0x80,0xd4,0x08,0x40,0x0d,0x90,0x98,0x01,0xa0, - 0x30,0x03,0x40,0x60,0x04,0x00,0x00,0x00,0x00,0x83,0x0c,0x8b,0x60,0x8c,0x18,0x28, - 0x42,0x40,0x29,0x49,0x50,0x20,0x86,0x60,0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const char _sgl_vs_source_metal_sim[756] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x74,0x6d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, - 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a, - 0x65,0x20,0x5b,0x5b,0x70,0x6f,0x69,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x5d,0x5d, - 0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74, - 0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72, - 0x64,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75, - 0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69, - 0x62,0x75,0x74,0x65,0x28,0x33,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76, - 0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69, - 0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20, - 0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72, - 0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20,0x2a, - 0x20,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69, - 0x7a,0x65,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20, - 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e, - 0x74,0x6d,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31, - 0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -static const char _sgl_fs_source_metal_sim[439] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x2e,0x78,0x79,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f, - 0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75, - 0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sgl_vs_bytecode_hlsl4[1032] = { - 0x44,0x58,0x42,0x43,0x74,0x7f,0x01,0xd9,0xf4,0xd5,0xed,0x1d,0x74,0xc1,0x30,0x27, - 0xd8,0xe9,0x9d,0x50,0x01,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x02,0x00,0x00, - 0x8c,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xd8,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0xaf,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f, - 0x6d,0x76,0x70,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f,0x74,0x6d,0x00,0x4d,0x69,0x63,0x72,0x6f, - 0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68, - 0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30, - 0x2e,0x31,0x00,0xab,0x49,0x53,0x47,0x4e,0x74,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x68,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x84,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x61,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x56,0x15,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x36,0x00,0x00,0x05, - 0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00, - 0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x56,0x15,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0xa6,0x1a,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0xf6,0x1f,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54, - 0x74,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0xc8,0x9b,0x66,0x64,0x80,0x2f,0xbe,0x14,0xd9,0x88,0xa0,0x97, - 0x64,0x14,0x66,0xff,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -}; -#elif defined(SOKOL_WGPU) -static const char _sgl_vs_source_wgsl[1162] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x6d,0x76,0x70,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78,0x34,0x66,0x2c,0x0a, - 0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x36,0x34,0x29, - 0x20,0x2a,0x2f,0x0a,0x20,0x20,0x74,0x6d,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78, - 0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29, - 0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76,0x61,0x72, - 0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x66,0x33,0x32,0x3b,0x0a,0x0a, - 0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b, - 0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x32,0x20,0x3a,0x20,0x6d,0x61, - 0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x35,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f, - 0x31,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x32,0x20,0x2a,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x32,0x20,0x3a,0x20,0x6d, - 0x61,0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x74,0x6d, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x36,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x28,0x78,0x5f,0x33,0x32,0x20,0x2a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x33,0x36,0x2e,0x78,0x2c,0x20,0x78, - 0x5f,0x33,0x36,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30, - 0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x35,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x35, - 0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73, - 0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b, - 0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a, - 0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c, - 0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x33,0x29,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x66,0x33,0x32,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65, - 0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x70,0x73,0x69,0x7a,0x65,0x20, - 0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74, - 0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sgl_fs_source_wgsl[647] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x35,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x78,0x5f,0x32,0x33,0x2e,0x78, - 0x2c,0x20,0x78,0x5f,0x32,0x33,0x2e,0x79,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x35,0x20,0x2a,0x20,0x78, - 0x5f,0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f, - 0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40, - 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b, - 0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31, - 0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sgl_vs_source_dummy = ""; -static const char* _sgl_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -// ████████ ██ ██ ██████ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ -// ██ ████ ██████ █████ ███████ -// ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ███████ -// -// >>types -typedef enum { - SGL_PRIMITIVETYPE_POINTS = 0, - SGL_PRIMITIVETYPE_LINES, - SGL_PRIMITIVETYPE_LINE_STRIP, - SGL_PRIMITIVETYPE_TRIANGLES, - SGL_PRIMITIVETYPE_TRIANGLE_STRIP, - SGL_PRIMITIVETYPE_QUADS, - SGL_NUM_PRIMITIVE_TYPES, -} _sgl_primitive_type_t; - -typedef struct { - uint32_t id; - sg_resource_state state; -} _sgl_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sgl_pool_t; - -typedef struct { - _sgl_slot_t slot; - sg_pipeline pip[SGL_NUM_PRIMITIVE_TYPES]; -} _sgl_pipeline_t; - -typedef struct { - _sgl_pool_t pool; - _sgl_pipeline_t* pips; -} _sgl_pipeline_pool_t; - -typedef enum { - SGL_MATRIXMODE_MODELVIEW, - SGL_MATRIXMODE_PROJECTION, - SGL_MATRIXMODE_TEXTURE, - SGL_NUM_MATRIXMODES -} _sgl_matrix_mode_t; - -typedef struct { - float pos[3]; - float uv[2]; - uint32_t rgba; - float psize; -} _sgl_vertex_t; - -typedef struct { - float v[4][4]; -} _sgl_matrix_t; - -typedef struct { - _sgl_matrix_t mvp; /* model-view-projection matrix */ - _sgl_matrix_t tm; /* texture matrix */ -} _sgl_uniform_t; - -typedef enum { - SGL_COMMAND_DRAW, - SGL_COMMAND_VIEWPORT, - SGL_COMMAND_SCISSOR_RECT, -} _sgl_command_type_t; - -typedef struct { - sg_pipeline pip; - sg_image img; - sg_sampler smp; - int base_vertex; - int num_vertices; - int uniform_index; -} _sgl_draw_args_t; - -typedef struct { - int x, y, w, h; - bool origin_top_left; -} _sgl_viewport_args_t; - -typedef struct { - int x, y, w, h; - bool origin_top_left; -} _sgl_scissor_rect_args_t; - -typedef union { - _sgl_draw_args_t draw; - _sgl_viewport_args_t viewport; - _sgl_scissor_rect_args_t scissor_rect; -} _sgl_args_t; - -typedef struct { - _sgl_command_type_t cmd; - int layer_id; - _sgl_args_t args; -} _sgl_command_t; - -#define _SGL_INVALID_SLOT_INDEX (0) -#define _SGL_MAX_STACK_DEPTH (64) -#define _SGL_DEFAULT_CONTEXT_POOL_SIZE (4) -#define _SGL_DEFAULT_PIPELINE_POOL_SIZE (64) -#define _SGL_DEFAULT_MAX_VERTICES (1<<16) -#define _SGL_DEFAULT_MAX_COMMANDS (1<<14) -#define _SGL_SLOT_SHIFT (16) -#define _SGL_MAX_POOL_SIZE (1<<_SGL_SLOT_SHIFT) -#define _SGL_SLOT_MASK (_SGL_MAX_POOL_SIZE-1) - -typedef struct { - _sgl_slot_t slot; - sgl_context_desc_t desc; - uint32_t frame_id; - uint32_t update_frame_id; - struct { - int cap; - int next; - _sgl_vertex_t* ptr; - } vertices; - struct { - int cap; - int next; - _sgl_uniform_t* ptr; - } uniforms; - struct { - int cap; - int next; - _sgl_command_t* ptr; - } commands; - - /* state tracking */ - int base_vertex; - int vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */ - sgl_error_t error; - bool in_begin; - int layer_id; - float u, v; - uint32_t rgba; - float point_size; - _sgl_primitive_type_t cur_prim_type; - sg_image cur_img; - sg_sampler cur_smp; - bool texturing_enabled; - bool matrix_dirty; /* reset in sgl_end(), set in any of the matrix stack functions */ - - /* sokol-gfx resources */ - sg_buffer vbuf; - sgl_pipeline def_pip; - sg_bindings bind; - - /* pipeline stack */ - int pip_tos; - sgl_pipeline pip_stack[_SGL_MAX_STACK_DEPTH]; - - /* matrix stacks */ - _sgl_matrix_mode_t cur_matrix_mode; - int matrix_tos[SGL_NUM_MATRIXMODES]; - _sgl_matrix_t matrix_stack[SGL_NUM_MATRIXMODES][_SGL_MAX_STACK_DEPTH]; -} _sgl_context_t; - -typedef struct { - _sgl_pool_t pool; - _sgl_context_t* contexts; -} _sgl_context_pool_t; - -typedef struct { - uint32_t init_cookie; - sgl_desc_t desc; - sg_image def_img; // a default white texture - sg_sampler def_smp; // a default sampler - sg_shader shd; // same shader for all contexts - sgl_context def_ctx_id; - sgl_context cur_ctx_id; - _sgl_context_t* cur_ctx; // may be 0! - _sgl_pipeline_pool_t pip_pool; - _sgl_context_pool_t context_pool; -} _sgl_t; -static _sgl_t _sgl; - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SGL_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sgl_log_messages[] = { - _SGL_LOG_ITEMS -}; -#undef _SGL_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SGL_PANIC(code) _sgl_log(SGL_LOGITEM_ ##code, 0, __LINE__) -#define _SGL_ERROR(code) _sgl_log(SGL_LOGITEM_ ##code, 1, __LINE__) -#define _SGL_WARN(code) _sgl_log(SGL_LOGITEM_ ##code, 2, __LINE__) -#define _SGL_INFO(code) _sgl_log(SGL_LOGITEM_ ##code, 3, __LINE__) - -static void _sgl_log(sgl_log_item_t log_item, uint32_t log_level, uint32_t line_nr) { - if (_sgl.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sgl_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sgl.desc.logger.func("sgl", log_level, log_item, message, line_nr, filename, _sgl.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _sgl_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _sgl_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sgl.desc.allocator.alloc_fn) { - ptr = _sgl.desc.allocator.alloc_fn(size, _sgl.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SGL_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _sgl_malloc_clear(size_t size) { - void* ptr = _sgl_malloc(size); - _sgl_clear(ptr, size); - return ptr; -} - -static void _sgl_free(void* ptr) { - if (_sgl.desc.allocator.free_fn) { - _sgl.desc.allocator.free_fn(ptr, _sgl.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _sgl_init_pool(_sgl_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - /* slot 0 is reserved for the 'invalid id', so bump the pool size by 1 */ - pool->size = num + 1; - pool->queue_top = 0; - /* generation counters indexable by pool slot index, slot 0 is reserved */ - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _sgl_malloc_clear(gen_ctrs_size); - /* it's not a bug to only reserve 'num' here */ - pool->free_queue = (int*) _sgl_malloc_clear(sizeof(int) * (size_t)num); - /* never allocate the zero-th pool item since the invalid id is 0 */ - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _sgl_discard_pool(_sgl_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sgl_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sgl_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _sgl_pool_alloc_index(_sgl_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SGL_INVALID_SLOT_INDEX; - } -} - -static void _sgl_pool_free_index(_sgl_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - /* debug check against double-free */ - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* allocate the slot at slot_index: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the resource id -*/ -static uint32_t _sgl_slot_alloc(_sgl_pool_t* pool, _sgl_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == SG_RESOURCESTATE_INITIAL) && (slot->id == SG_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SGL_SLOT_SHIFT)|(slot_index & _SGL_SLOT_MASK); - slot->state = SG_RESOURCESTATE_ALLOC; - return slot->id; -} - -/* extract slot index from id */ -static int _sgl_slot_index(uint32_t id) { - int slot_index = (int) (id & _SGL_SLOT_MASK); - SOKOL_ASSERT(_SGL_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -// ██████ ██ ██████ ███████ ██ ██ ███ ██ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██████ ██ ██████ █████ ██ ██ ██ ██ ██ █████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ███████ ██ ██ ████ ███████ ███████ -// -// >>pipelines -static void _sgl_reset_pipeline(_sgl_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _sgl_clear(pip, sizeof(_sgl_pipeline_t)); -} - -static void _sgl_setup_pipeline_pool(int pool_size) { - /* note: the pools here will have an additional item, since slot 0 is reserved */ - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE)); - _sgl_init_pool(&_sgl.pip_pool.pool, pool_size); - size_t pool_byte_size = sizeof(_sgl_pipeline_t) * (size_t)_sgl.pip_pool.pool.size; - _sgl.pip_pool.pips = (_sgl_pipeline_t*) _sgl_malloc_clear(pool_byte_size); -} - -static void _sgl_discard_pipeline_pool(void) { - SOKOL_ASSERT(0 != _sgl.pip_pool.pips); - _sgl_free(_sgl.pip_pool.pips); _sgl.pip_pool.pips = 0; - _sgl_discard_pool(&_sgl.pip_pool.pool); -} - -/* get pipeline pointer without id-check */ -static _sgl_pipeline_t* _sgl_pipeline_at(uint32_t pip_id) { - SOKOL_ASSERT(SG_INVALID_ID != pip_id); - int slot_index = _sgl_slot_index(pip_id); - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < _sgl.pip_pool.pool.size)); - return &_sgl.pip_pool.pips[slot_index]; -} - -/* get pipeline pointer with id-check, returns 0 if no match */ -static _sgl_pipeline_t* _sgl_lookup_pipeline(uint32_t pip_id) { - if (SG_INVALID_ID != pip_id) { - _sgl_pipeline_t* pip = _sgl_pipeline_at(pip_id); - if (pip->slot.id == pip_id) { - return pip; - } - } - return 0; -} - -/* make pipeline id from uint32_t id */ -static sgl_pipeline _sgl_make_pip_id(uint32_t pip_id) { - sgl_pipeline pip = { pip_id }; - return pip; -} - -static sgl_pipeline _sgl_alloc_pipeline(void) { - sgl_pipeline res; - int slot_index = _sgl_pool_alloc_index(&_sgl.pip_pool.pool); - if (_SGL_INVALID_SLOT_INDEX != slot_index) { - res = _sgl_make_pip_id(_sgl_slot_alloc(&_sgl.pip_pool.pool, &_sgl.pip_pool.pips[slot_index].slot, slot_index)); - } else { - /* pool is exhausted */ - res = _sgl_make_pip_id(SG_INVALID_ID); - } - return res; -} - -static void _sgl_init_pipeline(sgl_pipeline pip_id, const sg_pipeline_desc* in_desc, const sgl_context_desc_t* ctx_desc) { - SOKOL_ASSERT((pip_id.id != SG_INVALID_ID) && in_desc && ctx_desc); - - /* create a new desc with 'patched' shader and pixel format state */ - sg_pipeline_desc desc = *in_desc; - desc.layout.buffers[0].stride = sizeof(_sgl_vertex_t); - { - sg_vertex_attr_state* pos = &desc.layout.attrs[0]; - pos->offset = offsetof(_sgl_vertex_t, pos); - pos->format = SG_VERTEXFORMAT_FLOAT3; - } - { - sg_vertex_attr_state* uv = &desc.layout.attrs[1]; - uv->offset = offsetof(_sgl_vertex_t, uv); - uv->format = SG_VERTEXFORMAT_FLOAT2; - } - { - sg_vertex_attr_state* rgba = &desc.layout.attrs[2]; - rgba->offset = offsetof(_sgl_vertex_t, rgba); - rgba->format = SG_VERTEXFORMAT_UBYTE4N; - } - { - sg_vertex_attr_state* psize = &desc.layout.attrs[3]; - psize->offset = offsetof(_sgl_vertex_t, psize); - psize->format = SG_VERTEXFORMAT_FLOAT; - } - if (in_desc->shader.id == SG_INVALID_ID) { - desc.shader = _sgl.shd; - } - desc.index_type = SG_INDEXTYPE_NONE; - desc.sample_count = ctx_desc->sample_count; - if (desc.face_winding == _SG_FACEWINDING_DEFAULT) { - desc.face_winding = _sgl.desc.face_winding; - } - desc.depth.pixel_format = ctx_desc->depth_format; - if (ctx_desc->depth_format == SG_PIXELFORMAT_NONE) { - desc.depth.write_enabled = false; - } - desc.colors[0].pixel_format = ctx_desc->color_format; - if (desc.colors[0].write_mask == _SG_COLORMASK_DEFAULT) { - desc.colors[0].write_mask = SG_COLORMASK_RGB; - } - - _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); - SOKOL_ASSERT(pip && (pip->slot.state == SG_RESOURCESTATE_ALLOC)); - pip->slot.state = SG_RESOURCESTATE_VALID; - for (int i = 0; i < SGL_NUM_PRIMITIVE_TYPES; i++) { - switch (i) { - case SGL_PRIMITIVETYPE_POINTS: - desc.primitive_type = SG_PRIMITIVETYPE_POINTS; - break; - case SGL_PRIMITIVETYPE_LINES: - desc.primitive_type = SG_PRIMITIVETYPE_LINES; - break; - case SGL_PRIMITIVETYPE_LINE_STRIP: - desc.primitive_type = SG_PRIMITIVETYPE_LINE_STRIP; - break; - case SGL_PRIMITIVETYPE_TRIANGLES: - desc.primitive_type = SG_PRIMITIVETYPE_TRIANGLES; - break; - case SGL_PRIMITIVETYPE_TRIANGLE_STRIP: - case SGL_PRIMITIVETYPE_QUADS: - desc.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP; - break; - } - if (SGL_PRIMITIVETYPE_QUADS == i) { - /* quads are emulated via triangles, use the same pipeline object */ - pip->pip[i] = pip->pip[SGL_PRIMITIVETYPE_TRIANGLES]; - } else { - pip->pip[i] = sg_make_pipeline(&desc); - if (pip->pip[i].id == SG_INVALID_ID) { - _SGL_ERROR(MAKE_PIPELINE_FAILED); - pip->slot.state = SG_RESOURCESTATE_FAILED; - } - } - } -} - -static sgl_pipeline _sgl_make_pipeline(const sg_pipeline_desc* desc, const sgl_context_desc_t* ctx_desc) { - SOKOL_ASSERT(desc && ctx_desc); - sgl_pipeline pip_id = _sgl_alloc_pipeline(); - if (pip_id.id != SG_INVALID_ID) { - _sgl_init_pipeline(pip_id, desc, ctx_desc); - } else { - _SGL_ERROR(PIPELINE_POOL_EXHAUSTED); - } - return pip_id; -} - -static void _sgl_destroy_pipeline(sgl_pipeline pip_id) { - _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); - if (pip) { - sg_push_debug_group("sokol-gl"); - for (int i = 0; i < SGL_NUM_PRIMITIVE_TYPES; i++) { - if (i != SGL_PRIMITIVETYPE_QUADS) { - sg_destroy_pipeline(pip->pip[i]); - } - } - sg_pop_debug_group(); - _sgl_reset_pipeline(pip); - _sgl_pool_free_index(&_sgl.pip_pool.pool, _sgl_slot_index(pip_id.id)); - } -} - -static sg_pipeline _sgl_get_pipeline(sgl_pipeline pip_id, _sgl_primitive_type_t prim_type) { - _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); - if (pip) { - return pip->pip[prim_type]; - } else { - sg_pipeline dummy_id = { SG_INVALID_ID }; - return dummy_id; - } -} - -// ██████ ██████ ███ ██ ████████ ███████ ██ ██ ████████ ███████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ████ ██ ███████ ██ ██ ██ ███████ -// -// >>contexts -static void _sgl_reset_context(_sgl_context_t* ctx) { - SOKOL_ASSERT(ctx); - SOKOL_ASSERT(0 == ctx->vertices.ptr); - SOKOL_ASSERT(0 == ctx->uniforms.ptr); - SOKOL_ASSERT(0 == ctx->commands.ptr); - _sgl_clear(ctx, sizeof(_sgl_context_t)); -} - -static void _sgl_setup_context_pool(int pool_size) { - /* note: the pools here will have an additional item, since slot 0 is reserved */ - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE)); - _sgl_init_pool(&_sgl.context_pool.pool, pool_size); - size_t pool_byte_size = sizeof(_sgl_context_t) * (size_t)_sgl.context_pool.pool.size; - _sgl.context_pool.contexts = (_sgl_context_t*) _sgl_malloc_clear(pool_byte_size); -} - -static void _sgl_discard_context_pool(void) { - SOKOL_ASSERT(0 != _sgl.context_pool.contexts); - _sgl_free(_sgl.context_pool.contexts); _sgl.context_pool.contexts = 0; - _sgl_discard_pool(&_sgl.context_pool.pool); -} - -// get context pointer without id-check -static _sgl_context_t* _sgl_context_at(uint32_t ctx_id) { - SOKOL_ASSERT(SG_INVALID_ID != ctx_id); - int slot_index = _sgl_slot_index(ctx_id); - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < _sgl.context_pool.pool.size)); - return &_sgl.context_pool.contexts[slot_index]; -} - -// get context pointer with id-check, returns 0 if no match -static _sgl_context_t* _sgl_lookup_context(uint32_t ctx_id) { - if (SG_INVALID_ID != ctx_id) { - _sgl_context_t* ctx = _sgl_context_at(ctx_id); - if (ctx->slot.id == ctx_id) { - return ctx; - } - } - return 0; -} - -// make context id from uint32_t id -static sgl_context _sgl_make_ctx_id(uint32_t ctx_id) { - sgl_context ctx = { ctx_id }; - return ctx; -} - -static sgl_context _sgl_alloc_context(void) { - sgl_context res; - int slot_index = _sgl_pool_alloc_index(&_sgl.context_pool.pool); - if (_SGL_INVALID_SLOT_INDEX != slot_index) { - res = _sgl_make_ctx_id(_sgl_slot_alloc(&_sgl.context_pool.pool, &_sgl.context_pool.contexts[slot_index].slot, slot_index)); - } else { - // pool is exhausted - res = _sgl_make_ctx_id(SG_INVALID_ID); - } - return res; -} - -// return sgl_context_desc_t with patched defaults -static sgl_context_desc_t _sgl_context_desc_defaults(const sgl_context_desc_t* desc) { - sgl_context_desc_t res = *desc; - res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES); - res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS); - return res; -} - -static void _sgl_identity(_sgl_matrix_t*); -static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx); -static void _sgl_init_context(sgl_context ctx_id, const sgl_context_desc_t* in_desc) { - SOKOL_ASSERT((ctx_id.id != SG_INVALID_ID) && in_desc); - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - SOKOL_ASSERT(ctx); - ctx->desc = _sgl_context_desc_defaults(in_desc); - // NOTE: frame_id must be non-zero, so that updates trigger in first frame - ctx->frame_id = 1; - ctx->cur_img = _sgl.def_img; - ctx->cur_smp = _sgl.def_smp; - - // allocate buffers and pools - ctx->vertices.cap = ctx->desc.max_vertices; - ctx->commands.cap = ctx->uniforms.cap = ctx->desc.max_commands; - ctx->vertices.ptr = (_sgl_vertex_t*) _sgl_malloc((size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t)); - ctx->uniforms.ptr = (_sgl_uniform_t*) _sgl_malloc((size_t)ctx->uniforms.cap * sizeof(_sgl_uniform_t)); - ctx->commands.ptr = (_sgl_command_t*) _sgl_malloc((size_t)ctx->commands.cap * sizeof(_sgl_command_t)); - - // create sokol-gfx resource objects - sg_push_debug_group("sokol-gl"); - - sg_buffer_desc vbuf_desc; - _sgl_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.size = (size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t); - vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.label = "sgl-vertex-buffer"; - ctx->vbuf = sg_make_buffer(&vbuf_desc); - SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id); - ctx->bind.vertex_buffers[0] = ctx->vbuf; - - sg_pipeline_desc def_pip_desc; - _sgl_clear(&def_pip_desc, sizeof(def_pip_desc)); - def_pip_desc.depth.write_enabled = true; - ctx->def_pip = _sgl_make_pipeline(&def_pip_desc, &ctx->desc); - if (!sg_add_commit_listener(_sgl_make_commit_listener(ctx))) { - _SGL_ERROR(ADD_COMMIT_LISTENER_FAILED); - } - sg_pop_debug_group(); - - // default state - ctx->rgba = 0xFFFFFFFF; - ctx->point_size = 1.0f; - for (int i = 0; i < SGL_NUM_MATRIXMODES; i++) { - _sgl_identity(&ctx->matrix_stack[i][0]); - } - ctx->pip_stack[0] = ctx->def_pip; - ctx->matrix_dirty = true; -} - -static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) { - SOKOL_ASSERT(desc); - sgl_context ctx_id = _sgl_alloc_context(); - if (ctx_id.id != SG_INVALID_ID) { - _sgl_init_context(ctx_id, desc); - } else { - _SGL_ERROR(CONTEXT_POOL_EXHAUSTED); - } - return ctx_id; -} - -static void _sgl_destroy_context(sgl_context ctx_id) { - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - SOKOL_ASSERT(ctx->vertices.ptr); - SOKOL_ASSERT(ctx->uniforms.ptr); - SOKOL_ASSERT(ctx->commands.ptr); - - _sgl_free(ctx->vertices.ptr); - _sgl_free(ctx->uniforms.ptr); - _sgl_free(ctx->commands.ptr); - ctx->vertices.ptr = 0; - ctx->uniforms.ptr = 0; - ctx->commands.ptr = 0; - - sg_push_debug_group("sokol-gl"); - sg_destroy_buffer(ctx->vbuf); - _sgl_destroy_pipeline(ctx->def_pip); - sg_remove_commit_listener(_sgl_make_commit_listener(ctx)); - sg_pop_debug_group(); - - _sgl_reset_context(ctx); - _sgl_pool_free_index(&_sgl.context_pool.pool, _sgl_slot_index(ctx_id.id)); - } -} - -// ███ ███ ██ ███████ ██████ -// ████ ████ ██ ██ ██ -// ██ ████ ██ ██ ███████ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██████ -// -// >>misc -static void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) { - ctx->in_begin = true; - ctx->base_vertex = ctx->vertices.next; - ctx->vtx_count = 0; - ctx->cur_prim_type = mode; -} - -static void _sgl_rewind(_sgl_context_t* ctx) { - ctx->frame_id++; - ctx->vertices.next = 0; - ctx->uniforms.next = 0; - ctx->commands.next = 0; - ctx->base_vertex = 0; - ctx->error = SGL_NO_ERROR; - ctx->layer_id = 0; - ctx->matrix_dirty = true; -} - -// called from inside sokol-gfx sg_commit() -static void _sgl_commit_listener(void* userdata) { - _sgl_context_t* ctx = _sgl_lookup_context((uint32_t)(uintptr_t)userdata); - if (ctx) { - _sgl_rewind(ctx); - } -} - -static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx) { - sg_commit_listener listener = { _sgl_commit_listener, (void*)(uintptr_t)(ctx->slot.id) }; - return listener; -} - -static _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) { - if (ctx->vertices.next < ctx->vertices.cap) { - return &ctx->vertices.ptr[ctx->vertices.next++]; - } else { - ctx->error = SGL_ERROR_VERTICES_FULL; - return 0; - } -} - -static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) { - if (ctx->uniforms.next < ctx->uniforms.cap) { - return &ctx->uniforms.ptr[ctx->uniforms.next++]; - } else { - ctx->error = SGL_ERROR_UNIFORMS_FULL; - return 0; - } -} - -static _sgl_command_t* _sgl_cur_command(_sgl_context_t* ctx) { - if (ctx->commands.next > 0) { - return &ctx->commands.ptr[ctx->commands.next - 1]; - } else { - return 0; - } -} - -static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) { - if (ctx->commands.next < ctx->commands.cap) { - return &ctx->commands.ptr[ctx->commands.next++]; - } else { - ctx->error = SGL_ERROR_COMMANDS_FULL; - return 0; - } -} - -static uint32_t _sgl_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r); -} - -static float _sgl_clamp(float v, float lo, float hi) { - if (v < lo) return lo; - else if (v > hi) return hi; - else return v; -} - -static uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) { - uint8_t r_u8 = (uint8_t) (_sgl_clamp(r, 0.0f, 1.0f) * 255.0f); - uint8_t g_u8 = (uint8_t) (_sgl_clamp(g, 0.0f, 1.0f) * 255.0f); - uint8_t b_u8 = (uint8_t) (_sgl_clamp(b, 0.0f, 1.0f) * 255.0f); - uint8_t a_u8 = (uint8_t) (_sgl_clamp(a, 0.0f, 1.0f) * 255.0f); - return _sgl_pack_rgbab(r_u8, g_u8, b_u8, a_u8); -} - -static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, float v, uint32_t rgba) { - SOKOL_ASSERT(ctx->in_begin); - _sgl_vertex_t* vtx; - /* handle non-native primitive types */ - if ((ctx->cur_prim_type == SGL_PRIMITIVETYPE_QUADS) && ((ctx->vtx_count & 3) == 3)) { - /* for quads, before writing the last quad vertex, reuse - the first and third vertex to start the second triangle in the quad - */ - vtx = _sgl_next_vertex(ctx); - if (vtx) { *vtx = *(vtx - 3); } - vtx = _sgl_next_vertex(ctx); - if (vtx) { *vtx = *(vtx - 2); } - } - vtx = _sgl_next_vertex(ctx); - if (vtx) { - vtx->pos[0] = x; vtx->pos[1] = y; vtx->pos[2] = z; - vtx->uv[0] = u; vtx->uv[1] = v; - vtx->rgba = rgba; - vtx->psize = ctx->point_size; - } - ctx->vtx_count++; -} - -static void _sgl_identity(_sgl_matrix_t* m) { - for (int c = 0; c < 4; c++) { - for (int r = 0; r < 4; r++) { - m->v[c][r] = (r == c) ? 1.0f : 0.0f; - } - } -} - -static void _sgl_transpose(_sgl_matrix_t* dst, const _sgl_matrix_t* m) { - SOKOL_ASSERT(dst != m); - for (int c = 0; c < 4; c++) { - for (int r = 0; r < 4; r++) { - dst->v[r][c] = m->v[c][r]; - } - } -} - -/* _sgl_rotate, _sgl_frustum, _sgl_ortho from MESA m_matric.c */ -static void _sgl_matmul4(_sgl_matrix_t* p, const _sgl_matrix_t* a, const _sgl_matrix_t* b) { - for (int r = 0; r < 4; r++) { - float ai0=a->v[0][r], ai1=a->v[1][r], ai2=a->v[2][r], ai3=a->v[3][r]; - p->v[0][r] = ai0*b->v[0][0] + ai1*b->v[0][1] + ai2*b->v[0][2] + ai3*b->v[0][3]; - p->v[1][r] = ai0*b->v[1][0] + ai1*b->v[1][1] + ai2*b->v[1][2] + ai3*b->v[1][3]; - p->v[2][r] = ai0*b->v[2][0] + ai1*b->v[2][1] + ai2*b->v[2][2] + ai3*b->v[2][3]; - p->v[3][r] = ai0*b->v[3][0] + ai1*b->v[3][1] + ai2*b->v[3][2] + ai3*b->v[3][3]; - } -} - -static void _sgl_mul(_sgl_matrix_t* dst, const _sgl_matrix_t* m) { - _sgl_matmul4(dst, dst, m); -} - -static void _sgl_rotate(_sgl_matrix_t* dst, float a, float x, float y, float z) { - - float s = sinf(a); - float c = cosf(a); - - float mag = sqrtf(x*x + y*y + z*z); - if (mag < 1.0e-4F) { - return; - } - x /= mag; - y /= mag; - z /= mag; - float xx = x * x; - float yy = y * y; - float zz = z * z; - float xy = x * y; - float yz = y * z; - float zx = z * x; - float xs = x * s; - float ys = y * s; - float zs = z * s; - float one_c = 1.0f - c; - - _sgl_matrix_t m; - m.v[0][0] = (one_c * xx) + c; - m.v[1][0] = (one_c * xy) - zs; - m.v[2][0] = (one_c * zx) + ys; - m.v[3][0] = 0.0f; - m.v[0][1] = (one_c * xy) + zs; - m.v[1][1] = (one_c * yy) + c; - m.v[2][1] = (one_c * yz) - xs; - m.v[3][1] = 0.0f; - m.v[0][2] = (one_c * zx) - ys; - m.v[1][2] = (one_c * yz) + xs; - m.v[2][2] = (one_c * zz) + c; - m.v[3][2] = 0.0f; - m.v[0][3] = 0.0f; - m.v[1][3] = 0.0f; - m.v[2][3] = 0.0f; - m.v[3][3] = 1.0f; - _sgl_mul(dst, &m); -} - -static void _sgl_scale(_sgl_matrix_t* dst, float x, float y, float z) { - for (int r = 0; r < 4; r++) { - dst->v[0][r] *= x; - dst->v[1][r] *= y; - dst->v[2][r] *= z; - } -} - -static void _sgl_translate(_sgl_matrix_t* dst, float x, float y, float z) { - for (int r = 0; r < 4; r++) { - dst->v[3][r] = dst->v[0][r]*x + dst->v[1][r]*y + dst->v[2][r]*z + dst->v[3][r]; - } -} - -static void _sgl_frustum(_sgl_matrix_t* dst, float left, float right, float bottom, float top, float znear, float zfar) { - float x = (2.0f * znear) / (right - left); - float y = (2.0f * znear) / (top - bottom); - float a = (right + left) / (right - left); - float b = (top + bottom) / (top - bottom); - float c = -(zfar + znear) / (zfar - znear); - float d = -(2.0f * zfar * znear) / (zfar - znear); - _sgl_matrix_t m; - m.v[0][0] = x; m.v[0][1] = 0.0f; m.v[0][2] = 0.0f; m.v[0][3] = 0.0f; - m.v[1][0] = 0.0f; m.v[1][1] = y; m.v[1][2] = 0.0f; m.v[1][3] = 0.0f; - m.v[2][0] = a; m.v[2][1] = b; m.v[2][2] = c; m.v[2][3] = -1.0f; - m.v[3][0] = 0.0f; m.v[3][1] = 0.0f; m.v[3][2] = d; m.v[3][3] = 0.0f; - _sgl_mul(dst, &m); -} - -static void _sgl_ortho(_sgl_matrix_t* dst, float left, float right, float bottom, float top, float znear, float zfar) { - _sgl_matrix_t m; - m.v[0][0] = 2.0f / (right - left); - m.v[1][0] = 0.0f; - m.v[2][0] = 0.0f; - m.v[3][0] = -(right + left) / (right - left); - m.v[0][1] = 0.0f; - m.v[1][1] = 2.0f / (top - bottom); - m.v[2][1] = 0.0f; - m.v[3][1] = -(top + bottom) / (top - bottom); - m.v[0][2] = 0.0f; - m.v[1][2] = 0.0f; - m.v[2][2] = -2.0f / (zfar - znear); - m.v[3][2] = -(zfar + znear) / (zfar - znear); - m.v[0][3] = 0.0f; - m.v[1][3] = 0.0f; - m.v[2][3] = 0.0f; - m.v[3][3] = 1.0f; - - _sgl_mul(dst, &m); -} - -/* _sgl_perspective, _sgl_lookat from Regal project.c */ -static void _sgl_perspective(_sgl_matrix_t* dst, float fovy, float aspect, float znear, float zfar) { - float sine = sinf(fovy / 2.0f); - float delta_z = zfar - znear; - if ((delta_z == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) { - return; - } - float cotan = cosf(fovy / 2.0f) / sine; - _sgl_matrix_t m; - _sgl_identity(&m); - m.v[0][0] = cotan / aspect; - m.v[1][1] = cotan; - m.v[2][2] = -(zfar + znear) / delta_z; - m.v[2][3] = -1.0f; - m.v[3][2] = -2.0f * znear * zfar / delta_z; - m.v[3][3] = 0.0f; - _sgl_mul(dst, &m); -} - -static void _sgl_normalize(float v[3]) { - float r = sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); - if (r == 0.0f) { - return; - } - v[0] /= r; - v[1] /= r; - v[2] /= r; -} - -static void _sgl_cross(float v1[3], float v2[3], float res[3]) { - res[0] = v1[1]*v2[2] - v1[2]*v2[1]; - res[1] = v1[2]*v2[0] - v1[0]*v2[2]; - res[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} - -static void _sgl_lookat(_sgl_matrix_t* dst, - float eye_x, float eye_y, float eye_z, - float center_x, float center_y, float center_z, - float up_x, float up_y, float up_z) -{ - float fwd[3], side[3], up[3]; - - fwd[0] = center_x - eye_x; fwd[1] = center_y - eye_y; fwd[2] = center_z - eye_z; - up[0] = up_x; up[1] = up_y; up[2] = up_z; - _sgl_normalize(fwd); - _sgl_cross(fwd, up, side); - _sgl_normalize(side); - _sgl_cross(side, fwd, up); - - _sgl_matrix_t m; - _sgl_identity(&m); - m.v[0][0] = side[0]; - m.v[1][0] = side[1]; - m.v[2][0] = side[2]; - m.v[0][1] = up[0]; - m.v[1][1] = up[1]; - m.v[2][1] = up[2]; - m.v[0][2] = -fwd[0]; - m.v[1][2] = -fwd[1]; - m.v[2][2] = -fwd[2]; - _sgl_mul(dst, &m); - _sgl_translate(dst, -eye_x, -eye_y, -eye_z); -} - -/* current top-of-stack projection matrix */ -static _sgl_matrix_t* _sgl_matrix_projection(_sgl_context_t* ctx) { - return &ctx->matrix_stack[SGL_MATRIXMODE_PROJECTION][ctx->matrix_tos[SGL_MATRIXMODE_PROJECTION]]; -} - -/* get top-of-stack modelview matrix */ -static _sgl_matrix_t* _sgl_matrix_modelview(_sgl_context_t* ctx) { - return &ctx->matrix_stack[SGL_MATRIXMODE_MODELVIEW][ctx->matrix_tos[SGL_MATRIXMODE_MODELVIEW]]; -} - -/* get top-of-stack texture matrix */ -static _sgl_matrix_t* _sgl_matrix_texture(_sgl_context_t* ctx) { - return &ctx->matrix_stack[SGL_MATRIXMODE_TEXTURE][ctx->matrix_tos[SGL_MATRIXMODE_TEXTURE]]; -} - -/* get pointer to current top-of-stack of current matrix mode */ -static _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) { - return &ctx->matrix_stack[ctx->cur_matrix_mode][ctx->matrix_tos[ctx->cur_matrix_mode]]; -} - -// return sg_context_desc_t with patched defaults -static sgl_desc_t _sgl_desc_defaults(const sgl_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sgl_desc_t res = *desc; - res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES); - res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS); - res.context_pool_size = _sgl_def(desc->context_pool_size, _SGL_DEFAULT_CONTEXT_POOL_SIZE); - res.pipeline_pool_size = _sgl_def(desc->pipeline_pool_size, _SGL_DEFAULT_PIPELINE_POOL_SIZE); - res.face_winding = _sgl_def(desc->face_winding, SG_FACEWINDING_CCW); - return res; -} - -// create resources which are shared between all contexts -static void _sgl_setup_common(void) { - sg_push_debug_group("sokol-gl"); - - uint32_t pixels[64]; - for (int i = 0; i < 64; i++) { - pixels[i] = 0xFFFFFFFF; - } - sg_image_desc img_desc; - _sgl_clear(&img_desc, sizeof(img_desc)); - img_desc.type = SG_IMAGETYPE_2D; - img_desc.width = 8; - img_desc.height = 8; - img_desc.num_mipmaps = 1; - img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - img_desc.data.subimage[0][0] = SG_RANGE(pixels); - img_desc.label = "sgl-default-texture"; - _sgl.def_img = sg_make_image(&img_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sgl.def_img.id); - - sg_sampler_desc smp_desc; - _sgl_clear(&smp_desc, sizeof(smp_desc)); - smp_desc.min_filter = SG_FILTER_NEAREST; - smp_desc.mag_filter = SG_FILTER_NEAREST; - _sgl.def_smp = sg_make_sampler(&smp_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sgl.def_smp.id); - - // one shader for all contexts - sg_shader_desc shd_desc; - _sgl_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[3].name = "psize"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.attrs[3].sem_name = "TEXCOORD"; - shd_desc.attrs[3].sem_index = 3; - sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; - ub->size = sizeof(_sgl_uniform_t); - ub->uniforms[0].name = "vs_params"; - ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - ub->uniforms[0].array_count = 8; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.label = "sgl-shader"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _sgl_vs_source_glsl330; - shd_desc.fs.source = _sgl_fs_source_glsl330; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _sgl_vs_source_glsl300es; - shd_desc.fs.source = _sgl_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = _sgl_vs_source_metal_sim; - shd_desc.fs.source = _sgl_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _sgl_vs_source_wgsl; - shd_desc.fs.source = _sgl_fs_source_wgsl; - #else - shd_desc.vs.source = _sgl_vs_source_dummy; - shd_desc.fs.source = _sgl_fs_source_dummy; - #endif - _sgl.shd = sg_make_shader(&shd_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sgl.shd.id); - sg_pop_debug_group(); -} - -// discard resources which are shared between all contexts -static void _sgl_discard_common(void) { - sg_push_debug_group("sokol-gl"); - sg_destroy_image(_sgl.def_img); - sg_destroy_sampler(_sgl.def_smp); - sg_destroy_shader(_sgl.shd); - sg_pop_debug_group(); -} - -static bool _sgl_is_default_context(sgl_context ctx_id) { - return ctx_id.id == SGL_DEFAULT_CONTEXT.id; -} - -static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { - SOKOL_ASSERT(ctx); - if ((ctx->error == SGL_NO_ERROR) && (ctx->vertices.next > 0) && (ctx->commands.next > 0)) { - sg_push_debug_group("sokol-gl"); - - uint32_t cur_pip_id = SG_INVALID_ID; - uint32_t cur_img_id = SG_INVALID_ID; - uint32_t cur_smp_id = SG_INVALID_ID; - int cur_uniform_index = -1; - - if (ctx->update_frame_id != ctx->frame_id) { - ctx->update_frame_id = ctx->frame_id; - const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sgl_vertex_t) }; - sg_update_buffer(ctx->vbuf, &range); - } - - for (int i = 0; i < ctx->commands.next; i++) { - const _sgl_command_t* cmd = &ctx->commands.ptr[i]; - if (cmd->layer_id != layer_id) { - continue; - } - switch (cmd->cmd) { - case SGL_COMMAND_VIEWPORT: - { - const _sgl_viewport_args_t* args = &cmd->args.viewport; - sg_apply_viewport(args->x, args->y, args->w, args->h, args->origin_top_left); - } - break; - case SGL_COMMAND_SCISSOR_RECT: - { - const _sgl_scissor_rect_args_t* args = &cmd->args.scissor_rect; - sg_apply_scissor_rect(args->x, args->y, args->w, args->h, args->origin_top_left); - } - break; - case SGL_COMMAND_DRAW: - { - const _sgl_draw_args_t* args = &cmd->args.draw; - if (args->pip.id != cur_pip_id) { - sg_apply_pipeline(args->pip); - cur_pip_id = args->pip.id; - /* when pipeline changes, also need to re-apply uniforms and bindings */ - cur_img_id = SG_INVALID_ID; - cur_smp_id = SG_INVALID_ID; - cur_uniform_index = -1; - } - if ((cur_img_id != args->img.id) || (cur_smp_id != args->smp.id)) { - ctx->bind.fs.images[0] = args->img; - ctx->bind.fs.samplers[0] = args->smp; - sg_apply_bindings(&ctx->bind); - cur_img_id = args->img.id; - cur_smp_id = args->smp.id; - } - if (cur_uniform_index != args->uniform_index) { - const sg_range ub_range = { &ctx->uniforms.ptr[args->uniform_index], sizeof(_sgl_uniform_t) }; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &ub_range); - cur_uniform_index = args->uniform_index; - } - /* FIXME: what if number of vertices doesn't match the primitive type? */ - if (args->num_vertices > 0) { - sg_draw(args->base_vertex, args->num_vertices, 1); - } - } - break; - } - } - sg_pop_debug_group(); - } -} - -static sgl_context_desc_t _sgl_as_context_desc(const sgl_desc_t* desc) { - sgl_context_desc_t ctx_desc; - _sgl_clear(&ctx_desc, sizeof(ctx_desc)); - ctx_desc.max_vertices = desc->max_vertices; - ctx_desc.max_commands = desc->max_commands; - ctx_desc.color_format = desc->color_format; - ctx_desc.depth_format = desc->depth_format; - ctx_desc.sample_count = desc->sample_count; - return ctx_desc; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { - SOKOL_ASSERT(desc); - _sgl_clear(&_sgl, sizeof(_sgl)); - _sgl.init_cookie = _SGL_INIT_COOKIE; - _sgl.desc = _sgl_desc_defaults(desc); - _sgl_setup_pipeline_pool(_sgl.desc.pipeline_pool_size); - _sgl_setup_context_pool(_sgl.desc.context_pool_size); - _sgl_setup_common(); - const sgl_context_desc_t ctx_desc = _sgl_as_context_desc(&_sgl.desc); - _sgl.def_ctx_id = sgl_make_context(&ctx_desc); - SOKOL_ASSERT(SGL_DEFAULT_CONTEXT.id == _sgl.def_ctx_id.id); - sgl_set_context(_sgl.def_ctx_id); -} - -SOKOL_API_IMPL void sgl_shutdown(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - // contexts own a pipeline, so destroy contexts before pipelines - for (int i = 0; i < _sgl.context_pool.pool.size; i++) { - _sgl_context_t* ctx = &_sgl.context_pool.contexts[i]; - _sgl_destroy_context(_sgl_make_ctx_id(ctx->slot.id)); - } - for (int i = 0; i < _sgl.pip_pool.pool.size; i++) { - _sgl_pipeline_t* pip = &_sgl.pip_pool.pips[i]; - _sgl_destroy_pipeline(_sgl_make_pip_id(pip->slot.id)); - } - _sgl_discard_context_pool(); - _sgl_discard_pipeline_pool(); - _sgl_discard_common(); - _sgl.init_cookie = 0; -} - -SOKOL_API_IMPL sgl_error_t sgl_error(void) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - return ctx->error; - } else { - return SGL_ERROR_NO_CONTEXT; - } -} - -SOKOL_API_IMPL sgl_error_t sgl_context_error(sgl_context ctx_id) { - const _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - return ctx->error; - } else { - return SGL_ERROR_NO_CONTEXT; - } -} - -SOKOL_API_IMPL float sgl_rad(float deg) { - return (deg * (float)M_PI) / 180.0f; -} - -SOKOL_API_IMPL float sgl_deg(float rad) { - return (rad * 180.0f) / (float)M_PI; -} - -SOKOL_API_IMPL sgl_context sgl_make_context(const sgl_context_desc_t* desc) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - return _sgl_make_context(desc); -} - -SOKOL_API_IMPL void sgl_destroy_context(sgl_context ctx_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - if (_sgl_is_default_context(ctx_id)) { - _SGL_WARN(CANNOT_DESTROY_DEFAULT_CONTEXT); - return; - } - _sgl_destroy_context(ctx_id); - // re-validate the current context pointer (this will return a nullptr - // if we just destroyed the current context) - _sgl.cur_ctx = _sgl_lookup_context(_sgl.cur_ctx_id.id); -} - -SOKOL_API_IMPL void sgl_set_context(sgl_context ctx_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - if (_sgl_is_default_context(ctx_id)) { - _sgl.cur_ctx_id = _sgl.def_ctx_id; - } else { - _sgl.cur_ctx_id = ctx_id; - } - // this will return null if the handle isn't valid - _sgl.cur_ctx = _sgl_lookup_context(_sgl.cur_ctx_id.id); -} - -SOKOL_API_IMPL sgl_context sgl_get_context(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - return _sgl.cur_ctx_id; -} - -SOKOL_API_IMPL sgl_context sgl_default_context(void) { - return SGL_DEFAULT_CONTEXT; -} - -SOKOL_API_IMPL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - return _sgl_make_pipeline(desc, &ctx->desc); - } else { - return _sgl_make_pip_id(SG_INVALID_ID); - } -} - -SOKOL_API_IMPL sgl_pipeline sgl_context_make_pipeline(sgl_context ctx_id, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - const _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - return _sgl_make_pipeline(desc, &ctx->desc); - } else { - return _sgl_make_pip_id(SG_INVALID_ID); - } -} - -SOKOL_API_IMPL void sgl_destroy_pipeline(sgl_pipeline pip_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_destroy_pipeline(pip_id); -} - -SOKOL_API_IMPL void sgl_load_pipeline(sgl_pipeline pip_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->pip_tos >= 0) && (ctx->pip_tos < _SGL_MAX_STACK_DEPTH)); - ctx->pip_stack[ctx->pip_tos] = pip_id; -} - -SOKOL_API_IMPL void sgl_load_default_pipeline(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->pip_tos >= 0) && (ctx->pip_tos < _SGL_MAX_STACK_DEPTH)); - ctx->pip_stack[ctx->pip_tos] = ctx->def_pip; -} - -SOKOL_API_IMPL void sgl_push_pipeline(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - if (ctx->pip_tos < (_SGL_MAX_STACK_DEPTH - 1)) { - ctx->pip_tos++; - ctx->pip_stack[ctx->pip_tos] = ctx->pip_stack[ctx->pip_tos-1]; - } else { - ctx->error = SGL_ERROR_STACK_OVERFLOW; - } -} - -SOKOL_API_IMPL void sgl_pop_pipeline(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - if (ctx->pip_tos > 0) { - ctx->pip_tos--; - } else { - ctx->error = SGL_ERROR_STACK_UNDERFLOW; - } -} - -SOKOL_API_IMPL void sgl_defaults(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->u = 0.0f; ctx->v = 0.0f; - ctx->rgba = 0xFFFFFFFF; - ctx->point_size = 1.0f; - ctx->texturing_enabled = false; - ctx->cur_img = _sgl.def_img; - ctx->cur_smp = _sgl.def_smp; - sgl_load_default_pipeline(); - _sgl_identity(_sgl_matrix_texture(ctx)); - _sgl_identity(_sgl_matrix_modelview(ctx)); - _sgl_identity(_sgl_matrix_projection(ctx)); - ctx->cur_matrix_mode = SGL_MATRIXMODE_MODELVIEW; - ctx->matrix_dirty = true; -} - -SOKOL_API_IMPL void sgl_layer(int layer_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->layer_id = layer_id; -} - -SOKOL_API_IMPL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_command_t* cmd = _sgl_next_command(ctx); - if (cmd) { - cmd->cmd = SGL_COMMAND_VIEWPORT; - cmd->layer_id = ctx->layer_id; - cmd->args.viewport.x = x; - cmd->args.viewport.y = y; - cmd->args.viewport.w = w; - cmd->args.viewport.h = h; - cmd->args.viewport.origin_top_left = origin_top_left; - } -} - -SOKOL_API_IMPL void sgl_viewportf(float x, float y, float w, float h, bool origin_top_left) { - sgl_viewport((int)x, (int)y, (int)w, (int)h, origin_top_left); -} - -SOKOL_API_IMPL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_command_t* cmd = _sgl_next_command(ctx); - if (cmd) { - cmd->cmd = SGL_COMMAND_SCISSOR_RECT; - cmd->layer_id = ctx->layer_id; - cmd->args.scissor_rect.x = x; - cmd->args.scissor_rect.y = y; - cmd->args.scissor_rect.w = w; - cmd->args.scissor_rect.h = h; - cmd->args.scissor_rect.origin_top_left = origin_top_left; - } -} - -SOKOL_API_IMPL void sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left) { - sgl_scissor_rect((int)x, (int)y, (int)w, (int)h, origin_top_left); -} - -SOKOL_API_IMPL void sgl_enable_texture(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->texturing_enabled = true; -} - -SOKOL_API_IMPL void sgl_disable_texture(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->texturing_enabled = false; -} - -SOKOL_API_IMPL void sgl_texture(sg_image img, sg_sampler smp) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - if (SG_INVALID_ID != img.id) { - ctx->cur_img = img; - } else { - ctx->cur_img = _sgl.def_img; - } - if (SG_INVALID_ID != smp.id) { - ctx->cur_smp = smp; - } else { - ctx->cur_smp = _sgl.def_smp; - } -} - -SOKOL_API_IMPL void sgl_begin_points(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_POINTS); -} - -SOKOL_API_IMPL void sgl_begin_lines(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_LINES); -} - -SOKOL_API_IMPL void sgl_begin_line_strip(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_LINE_STRIP); -} - -SOKOL_API_IMPL void sgl_begin_triangles(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_TRIANGLES); -} - -SOKOL_API_IMPL void sgl_begin_triangle_strip(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_TRIANGLE_STRIP); -} - -SOKOL_API_IMPL void sgl_begin_quads(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_QUADS); -} - -SOKOL_API_IMPL void sgl_end(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(ctx->in_begin); - SOKOL_ASSERT(ctx->vertices.next >= ctx->base_vertex); - ctx->in_begin = false; - bool matrix_dirty = ctx->matrix_dirty; - if (matrix_dirty) { - ctx->matrix_dirty = false; - _sgl_uniform_t* uni = _sgl_next_uniform(ctx); - if (uni) { - _sgl_matmul4(&uni->mvp, _sgl_matrix_projection(ctx), _sgl_matrix_modelview(ctx)); - uni->tm = *_sgl_matrix_texture(ctx); - } - } - // check if command can be merged with current command - sg_pipeline pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); - sg_image img = ctx->texturing_enabled ? ctx->cur_img : _sgl.def_img; - sg_sampler smp = ctx->texturing_enabled ? ctx->cur_smp : _sgl.def_smp; - _sgl_command_t* cur_cmd = _sgl_cur_command(ctx); - bool merge_cmd = false; - if (cur_cmd) { - if ((cur_cmd->cmd == SGL_COMMAND_DRAW) && - (cur_cmd->layer_id == ctx->layer_id) && - (ctx->cur_prim_type != SGL_PRIMITIVETYPE_LINE_STRIP) && - (ctx->cur_prim_type != SGL_PRIMITIVETYPE_TRIANGLE_STRIP) && - !matrix_dirty && - (cur_cmd->args.draw.img.id == img.id) && - (cur_cmd->args.draw.smp.id == smp.id) && - (cur_cmd->args.draw.pip.id == pip.id)) - { - merge_cmd = true; - } - } - if (merge_cmd) { - // draw command can be merged with the previous command - cur_cmd->args.draw.num_vertices += ctx->vertices.next - ctx->base_vertex; - } else { - // append a new draw command - _sgl_command_t* cmd = _sgl_next_command(ctx); - if (cmd) { - SOKOL_ASSERT(ctx->uniforms.next > 0); - cmd->cmd = SGL_COMMAND_DRAW; - cmd->layer_id = ctx->layer_id; - cmd->args.draw.img = img; - cmd->args.draw.smp = smp; - cmd->args.draw.pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); - cmd->args.draw.base_vertex = ctx->base_vertex; - cmd->args.draw.num_vertices = ctx->vertices.next - ctx->base_vertex; - cmd->args.draw.uniform_index = ctx->uniforms.next - 1; - } - } -} - -SOKOL_API_IMPL void sgl_point_size(float s) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->point_size = s; - } -} - -SOKOL_API_IMPL void sgl_t2f(float u, float v) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->u = u; - ctx->v = v; - } -} - -SOKOL_API_IMPL void sgl_c3f(float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbaf(r, g, b, 1.0f); - } -} - -SOKOL_API_IMPL void sgl_c4f(float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbaf(r, g, b, a); - } -} - -SOKOL_API_IMPL void sgl_c3b(uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbab(r, g, b, 255); - } -} - -SOKOL_API_IMPL void sgl_c4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbab(r, g, b, a); - } -} - -SOKOL_API_IMPL void sgl_c1i(uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = rgba; - } -} - -SOKOL_API_IMPL void sgl_v2f(float x, float y) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f(float x, float y, float z) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f(float x, float y, float u, float v) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f(float x, float y, float z, float u, float v) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v2f_c3f(float x, float y, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c3b(float x, float y, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c4f(float x, float y, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c4b(float x, float y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c1i(float x, float y, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f_c3f(float x, float y, float z, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c3b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c4f(float x, float y, float z, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c4b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c1i(float x, float y, float z, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, rgba); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c3f(float x, float y, float u, float v, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c3b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c4f(float x, float y, float u, float v, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c4b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c1i(float x, float y, float u, float v, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c3f(float x, float y, float z, float u, float v, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c3b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c4f(float x, float y, float z, float u, float v, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx,x, y, z, u, v, rgba); - } -} - -SOKOL_API_IMPL void sgl_matrix_mode_modelview(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->cur_matrix_mode = SGL_MATRIXMODE_MODELVIEW; - } -} - -SOKOL_API_IMPL void sgl_matrix_mode_projection(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->cur_matrix_mode = SGL_MATRIXMODE_PROJECTION; - } -} - -SOKOL_API_IMPL void sgl_matrix_mode_texture(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->cur_matrix_mode = SGL_MATRIXMODE_TEXTURE; - } -} - -SOKOL_API_IMPL void sgl_load_identity(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_identity(_sgl_matrix(ctx)); -} - -SOKOL_API_IMPL void sgl_load_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - memcpy(&_sgl_matrix(ctx)->v[0][0], &m[0], 64); -} - -SOKOL_API_IMPL void sgl_load_transpose_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_transpose(_sgl_matrix(ctx), (const _sgl_matrix_t*) &m[0]); -} - -SOKOL_API_IMPL void sgl_mult_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - const _sgl_matrix_t* m0 = (const _sgl_matrix_t*) &m[0]; - _sgl_mul(_sgl_matrix(ctx), m0); -} - -SOKOL_API_IMPL void sgl_mult_transpose_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_matrix_t m0; - _sgl_transpose(&m0, (const _sgl_matrix_t*) &m[0]); - _sgl_mul(_sgl_matrix(ctx), &m0); -} - -SOKOL_API_IMPL void sgl_rotate(float angle_rad, float x, float y, float z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_rotate(_sgl_matrix(ctx), angle_rad, x, y, z); -} - -SOKOL_API_IMPL void sgl_scale(float x, float y, float z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_scale(_sgl_matrix(ctx), x, y, z); -} - -SOKOL_API_IMPL void sgl_translate(float x, float y, float z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_translate(_sgl_matrix(ctx), x, y, z); -} - -SOKOL_API_IMPL void sgl_frustum(float l, float r, float b, float t, float n, float f) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_frustum(_sgl_matrix(ctx), l, r, b, t, n, f); -} - -SOKOL_API_IMPL void sgl_ortho(float l, float r, float b, float t, float n, float f) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_ortho(_sgl_matrix(ctx), l, r, b, t, n, f); -} - -SOKOL_API_IMPL void sgl_perspective(float fov_y, float aspect, float z_near, float z_far) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_perspective(_sgl_matrix(ctx), fov_y, aspect, z_near, z_far); -} - -SOKOL_API_IMPL void sgl_lookat(float eye_x, float eye_y, float eye_z, float center_x, float center_y, float center_z, float up_x, float up_y, float up_z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_lookat(_sgl_matrix(ctx), eye_x, eye_y, eye_z, center_x, center_y, center_z, up_x, up_y, up_z); -} - -SOKOL_GL_API_DECL void sgl_push_matrix(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->cur_matrix_mode >= 0) && (ctx->cur_matrix_mode < SGL_NUM_MATRIXMODES)); - ctx->matrix_dirty = true; - if (ctx->matrix_tos[ctx->cur_matrix_mode] < (_SGL_MAX_STACK_DEPTH - 1)) { - const _sgl_matrix_t* src = _sgl_matrix(ctx); - ctx->matrix_tos[ctx->cur_matrix_mode]++; - _sgl_matrix_t* dst = _sgl_matrix(ctx); - *dst = *src; - } else { - ctx->error = SGL_ERROR_STACK_OVERFLOW; - } -} - -SOKOL_GL_API_DECL void sgl_pop_matrix(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->cur_matrix_mode >= 0) && (ctx->cur_matrix_mode < SGL_NUM_MATRIXMODES)); - ctx->matrix_dirty = true; - if (ctx->matrix_tos[ctx->cur_matrix_mode] > 0) { - ctx->matrix_tos[ctx->cur_matrix_mode]--; - } else { - ctx->error = SGL_ERROR_STACK_UNDERFLOW; - } -} - -SOKOL_API_IMPL void sgl_draw(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_draw(ctx, 0); - } -} - -SOKOL_API_IMPL void sgl_draw_layer(int layer_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_draw(ctx, layer_id); - } -} - -SOKOL_API_IMPL void sgl_context_draw(sgl_context ctx_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - _sgl_draw(ctx, 0); - } -} - -SOKOL_API_IMPL void sgl_context_draw_layer(sgl_context ctx_id, int layer_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - _sgl_draw(ctx, layer_id); - } -} - -#endif /* SOKOL_GL_IMPL */ diff --git a/source/engine/thirdparty/sokol/util/sokol_imgui.h b/source/engine/thirdparty/sokol/util/sokol_imgui.h deleted file mode 100644 index 9c041ea..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_imgui.h +++ /dev/null @@ -1,3141 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_IMGUI_IMPL) -#define SOKOL_IMGUI_IMPL -#endif -#ifndef SOKOL_IMGUI_INCLUDED -/* - sokol_imgui.h -- drop-in Dear ImGui renderer/event-handler for sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_IMGUI_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - NOTE that the implementation can be compiled either as C++ or as C. - When compiled as C++, sokol_imgui.h will directly call into the - Dear ImGui C++ API. When compiled as C, sokol_imgui.h will call - cimgui.h functions instead. - - NOTE that the formerly separate header sokol_cimgui.h has been - merged into sokol_imgui.h - - The following defines are used by the implementation to select the - platform-specific embedded shader code (these are the same defines as - used by sokol_gfx.h and sokol_app.h): - - SOKOL_GLCORE33 - SOKOL_GLES3 - SOKOL_D3D11 - SOKOL_METAL - SOKOL_WGPU - - Optionally provide the following configuration define both before including the - the declaration and implementation: - - SOKOL_IMGUI_NO_SOKOL_APP - don't depend on sokol_app.h (see below for details) - - Optionally provide the following macros before including the implementation - to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_IMGUI_API_DECL- public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_IMGUI_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_imgui.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_IMGUI_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before sokol_imgui.h (both before including - the declaration and implementation): - - sokol_gfx.h - sokol_app.h (except SOKOL_IMGUI_NO_SOKOL_APP) - - Additionally, include the following headers before including the - implementation: - - If the implementation is compiled as C++: - imgui.h - - If the implementation is compiled as C: - cimgui.h - - - FEATURE OVERVIEW: - ================= - sokol_imgui.h implements the initialization, rendering and event-handling - code for Dear ImGui (https://github.com/ocornut/imgui) on top of - sokol_gfx.h and (optionally) sokol_app.h. - - The sokol_app.h dependency is optional and used for input event handling. - If you only use sokol_gfx.h but not sokol_app.h in your application, - define SOKOL_IMGUI_NO_SOKOL_APP before including the implementation - of sokol_imgui.h, this will remove any dependency to sokol_app.h, but - you must feed input events into Dear ImGui yourself. - - sokol_imgui.h is not thread-safe, all calls must be made from the - same thread where sokol_gfx.h is running. - - HOWTO: - ====== - - --- To initialize sokol-imgui, call: - - simgui_setup(const simgui_desc_t* desc) - - This will initialize Dear ImGui and create sokol-gfx resources - (two buffers for vertices and indices, a font texture and a pipeline- - state-object). - - Use the following simgui_desc_t members to configure behaviour: - - int max_vertices - The maximum number of vertices used for UI rendering, default is 65536. - sokol-imgui will use this to compute the size of the vertex- - and index-buffers allocated via sokol_gfx.h - - int image_pool_size - Number of simgui_image_t objects which can be alive at the same time. - The default is 256. - - sg_pixel_format color_format - The color pixel format of the render pass where the UI - will be rendered. The default (0) matches sokoL_gfx.h's - default pass. - - sg_pixel_format depth_format - The depth-buffer pixel format of the render pass where - the UI will be rendered. The default (0) matches - sokol_gfx.h's default pass depth format. - - int sample_count - The MSAA sample-count of the render pass where the UI - will be rendered. The default (0) matches sokol_gfx.h's - default pass sample count. - - const char* ini_filename - Sets this path as ImGui::GetIO().IniFilename where ImGui will store - and load UI persistency data. By default this is 0, so that Dear ImGui - will not preserve state between sessions (and also won't do - any filesystem calls). Also see the ImGui functions: - - LoadIniSettingsFromMemory() - - SaveIniSettingsFromMemory() - These functions give you explicit control over loading and saving - UI state while using your own filesystem wrapper functions (in this - case keep simgui_desc.ini_filename zero) - - bool no_default_font - Set this to true if you don't want to use ImGui's default - font. In this case you need to initialize the font - yourself after simgui_setup() is called. - - bool disable_paste_override - If set to true, sokol_imgui.h will not 'emulate' a Dear Imgui - clipboard paste action on SAPP_EVENTTYPE_CLIPBOARD_PASTED event. - This is mainly a hack/workaround to allow external workarounds - for making copy/paste work on the web platform. In general, - copy/paste support isn't properly fleshed out in sokol_imgui.h yet. - - bool disable_set_mouse_cursor - If true, sokol_imgui.h will not control the mouse cursor type - by calling sapp_set_mouse_cursor(). - - bool disable_windows_resize_from_edges - If true, windows can only be resized from the bottom right corner. - The default is false, meaning windows can be resized from edges. - - bool write_alpha_channel - Set this to true if you want alpha values written to the - framebuffer. By default this behavior is disabled to prevent - undesired behavior on platforms like the web where the canvas is - always alpha-blended with the background. - - simgui_allocator_t allocator - Used to override memory allocation functions. See further below - for details. - - simgui_logger_t logger - A user-provided logging callback. Note that without logging - callback, sokol-imgui will be completely silent! - See the section about ERROR REPORTING AND LOGGING below - for more details. - - --- At the start of a frame, call: - - simgui_new_frame(&(simgui_frame_desc_t){ - .width = ..., - .height = ..., - .delta_time = ..., - .dpi_scale = ... - }); - - 'width' and 'height' are the dimensions of the rendering surface, - passed to ImGui::GetIO().DisplaySize. - - 'delta_time' is the frame duration passed to ImGui::GetIO().DeltaTime. - - 'dpi_scale' is the current DPI scale factor, if this is left zero-initialized, - 1.0f will be used instead. Typical values for dpi_scale are >= 1.0f. - - For example, if you're using sokol_app.h and render to the default framebuffer: - - simgui_new_frame(&(simgui_frame_desc_t){ - .width = sapp_width(), - .height = sapp_height(), - .delta_time = sapp_frame_duration(), - .dpi_scale = sapp_dpi_scale() - }); - - --- at the end of the frame, before the sg_end_pass() where you - want to render the UI, call: - - simgui_render() - - This will first call ImGui::Render(), and then render ImGui's draw list - through sokol_gfx.h - - --- if you're using sokol_app.h, from inside the sokol_app.h event callback, - call: - - bool simgui_handle_event(const sapp_event* ev); - - The return value is the value of ImGui::GetIO().WantCaptureKeyboard, - if this is true, you might want to skip keyboard input handling - in your own event handler. - - If you want to use the ImGui functions for checking if a key is pressed - (e.g. ImGui::IsKeyPressed()) the following helper function to map - an sapp_keycode to an ImGuiKey value may be useful: - - int simgui_map_keycode(sapp_keycode c); - - Note that simgui_map_keycode() can be called outside simgui_setup()/simgui_shutdown(). - - --- finally, on application shutdown, call - - simgui_shutdown() - - - ON USER-PROVIDED IMAGES AND SAMPLERS - ==================================== - To render your own images via ImGui::Image(), first create an simgui_image_t - object from a sokol-gfx image and sampler object. - - // create a sokol-imgui image object which associates an sg_image with an sg_sampler - simgui_image_t simgui_img = simgui_make_image(&(simgui_image_desc_t){ - .image = sg_make_image(...), - .sampler = sg_make_sampler(...), - }); - - // convert the returned image handle into a ImTextureID handle - ImTextureID tex_id = simgui_imtextureid(simgui_img); - - // use the ImTextureID handle in Dear ImGui calls: - ImGui::Image(tex_id, ...); - - simgui_image_t objects are small and cheap (literally just the image and sampler - handle). - - You can omit the sampler handle in the simgui_make_image() call, in this case a - default sampler will be used with nearest-filtering and clamp-to-edge. - - Trying to render with an invalid simgui_image_t handle will render a small 8x8 - white default texture instead. - - To destroy a sokol-imgui image object, call - - simgui_destroy_image(simgui_img); - - But please be aware that the image object needs to be around until simgui_render() is called - in a frame (if this turns out to be too much of a hassle we could introduce some sort - of garbage collection where destroyed simgui_image_t objects are kept around until - the simgui_render() call). - - You can call: - - simgui_image_desc_t desc = simgui_query_image_desc(img) - - ...to get the original desc struct, useful if you need to get the sokol-gfx image - and sampler handle of the simgui_image_t object. - - You can convert an ImTextureID back into an simgui_image_t handle: - - simgui_image_t img = simgui_image_from_imtextureid(tex_id); - - - MEMORY ALLOCATION OVERRIDE - ========================== - You can override the memory allocation functions at initialization time - like this: - - void* my_alloc(size_t size, void* user_data) { - return malloc(size); - } - - void my_free(void* ptr, void* user_data) { - free(ptr); - } - - ... - simgui_setup(&(simgui_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_imgui.h - itself though, not any allocations in Dear ImGui. - - - ERROR REPORTING AND LOGGING - =========================== - To get any logging information at all you need to provide a logging callback in the setup call - the easiest way is to use sokol_log.h: - - #include "sokol_log.h" - - simgui_setup(&(simgui_desc_t){ - .logger.func = slog_func - }); - - To override logging with your own callback, first write a logging function like this: - - void my_log(const char* tag, // e.g. 'simgui' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SIMGUI_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_imgui.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-imgui like this: - - simgui_setup(&(simgui_desc_t){ - .logger = { - .func = my_log, - .user_data = my_user_data, - } - }); - - The provided logging function must be reentrant (e.g. be callable from - different threads). - - If you don't want to provide your own custom logger it is highly recommended to use - the standard logger in sokol_log.h instead, otherwise you won't see any warnings or - errors. - - - IMGUI EVENT HANDLING - ==================== - You can call these functions from your platform's events to handle ImGui events - when SOKOL_IMGUI_NO_SOKOL_APP is defined. - - E.g. mouse position events can be dispatched like this: - - simgui_add_mouse_pos_event(100, 200); - - Key events require a mapping function to convert your platform's key values to ImGuiKey's: - - int map_keycode(int keycode) { - // Your mapping logic here... - } - simgui_add_key_event(map_keycode, keycode, true); - - Take note that modifiers (shift, ctrl, etc.) must be updated manually. - - If sokol_app is being used, ImGui events are handled for you. - - - LICENSE - ======= - - zlib/libpng license - - Copyright (c) 2018 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_IMGUI_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_imgui.h" -#endif -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) && !defined(SOKOL_APP_INCLUDED) -#error "Please include sokol_app.h before sokol_imgui.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_IMGUI_API_DECL) -#define SOKOL_IMGUI_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_IMGUI_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMGUI_IMPL) -#define SOKOL_IMGUI_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_IMGUI_API_DECL __declspec(dllimport) -#else -#define SOKOL_IMGUI_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SIMGUI_INVALID_ID = 0, -}; - -/* - simgui_image_t - - A combined image-sampler pair used to inject custom images and samplers into Dear ImGui. - - Create with simgui_make_image(), and convert to an ImTextureID handle via - simgui_imtextureid(). -*/ -typedef struct simgui_image_t { uint32_t id; } simgui_image_t; - -/* - simgui_image_desc_t - - Descriptor struct for simgui_make_image(). You must provide - at least an sg_image handle. Keeping the sg_sampler handle - zero-initialized will select the builtin default sampler - which uses linear filtering. -*/ -typedef struct simgui_image_desc_t { - sg_image image; - sg_sampler sampler; -} simgui_image_desc_t; - -/* - simgui_log_item - - An enum with a unique item for each log message, warning, error - and validation layer message. -*/ -#define _SIMGUI_LOG_ITEMS \ - _SIMGUI_LOGITEM_XMACRO(OK, "Ok") \ - _SIMGUI_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SIMGUI_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \ - -#define _SIMGUI_LOGITEM_XMACRO(item,msg) SIMGUI_LOGITEM_##item, -typedef enum simgui_log_item_t { - _SIMGUI_LOG_ITEMS -} simgui_log_item_t; -#undef _SIMGUI_LOGITEM_XMACRO - -/* - simgui_allocator_t - - Used in simgui_desc_t to provide custom memory-alloc and -free functions - to sokol_imgui.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct simgui_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} simgui_allocator_t; - -/* - simgui_logger - - Used in simgui_desc_t to provide a logging function. Please be aware - that without logging function, sokol-imgui will be completely - silent, e.g. it will not report errors, warnings and - validation layer messages. For maximum error verbosity, - compile in debug mode (e.g. NDEBUG *not* defined) and install - a logger (for instance the standard logging function from sokol_log.h). -*/ -typedef struct simgui_logger_t { - void (*func)( - const char* tag, // always "simgui" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SIMGUI_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_imgui.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} simgui_logger_t; - -typedef struct simgui_desc_t { - int max_vertices; // default: 65536 - int image_pool_size; // default: 256 - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - const char* ini_filename; - bool no_default_font; - bool disable_paste_override; // if true, don't send Ctrl-V on EVENTTYPE_CLIPBOARD_PASTED - bool disable_set_mouse_cursor; // if true, don't control the mouse cursor type via sapp_set_mouse_cursor() - bool disable_windows_resize_from_edges; // if true, only resize edges from the bottom right corner - bool write_alpha_channel; // if true, alpha values get written into the framebuffer - simgui_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - simgui_logger_t logger; // optional log function override -} simgui_desc_t; - -typedef struct simgui_frame_desc_t { - int width; - int height; - double delta_time; - float dpi_scale; -} simgui_frame_desc_t; - -typedef struct simgui_font_tex_desc_t { - sg_filter min_filter; - sg_filter mag_filter; -} simgui_font_tex_desc_t; - -SOKOL_IMGUI_API_DECL void simgui_setup(const simgui_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_new_frame(const simgui_frame_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_render(void); -SOKOL_IMGUI_API_DECL simgui_image_t simgui_make_image(const simgui_image_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_destroy_image(simgui_image_t img); -SOKOL_IMGUI_API_DECL simgui_image_desc_t simgui_query_image_desc(simgui_image_t img); -SOKOL_IMGUI_API_DECL void* simgui_imtextureid(simgui_image_t img); -SOKOL_IMGUI_API_DECL simgui_image_t simgui_image_from_imtextureid(void* imtextureid); -SOKOL_IMGUI_API_DECL void simgui_add_focus_event(bool focus); -SOKOL_IMGUI_API_DECL void simgui_add_mouse_pos_event(float x, float y); -SOKOL_IMGUI_API_DECL void simgui_add_touch_pos_event(float x, float y); -SOKOL_IMGUI_API_DECL void simgui_add_mouse_button_event(int mouse_button, bool down); -SOKOL_IMGUI_API_DECL void simgui_add_mouse_wheel_event(float wheel_x, float wheel_y); -SOKOL_IMGUI_API_DECL void simgui_add_key_event(int (*map_keycode)(int), int keycode, bool down); -SOKOL_IMGUI_API_DECL void simgui_add_input_character(uint32_t c); -SOKOL_IMGUI_API_DECL void simgui_add_input_characters_utf8(const char* c); -SOKOL_IMGUI_API_DECL void simgui_add_touch_button_event(int mouse_button, bool down); -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) -SOKOL_IMGUI_API_DECL bool simgui_handle_event(const sapp_event* ev); -SOKOL_IMGUI_API_DECL int simgui_map_keycode(sapp_keycode keycode); // returns ImGuiKey_* -#endif -SOKOL_IMGUI_API_DECL void simgui_shutdown(void); -SOKOL_IMGUI_API_DECL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_destroy_fonts_texture(void); - -#ifdef __cplusplus -} // extern "C" - -// reference-based equivalents for C++ -inline void simgui_setup(const simgui_desc_t& desc) { return simgui_setup(&desc); } -inline simgui_image_t simgui_make_image(const simgui_image_desc_t& desc) { return simgui_make_image(&desc); } -inline void simgui_new_frame(const simgui_frame_desc_t& desc) { return simgui_new_frame(&desc); } -inline void simgui_create_fonts_texture(const simgui_font_tex_desc_t& desc) { return simgui_create_fonts_texture(&desc); } - -#endif -#endif /* SOKOL_IMGUI_INCLUDED */ - -//-- IMPLEMENTATION ------------------------------------------------------------ -#ifdef SOKOL_IMGUI_IMPL -#define SOKOL_IMGUI_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use simgui_desc_t.allocator to override memory allocation functions" -#endif - -#if defined(__cplusplus) - #if !defined(IMGUI_VERSION) - #error "Please include imgui.h before the sokol_imgui.h implementation" - #endif -#else - #if !defined(CIMGUI_INCLUDED) - #error "Please include cimgui.h before the sokol_imgui.h implementation" - #endif -#endif - -#include // memset -#include // malloc/free - -#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) -#include -#endif - -#ifndef SOKOL_API_IMPL -#define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#define _SIMGUI_INIT_COOKIE (0xBABEBABE) -#define _SIMGUI_INVALID_SLOT_INDEX (0) -#define _SIMGUI_SLOT_SHIFT (16) -#define _SIMGUI_MAX_POOL_SIZE (1<<_SIMGUI_SLOT_SHIFT) -#define _SIMGUI_SLOT_MASK (_SIMGUI_MAX_POOL_SIZE-1) - -// helper macros and constants -#define _simgui_def(val, def) (((val) == 0) ? (def) : (val)) - -// workaround for missing ImDrawCallback_ResetRenderState in cimgui.h -// see: https://github.com/cimgui/cimgui/issues/261 -#ifndef ImDrawCallback_ResetRenderState -#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) -#endif - -typedef struct { - ImVec2 disp_size; - uint8_t _pad_8[8]; -} _simgui_vs_params_t; - -typedef enum { - _SIMGUI_RESOURCESTATE_INITIAL, - _SIMGUI_RESOURCESTATE_ALLOC, - _SIMGUI_RESOURCESTATE_VALID, - _SIMGUI_RESOURCESTATE_FAILED, - _SIMGUI_RESOURCESTATE_INVALID, - _SIMGUI_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF -} _simgui_resource_state; - -typedef struct { - uint32_t id; - _simgui_resource_state state; -} _simgui_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _simgui_pool_t; - -typedef struct { - _simgui_slot_t slot; - sg_image image; - sg_sampler sampler; - sg_pipeline pip; // this will either be _simgui.def_pip or _simgui.pip_unfilterable -} _simgui_image_t; - -typedef struct { - _simgui_pool_t pool; - _simgui_image_t* items; -} _simgui_image_pool_t; - -typedef struct { - uint32_t init_cookie; - simgui_desc_t desc; - float cur_dpi_scale; - sg_buffer vbuf; - sg_buffer ibuf; - sg_image font_img; - sg_sampler font_smp; - simgui_image_t default_font; - sg_image def_img; // used as default image for user images - sg_sampler def_smp; // used as default sampler for user images - sg_shader def_shd; - sg_pipeline def_pip; - // separate shader and pipeline for unfilterable user images - sg_shader shd_unfilterable; - sg_pipeline pip_unfilterable; - sg_range vertices; - sg_range indices; - bool is_osx; - _simgui_image_pool_t image_pool; -} _simgui_state_t; -static _simgui_state_t _simgui; - -/* - Embedded source code compiled with: - - sokol-shdc -i simgui.glsl -o simgui.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - vec2 disp_size; - }; - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv) * color; - } - @end - - @program simgui vs fs -*/ -#if defined(SOKOL_GLCORE33) -static const char _simgui_vs_source_glsl330[341] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20, - 0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28, - 0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29,0x20,0x2d,0x20, - 0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63, - 0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e, - 0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20, - 0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b, - 0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _simgui_fs_source_glsl330[177] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74, - 0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20, - 0x75,0x76,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -#elif defined(SOKOL_GLES3) -static const char _simgui_vs_source_glsl300es[344] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20, - 0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f, - 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65, - 0x63,0x34,0x28,0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29, - 0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20, - 0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c, - 0x20,0x30,0x2e,0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _simgui_fs_source_glsl300es[250] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _simgui_vs_bytecode_metal_macos[3052] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x7b,0x12,0x23,0x17,0xd9,0x25,0x1c, - 0x1b,0x42,0x42,0x9f,0xbf,0x31,0xd2,0x2c,0x3a,0x55,0x22,0x1d,0x40,0xd8,0xc4,0xf8, - 0x20,0x49,0x60,0x6d,0x3c,0xea,0x4e,0x1c,0x34,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc8,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xaf,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x81,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0x02,0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00, - 0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x16,0x00,0x00,0x00, - 0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3, - 0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c,0x10,0x3c,0x33,0x00, - 0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x91,0x83,0xa4,0x29,0xa2,0x84,0xc9, - 0xaf,0xa4,0xff,0x01,0x22,0x80,0x91,0x50,0x10,0x83,0x08,0x84,0x50,0x8a,0x89,0x90, - 0x22,0x1b,0x08,0x98,0x23,0x00,0x83,0x14,0xc8,0x39,0x02,0x50,0x18,0x44,0x08,0x84, - 0x61,0x04,0x22,0x19,0x01,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0,0x03, - 0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87,0x71, - 0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38,0xd8, - 0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06, - 0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07, - 0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20, - 0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d, - 0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50,0x07, - 0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x6d, - 0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xa0, - 0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x30,0x07,0x72,0x30,0x84,0x39,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0xc8, - 0x02,0x01,0x00,0x00,0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84, - 0x32,0xa0,0x1d,0x01,0x20,0x1d,0x4b,0x68,0x02,0x00,0x00,0x00,0x79,0x18,0x00,0x00, - 0xea,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9, - 0xb9,0xb4,0x37,0xb7,0x21,0x46,0x42,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93, - 0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x24,0x01,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e, - 0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd, - 0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e, - 0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26, - 0x65,0x88,0x80,0x10,0x43,0x8c,0x24,0x48,0x86,0x44,0x60,0xd1,0x54,0x46,0x17,0xc6, - 0x36,0x04,0x41,0x8e,0x24,0x48,0x82,0x44,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6, - 0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36, - 0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d, - 0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65, - 0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd, - 0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95, - 0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x90,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b, - 0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98, - 0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e, - 0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84, - 0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21, - 0x11,0x22,0x21,0x13,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b, - 0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08, - 0x83,0x3c,0x88,0x85,0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee, - 0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d, - 0xda,0x9b,0xdb,0x10,0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85, - 0x64,0x08,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd, - 0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b, - 0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32, - 0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36, - 0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43, - 0xa8,0x44,0x40,0x3c,0xe4,0x4b,0x84,0x24,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90, - 0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x02,0xc4, - 0x43,0xbe,0x24,0x48,0x02,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63, - 0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x24,0x40,0xc0, - 0x00,0x89,0x90,0x0b,0x99,0x90,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66, - 0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e, - 0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39, - 0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3, - 0x37,0x26,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x43,0x94,0x44,0x48,0x86, - 0x44,0x40,0x24,0x64,0x0d,0x18,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5, - 0xc1,0x95,0x7d,0xcd,0xa5,0xe9,0x95,0xf1,0x0a,0x4b,0x93,0x73,0x09,0x93,0x3b,0xfb, - 0xa2,0xcb,0x83,0x2b,0xfb,0x0a,0x63,0x4b,0x3b,0x73,0xfb,0x9a,0x4b,0xd3,0x2b,0x63, - 0x62,0x37,0xf7,0x05,0x17,0x26,0x17,0xd6,0x36,0xc7,0xe1,0x4b,0x46,0x66,0x08,0x19, - 0x24,0x06,0x72,0x06,0x08,0x1a,0x24,0x03,0xf2,0x25,0x42,0x12,0x20,0x69,0x80,0xa8, - 0x01,0xc2,0x06,0x48,0x1b,0x24,0x03,0xe2,0x06,0xc9,0x80,0x44,0xc8,0x1b,0x20,0x13, - 0x02,0x07,0x43,0x10,0x44,0x0c,0x10,0x32,0x40,0xcc,0x00,0x89,0x83,0x21,0xc6,0x01, - 0x20,0x1d,0x22,0x07,0x7c,0xde,0xda,0xdc,0xd2,0xe0,0xde,0xe8,0xca,0xdc,0xe8,0x40, - 0xc6,0xd0,0xc2,0xe4,0xf8,0x4c,0xa5,0xb5,0xc1,0xb1,0x95,0x81,0x0c,0xad,0xac,0x80, - 0x50,0x09,0x05,0x05,0x0d,0x11,0x90,0x3a,0x18,0x62,0x20,0x74,0x80,0xd8,0xc1,0x72, - 0x0c,0x31,0x90,0x3b,0x40,0xee,0x60,0x39,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e, - 0x6e,0xd0,0x0e,0xef,0x40,0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1, - 0x70,0x0e,0xf3,0x30,0x45,0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b, - 0xa4,0x03,0x39,0x94,0x83,0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8, - 0x83,0x1b,0xd8,0x43,0x39,0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18, - 0x41,0x85,0x43,0x3a,0xc8,0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38, - 0x9c,0x43,0x39,0xfc,0x82,0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c, - 0x09,0x90,0x11,0x53,0x38,0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43, - 0x3a,0xb0,0x43,0x39,0xfc,0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c, - 0x4c,0x19,0x14,0xc6,0x19,0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8, - 0x03,0x3d,0x94,0x03,0x3e,0x4c,0x09,0xe6,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00, - 0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88, - 0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6, - 0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce, - 0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8, - 0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48, - 0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11, - 0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e, - 0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89, - 0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b, - 0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37, - 0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78, - 0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81, - 0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1, - 0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c, - 0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39, - 0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc, - 0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58, - 0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87, - 0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f, - 0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e, - 0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66, - 0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0, - 0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e, - 0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc, - 0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3, - 0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07, - 0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e, - 0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e, - 0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d, - 0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00, - 0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00, - 0x61,0x20,0x00,0x00,0x23,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00, - 0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10,0x42,0xf0,0x3c,0x94, - 0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82,0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30, - 0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08,0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73, - 0x10,0xd7,0x65,0x55,0x34,0x33,0x00,0x04,0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46, - 0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00,0xe3,0x0d,0x4c,0x64,0x51,0x40,0x2c,0x0a, - 0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9,0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c, - 0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41,0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40, - 0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5b,0x86,0x20,0xc0,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_fs_bytecode_metal_macos[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xa1,0xce,0x6b,0xd1,0x1f,0x32,0x9e, - 0x8d,0x8d,0x1c,0xcc,0x19,0xcb,0xd3,0xb6,0x21,0x99,0x0b,0xb6,0x46,0x8b,0x87,0x98, - 0x8e,0x2d,0xb5,0x98,0x92,0x0a,0x81,0x7d,0xf3,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x0c,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x80,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81,0x00,0x00,0x00, - 0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70, - 0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42, - 0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45, - 0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84, - 0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0, - 0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32, - 0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe, - 0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d, - 0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c, - 0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e, - 0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34, - 0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72, - 0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28, - 0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91, - 0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1, - 0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13, - 0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3, - 0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46, - 0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d, - 0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8, - 0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba,0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60, - 0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0, - 0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b, - 0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1, - 0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e, - 0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1, - 0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c, - 0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61,0x07,0x76,0xb0,0x87, - 0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0x14,0x23,0x96,0x70, - 0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98, - 0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70,0x03,0x76,0x08,0x07,0x77,0x38,0x87, - 0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77, - 0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74,0x90,0x07,0x37,0x18,0x87,0x77,0x68, - 0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78,0x07,0x78,0xa0,0x87,0x74,0x78,0x07, - 0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98,0x70,0x48,0x07,0x79,0x70,0x03,0x73, - 0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77,0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00, - 0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00, - 0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4,0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00, - 0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91,0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6, - 0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_vs_bytecode_metal_ios[3052] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x69,0x97,0x6b,0xac,0xd8,0xa2,0x51, - 0x33,0x7c,0x5f,0x96,0xb2,0xb1,0x06,0x06,0x7c,0xbb,0x5f,0x88,0xa0,0xeb,0x9f,0xea, - 0x6e,0x6b,0x70,0xa9,0x6e,0xef,0xe6,0xa4,0xea,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc0,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xad,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x20,0x02,0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00, - 0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00, - 0x16,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84, - 0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c, - 0x10,0x3c,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x91,0x83,0xa4, - 0x29,0xa2,0x84,0xc9,0xaf,0xa4,0xff,0x01,0x22,0x80,0x91,0x50,0x10,0x83,0x08,0x84, - 0x50,0x8a,0x89,0x90,0x22,0x1b,0x08,0x98,0x23,0x00,0x83,0x14,0xc8,0x39,0x02,0x50, - 0x18,0x44,0x08,0x84,0x61,0x04,0x22,0x19,0x01,0x00,0x00,0x00,0x13,0xa8,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e, - 0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0, - 0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0, - 0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6, - 0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07, - 0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6, - 0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07, - 0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0, - 0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20, - 0x07,0x43,0x98,0x03,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00,0x00, - 0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47, - 0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84,0x32,0xa0,0x1d,0x01, - 0x20,0x1d,0x4b,0x80,0x04,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xe9,0x00,0x00,0x00, - 0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7, - 0x21,0x46,0x42,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3, - 0x2b,0x1b,0x62,0x24,0x01,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4, - 0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac, - 0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10, - 0x43,0x8c,0x24,0x48,0x86,0x44,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e, - 0x24,0x48,0x82,0x44,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56, - 0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56, - 0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65, - 0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c, - 0x65,0x43,0x04,0x64,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1, - 0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95, - 0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x51,0x58, - 0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d, - 0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72, - 0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc, - 0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85, - 0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21,0x11,0x22,0x21,0x13,0x42, - 0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6, - 0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85,0x44, - 0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed, - 0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x05, - 0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85,0x64,0x08,0x47,0x28,0x2c, - 0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52, - 0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59, - 0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0, - 0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf, - 0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x44,0x40,0x3c,0xe4, - 0x4b,0x84,0x24,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90,0x30,0x60,0x42,0x57,0x86, - 0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x02,0xc4,0x43,0xbe,0x24,0x48,0x02, - 0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x24,0x40,0xc0,0x00,0x89,0x90,0x0b,0x99, - 0x90,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c, - 0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58, - 0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba, - 0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x26,0x64,0x69,0x73, - 0x70,0x5f,0x73,0x69,0x7a,0x65,0x43,0x94,0x44,0x48,0x86,0x44,0x40,0x24,0x64,0x0d, - 0x18,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0xcd,0xa5, - 0xe9,0x95,0xf1,0x0a,0x4b,0x93,0x73,0x09,0x93,0x3b,0xfb,0xa2,0xcb,0x83,0x2b,0xfb, - 0x0a,0x63,0x4b,0x3b,0x73,0xfb,0x9a,0x4b,0xd3,0x2b,0x63,0x62,0x37,0xf7,0x05,0x17, - 0x26,0x17,0xd6,0x36,0xc7,0xe1,0x4b,0x46,0x66,0x08,0x19,0x24,0x06,0x72,0x06,0x08, - 0x1a,0x24,0x03,0xf2,0x25,0x42,0x12,0x20,0x69,0x80,0xa8,0x01,0xc2,0x06,0x48,0x1b, - 0x24,0x03,0xe2,0x06,0xc9,0x80,0x44,0xc8,0x1b,0x20,0x13,0x02,0x07,0x43,0x10,0x44, - 0x0c,0x10,0x32,0x40,0xcc,0x00,0x89,0x83,0x21,0xc6,0x01,0x20,0x1d,0x22,0x07,0x7c, - 0xde,0xda,0xdc,0xd2,0xe0,0xde,0xe8,0xca,0xdc,0xe8,0x40,0xc6,0xd0,0xc2,0xe4,0xf8, - 0x4c,0xa5,0xb5,0xc1,0xb1,0x95,0x81,0x0c,0xad,0xac,0x80,0x50,0x09,0x05,0x05,0x0d, - 0x11,0x90,0x3a,0x18,0x62,0x20,0x74,0x80,0xd8,0xc1,0x72,0x0c,0x31,0x90,0x3b,0x40, - 0xee,0x60,0x39,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40, - 0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45, - 0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xa4,0x03,0x39,0x94,0x83, - 0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39, - 0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8, - 0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38,0x9c,0x43,0x39,0xfc,0x82, - 0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c,0x09,0x90,0x11,0x53,0x38, - 0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc, - 0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19, - 0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e, - 0x4c,0x09,0xe6,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c, - 0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07, - 0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e, - 0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43, - 0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c, - 0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76, - 0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e, - 0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8, - 0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4, - 0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68, - 0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07, - 0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71, - 0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5, - 0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4, - 0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90, - 0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43, - 0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b, - 0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78, - 0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2, - 0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20, - 0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0, - 0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83, - 0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07, - 0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61, - 0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d, - 0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39, - 0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79, - 0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3, - 0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4, - 0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8, - 0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83, - 0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00, - 0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x23,0x00,0x00,0x00, - 0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40, - 0x60,0x1c,0x73,0x10,0x42,0xf0,0x3c,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82, - 0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30,0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08, - 0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73,0x10,0xd7,0x65,0x55,0x34,0x33,0x00,0x04, - 0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46,0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00, - 0xe3,0x0d,0x4c,0x64,0x51,0x40,0x2c,0x0a,0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9, - 0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c,0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41, - 0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40,0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x5b,0x86,0x20,0xc0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_fs_bytecode_metal_ios[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf0,0xa4,0xb3,0x95,0x4b,0xab,0x64, - 0x94,0xe7,0xa9,0x8a,0x69,0x27,0x6d,0x28,0x77,0x84,0x8d,0x3f,0xaf,0x7d,0x3c,0x39, - 0x31,0xc4,0xcb,0x53,0x6d,0xc0,0x0d,0xdf,0x08,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x04,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x7e,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87, - 0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9, - 0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07, - 0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20, - 0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72, - 0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07, - 0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10, - 0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07, - 0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98, - 0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03,0x04,0x80,0x00,0x00, - 0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98, - 0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02, - 0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00,0x00,0x79,0x18,0x00, - 0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d, - 0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c, - 0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2, - 0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d, - 0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9, - 0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc, - 0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb, - 0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e, - 0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34, - 0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb, - 0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb, - 0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6, - 0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1, - 0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46, - 0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e, - 0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f, - 0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba, - 0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f, - 0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e, - 0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21, - 0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f, - 0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5, - 0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1, - 0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1, - 0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07, - 0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79, - 0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70, - 0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87, - 0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74, - 0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78, - 0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98, - 0x70,0x48,0x07,0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77, - 0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4, - 0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00,0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91, - 0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6,0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const char _simgui_vs_source_metal_sim[672] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, - 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, - 0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, - 0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, - 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62, - 0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x5b, - 0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32, - 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74, - 0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61, - 0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x32, - 0x32,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, - 0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f, - 0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x28,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73, - 0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x5f,0x32,0x32,0x2e,0x64,0x69,0x73,0x70, - 0x5f,0x73,0x69,0x7a,0x65,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28, - 0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x32, - 0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76, - 0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -static const char _simgui_fs_source_metal_sim[436] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _simgui_vs_bytecode_hlsl4[892] = { - 0x44,0x58,0x42,0x43,0x0d,0xbd,0x9e,0x9e,0x7d,0xc0,0x2b,0x54,0x88,0xf9,0xca,0x89, - 0x32,0xe4,0x0c,0x59,0x01,0x00,0x00,0x00,0x7c,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x60,0x01,0x00,0x00,0xd0,0x01,0x00,0x00, - 0x00,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xc0,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x98,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x88,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x32,0x32,0x5f,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a, - 0x65,0x00,0xab,0xab,0x01,0x00,0x03,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52, - 0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e, - 0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x28,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x4a,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00, - 0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x08, - 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x80,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a, - 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x0a,0x32,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x08, - 0xc2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x80,0x3f,0x3e,0x00,0x00,0x01, - 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0x3a,0xa7,0x41,0x21,0xb4,0x2d,0xa7,0x6e,0xfe,0x31,0xb0,0xe0, - 0x14,0xe0,0xdf,0x5a,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -}; -#elif defined(SOKOL_WGPU) -static const char _simgui_vs_source_wgsl[1083] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28, - 0x30,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76, - 0x61,0x72,0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x32,0x32, - 0x20,0x3a,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x39, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x5f,0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x35,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x78,0x5f,0x32,0x32, - 0x2e,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x33,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d, - 0x20,0x28,0x28,0x28,0x78,0x5f,0x31,0x39,0x20,0x2f,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x30,0x2e,0x35,0x66,0x2c,0x20,0x30, - 0x2e,0x35,0x66,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x32,0x2e, - 0x30,0x66,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63, - 0x34,0x66,0x28,0x78,0x5f,0x33,0x33,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x33,0x33,0x2e, - 0x79,0x2c,0x20,0x30,0x2e,0x35,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a, - 0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x33,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x34,0x33,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x34,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x37,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75, - 0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61, - 0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c, - 0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78, - 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65, - 0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _simgui_fs_source_wgsl[630] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x34,0x20,0x2a,0x20,0x78,0x5f, - 0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75, - 0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f, - 0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66, - 0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28, - 0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29, - 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _simgui_vs_source_dummy = ""; -static const char* _simgui_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) -static void _simgui_set_clipboard(void* user_data, const char* text) { - (void)user_data; - sapp_set_clipboard_string(text); -} - -static const char* _simgui_get_clipboard(void* user_data) { - (void)user_data; - return sapp_get_clipboard_string(); -} -#endif - -#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) -EM_JS(int, simgui_js_is_osx, (void), { - if (navigator.userAgent.includes('Macintosh')) { - return 1; - } else { - return 0; - } -}); -#endif - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SIMGUI_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _simgui_log_messages[] = { - _SIMGUI_LOG_ITEMS -}; -#undef _SIMGUI_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SIMGUI_PANIC(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 0, 0, __LINE__) -#define _SIMGUI_ERROR(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 1, 0, __LINE__) -#define _SIMGUI_WARN(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 2, 0, __LINE__) -#define _SIMGUI_INFO(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 3, 0, __LINE__) -#define _SIMGUI_LOGMSG(code,msg) _simgui_log(SIMGUI_LOGITEM_ ##code, 3, msg, __LINE__) - -static void _simgui_log(simgui_log_item_t log_item, uint32_t log_level, const char* msg, uint32_t line_nr) { - if (_simgui.desc.logger.func) { - const char* filename = 0; - #if defined(SOKOL_DEBUG) - filename = __FILE__; - if (0 == msg) { - msg = _simgui_log_messages[log_item]; - } - #endif - _simgui.desc.logger.func("simgui", log_level, log_item, msg, line_nr, filename, _simgui.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _simgui_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _simgui_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_simgui.desc.allocator.alloc_fn) { - ptr = _simgui.desc.allocator.alloc_fn(size, _simgui.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SIMGUI_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _simgui_malloc_clear(size_t size) { - void* ptr = _simgui_malloc(size); - _simgui_clear(ptr, size); - return ptr; -} - -static void _simgui_free(void* ptr) { - if (_simgui.desc.allocator.free_fn) { - _simgui.desc.allocator.free_fn(ptr, _simgui.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _simgui_init_pool(_simgui_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _simgui_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _simgui_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _simgui_discard_pool(_simgui_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _simgui_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _simgui_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _simgui_pool_alloc_index(_simgui_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SIMGUI_INVALID_SLOT_INDEX; - } -} - -static void _simgui_pool_free_index(_simgui_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* initialize a pool slot: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the handle id -*/ -static uint32_t _simgui_slot_init(_simgui_pool_t* pool, _simgui_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == _SIMGUI_RESOURCESTATE_INITIAL) && (slot->id == SIMGUI_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SIMGUI_SLOT_SHIFT)|(slot_index & _SIMGUI_SLOT_MASK); - slot->state = _SIMGUI_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _simgui_slot_index(uint32_t id) { - int slot_index = (int) (id & _SIMGUI_SLOT_MASK); - SOKOL_ASSERT(_SIMGUI_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -static void _simgui_init_item_pool(_simgui_pool_t* pool, int pool_size, void** items_ptr, size_t item_size_bytes) { - // NOTE: the pools will have an additional item, since slot 0 is reserved - SOKOL_ASSERT(pool && (pool->size == 0)); - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SIMGUI_MAX_POOL_SIZE)); - SOKOL_ASSERT(items_ptr && (*items_ptr == 0)); - SOKOL_ASSERT(item_size_bytes > 0); - _simgui_init_pool(pool, pool_size); - const size_t pool_size_bytes = item_size_bytes * (size_t)pool->size; - *items_ptr = _simgui_malloc_clear(pool_size_bytes); -} - -static void _simgui_discard_item_pool(_simgui_pool_t* pool, void** items_ptr) { - SOKOL_ASSERT(pool && (pool->size != 0)); - SOKOL_ASSERT(items_ptr && (*items_ptr != 0)); - _simgui_free(*items_ptr); *items_ptr = 0; - _simgui_discard_pool(pool); -} - -static void _simgui_setup_image_pool(int pool_size) { - _simgui_image_pool_t* p = &_simgui.image_pool; - _simgui_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_simgui_image_t)); -} - -static void _simgui_discard_image_pool(void) { - _simgui_image_pool_t* p = &_simgui.image_pool; - _simgui_discard_item_pool(&p->pool, (void**)&p->items); -} - -static simgui_image_t _simgui_make_image_handle(uint32_t id) { - simgui_image_t handle = { id }; - return handle; -} - -static _simgui_image_t* _simgui_image_at(uint32_t id) { - SOKOL_ASSERT(SIMGUI_INVALID_ID != id); - const _simgui_image_pool_t* p = &_simgui.image_pool; - int slot_index = _simgui_slot_index(id); - SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _simgui_image_t* _simgui_lookup_image(uint32_t id) { - if (SIMGUI_INVALID_ID != id) { - _simgui_image_t* img = _simgui_image_at(id); - if (img->slot.id == id) { - return img; - } - } - return 0; -} - -static simgui_image_t _simgui_alloc_image(void) { - _simgui_image_pool_t* p = &_simgui.image_pool; - int slot_index = _simgui_pool_alloc_index(&p->pool); - if (_SIMGUI_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _simgui_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _simgui_make_image_handle(id); - } else { - // pool exhausted - return _simgui_make_image_handle(SIMGUI_INVALID_ID); - } -} - -static _simgui_resource_state _simgui_init_image(_simgui_image_t* img, const simgui_image_desc_t* desc) { - SOKOL_ASSERT(img && (img->slot.state == _SIMGUI_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - SOKOL_ASSERT(_simgui.def_pip.id != SIMGUI_INVALID_ID); - SOKOL_ASSERT(_simgui.pip_unfilterable.id != SIMGUI_INVALID_ID); - img->image = desc->image; - img->sampler = desc->sampler; - if (sg_query_pixelformat(sg_query_image_desc(desc->image).pixel_format).filter) { - img->pip = _simgui.def_pip; - } else { - img->pip = _simgui.pip_unfilterable; - } - return _SIMGUI_RESOURCESTATE_VALID; -} - -static void _simgui_deinit_image(_simgui_image_t* img) { - SOKOL_ASSERT(img); - img->image.id = SIMGUI_INVALID_ID; - img->sampler.id = SIMGUI_INVALID_ID; - img->pip.id = SIMGUI_INVALID_ID; -} - -static void _simgui_destroy_image(simgui_image_t img_id) { - _simgui_image_t* img = _simgui_lookup_image(img_id.id); - if (img) { - _simgui_deinit_image(img); - _simgui_image_pool_t* p = &_simgui.image_pool; - _simgui_clear(img, sizeof(_simgui_image_t)); - _simgui_pool_free_index(&p->pool, _simgui_slot_index(img_id.id)); - } -} - -static void _simgui_destroy_all_images(void) { - _simgui_image_pool_t* p = &_simgui.image_pool; - for (int i = 0; i < p->pool.size; i++) { - _simgui_image_t* img = &p->items[i]; - _simgui_destroy_image(_simgui_make_image_handle(img->slot.id)); - } -} - -static simgui_image_desc_t _simgui_image_desc_defaults(const simgui_image_desc_t* desc) { - SOKOL_ASSERT(desc); - simgui_image_desc_t res = *desc; - res.image.id = _simgui_def(res.image.id, _simgui.def_img.id); - res.sampler.id = _simgui_def(res.sampler.id, _simgui.def_smp.id); - return res; -} - -static bool _simgui_is_osx(void) { - #if defined(SOKOL_DUMMY_BACKEND) - return false; - #elif defined(__EMSCRIPTEN__) - return simgui_js_is_osx(); - #elif defined(__APPLE__) - return true; - #else - return false; - #endif -} - -static simgui_desc_t _simgui_desc_defaults(const simgui_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - simgui_desc_t res = *desc; - res.max_vertices = _simgui_def(res.max_vertices, 65536); - res.image_pool_size = _simgui_def(res.image_pool_size, 256); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) { - SOKOL_ASSERT(desc); - _simgui_clear(&_simgui, sizeof(_simgui)); - _simgui.init_cookie = _SIMGUI_INIT_COOKIE; - _simgui.desc = _simgui_desc_defaults(desc); - _simgui.cur_dpi_scale = 1.0f; - #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) - _simgui.is_osx = _simgui_is_osx(); - #endif - // can keep color_format, depth_format and sample_count as is, - // since sokol_gfx.h will do its own default-value handling - - // setup image pool - _simgui_setup_image_pool(_simgui.desc.image_pool_size); - - // allocate an intermediate vertex- and index-buffer - SOKOL_ASSERT(_simgui.desc.max_vertices > 0); - _simgui.vertices.size = (size_t)_simgui.desc.max_vertices * sizeof(ImDrawVert); - _simgui.vertices.ptr = _simgui_malloc(_simgui.vertices.size); - _simgui.indices.size = (size_t)_simgui.desc.max_vertices * 3 * sizeof(ImDrawIdx); - _simgui.indices.ptr = _simgui_malloc(_simgui.indices.size); - - // initialize Dear ImGui - #if defined(__cplusplus) - ImGui::CreateContext(); - ImGui::StyleColorsDark(); - ImGuiIO* io = &ImGui::GetIO(); - if (!_simgui.desc.no_default_font) { - io->Fonts->AddFontDefault(); - } - #else - igCreateContext(NULL); - igStyleColorsDark(igGetStyle()); - ImGuiIO* io = igGetIO(); - if (!_simgui.desc.no_default_font) { - ImFontAtlas_AddFontDefault(io->Fonts, NULL); - } - #endif - io->IniFilename = _simgui.desc.ini_filename; - io->ConfigMacOSXBehaviors = _simgui_is_osx(); - io->BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; - #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) - if (!_simgui.desc.disable_set_mouse_cursor) { - io->BackendFlags |= ImGuiBackendFlags_HasMouseCursors; - } - io->SetClipboardTextFn = _simgui_set_clipboard; - io->GetClipboardTextFn = _simgui_get_clipboard; - #endif - io->ConfigWindowsResizeFromEdges = !_simgui.desc.disable_windows_resize_from_edges; - - // create sokol-gfx resources - sg_push_debug_group("sokol-imgui"); - - // shader object for using the embedded shader source (or bytecode) - sg_shader_desc shd_desc; - _simgui_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; - ub->size = sizeof(_simgui_vs_params_t); - ub->uniforms[0].name = "vs_params"; - ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - ub->uniforms[0].array_count = 1; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.label = "sokol-imgui-shader"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _simgui_vs_source_glsl330; - shd_desc.fs.source = _simgui_fs_source_glsl330; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _simgui_vs_source_glsl300es; - shd_desc.fs.source = _simgui_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = _simgui_vs_source_metal_sim; - shd_desc.fs.source = _simgui_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _simgui_vs_source_wgsl; - shd_desc.fs.source = _simgui_fs_source_wgsl; - #else - shd_desc.vs.source = _simgui_vs_source_dummy; - shd_desc.fs.source = _simgui_fs_source_dummy; - #endif - _simgui.def_shd = sg_make_shader(&shd_desc); - - // pipeline object for imgui rendering - sg_pipeline_desc pip_desc; - _simgui_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert); - { - sg_vertex_attr_state* attr = &pip_desc.layout.attrs[0]; - attr->offset = offsetof(ImDrawVert, pos); - attr->format = SG_VERTEXFORMAT_FLOAT2; - } - { - sg_vertex_attr_state* attr = &pip_desc.layout.attrs[1]; - attr->offset = offsetof(ImDrawVert, uv); - attr->format = SG_VERTEXFORMAT_FLOAT2; - } - { - sg_vertex_attr_state* attr = &pip_desc.layout.attrs[2]; - attr->offset = offsetof(ImDrawVert, col); - attr->format = SG_VERTEXFORMAT_UBYTE4N; - } - pip_desc.shader = _simgui.def_shd; - pip_desc.index_type = SG_INDEXTYPE_UINT16; - pip_desc.sample_count = _simgui.desc.sample_count; - pip_desc.depth.pixel_format = _simgui.desc.depth_format; - pip_desc.colors[0].pixel_format = _simgui.desc.color_format; - pip_desc.colors[0].write_mask = _simgui.desc.write_alpha_channel ? SG_COLORMASK_RGBA : SG_COLORMASK_RGB; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - if (_simgui.desc.write_alpha_channel) { - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE; - } - pip_desc.label = "sokol-imgui-pipeline"; - _simgui.def_pip = sg_make_pipeline(&pip_desc); - - // create a unfilterable/nonfiltering variants of the shader and pipeline - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_NONFILTERING; - shd_desc.label = "sokol-imgui-shader-unfilterable"; - _simgui.shd_unfilterable = sg_make_shader(&shd_desc); - pip_desc.shader = _simgui.shd_unfilterable; - pip_desc.label = "sokol-imgui-pipeline-unfilterable"; - _simgui.pip_unfilterable = sg_make_pipeline(&pip_desc); - - // NOTE: since we're in C++ mode here we can't use C99 designated init - sg_buffer_desc vb_desc; - _simgui_clear(&vb_desc, sizeof(vb_desc)); - vb_desc.usage = SG_USAGE_STREAM; - vb_desc.size = _simgui.vertices.size; - vb_desc.label = "sokol-imgui-vertices"; - _simgui.vbuf = sg_make_buffer(&vb_desc); - - sg_buffer_desc ib_desc; - _simgui_clear(&ib_desc, sizeof(ib_desc)); - ib_desc.type = SG_BUFFERTYPE_INDEXBUFFER; - ib_desc.usage = SG_USAGE_STREAM; - ib_desc.size = _simgui.indices.size; - ib_desc.label = "sokol-imgui-indices"; - _simgui.ibuf = sg_make_buffer(&ib_desc); - - // a default user-image sampler - sg_sampler_desc def_sampler_desc; - _simgui_clear(&def_sampler_desc, sizeof(def_sampler_desc)); - def_sampler_desc.min_filter = SG_FILTER_NEAREST; - def_sampler_desc.mag_filter = SG_FILTER_NEAREST; - def_sampler_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - def_sampler_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - def_sampler_desc.label = "sokol-imgui-default-sampler"; - _simgui.def_smp = sg_make_sampler(&def_sampler_desc); - - // a default user image - static uint32_t def_pixels[64]; - memset(def_pixels, 0xFF, sizeof(def_pixels)); - sg_image_desc def_image_desc; - _simgui_clear(&def_image_desc, sizeof(def_image_desc)); - def_image_desc.width = 8; - def_image_desc.height = 8; - def_image_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - def_image_desc.data.subimage[0][0].ptr = def_pixels; - def_image_desc.data.subimage[0][0].size = sizeof(def_pixels); - def_image_desc.label = "sokol-imgui-default-image"; - _simgui.def_img = sg_make_image(&def_image_desc); - - // default font texture - if (!_simgui.desc.no_default_font) { - simgui_font_tex_desc_t simgui_font_smp_desc; - _simgui_clear(&simgui_font_smp_desc, sizeof(simgui_font_smp_desc)); - simgui_create_fonts_texture(&simgui_font_smp_desc); - } - - sg_pop_debug_group(); -} - -SOKOL_API_IMPL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* desc) { - SOKOL_ASSERT(desc); - - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #else - ImGuiIO* io = igGetIO(); - #endif - - // a default font sampler - sg_sampler_desc font_smp_desc; - _simgui_clear(&font_smp_desc, sizeof(font_smp_desc)); - font_smp_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - font_smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - font_smp_desc.min_filter = desc->min_filter; - font_smp_desc.mag_filter = desc->mag_filter; - font_smp_desc.mipmap_filter = SG_FILTER_NONE; - font_smp_desc.label = "sokol-imgui-font-sampler"; - _simgui.font_smp = sg_make_sampler(&font_smp_desc); - - unsigned char* font_pixels; - int font_width, font_height; - #if defined(__cplusplus) - io->Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height); - #else - int bytes_per_pixel; - ImFontAtlas_GetTexDataAsRGBA32(io->Fonts, &font_pixels, &font_width, &font_height, &bytes_per_pixel); - #endif - sg_image_desc font_img_desc; - _simgui_clear(&font_img_desc, sizeof(font_img_desc)); - font_img_desc.width = font_width; - font_img_desc.height = font_height; - font_img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - font_img_desc.data.subimage[0][0].ptr = font_pixels; - font_img_desc.data.subimage[0][0].size = (size_t)(font_width * font_height) * sizeof(uint32_t); - font_img_desc.label = "sokol-imgui-font-image"; - _simgui.font_img = sg_make_image(&font_img_desc); - - simgui_image_desc_t img_desc; - _simgui_clear(&img_desc, sizeof(img_desc)); - img_desc.image = _simgui.font_img; - img_desc.sampler = _simgui.font_smp; - _simgui.default_font = simgui_make_image(&img_desc); - io->Fonts->TexID = simgui_imtextureid(_simgui.default_font); -} - -SOKOL_API_IMPL void simgui_destroy_fonts_texture(void) { - // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID - sg_destroy_sampler(_simgui.font_smp); - sg_destroy_image(_simgui.font_img); - simgui_destroy_image(_simgui.default_font); -} - -SOKOL_API_IMPL void simgui_shutdown(void) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGui::DestroyContext(); - #else - igDestroyContext(0); - #endif - // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID - sg_destroy_pipeline(_simgui.pip_unfilterable); - sg_destroy_shader(_simgui.shd_unfilterable); - sg_destroy_pipeline(_simgui.def_pip); - sg_destroy_shader(_simgui.def_shd); - sg_destroy_sampler(_simgui.font_smp); - sg_destroy_image(_simgui.font_img); - sg_destroy_sampler(_simgui.def_smp); - sg_destroy_image(_simgui.def_img); - sg_destroy_buffer(_simgui.ibuf); - sg_destroy_buffer(_simgui.vbuf); - sg_pop_debug_group(); - sg_push_debug_group("sokol-imgui"); - _simgui_destroy_all_images(); - _simgui_discard_image_pool(); - SOKOL_ASSERT(_simgui.vertices.ptr); - _simgui_free((void*)_simgui.vertices.ptr); - SOKOL_ASSERT(_simgui.indices.ptr); - _simgui_free((void*)_simgui.indices.ptr); - _simgui.init_cookie = 0; -} - -SOKOL_API_IMPL simgui_image_t simgui_make_image(const simgui_image_desc_t* desc) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - SOKOL_ASSERT(desc); - const simgui_image_desc_t desc_def = _simgui_image_desc_defaults(desc); - simgui_image_t img_id = _simgui_alloc_image(); - _simgui_image_t* img = _simgui_lookup_image(img_id.id); - if (img) { - img->slot.state = _simgui_init_image(img, &desc_def); - SOKOL_ASSERT((img->slot.state == _SIMGUI_RESOURCESTATE_VALID) || (img->slot.state == _SIMGUI_RESOURCESTATE_FAILED)); - } else { - _SIMGUI_ERROR(IMAGE_POOL_EXHAUSTED); - } - return img_id; -} - -SOKOL_API_IMPL void simgui_destroy_image(simgui_image_t img_id) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - _simgui_destroy_image(img_id); -} - -SOKOL_API_IMPL simgui_image_desc_t simgui_query_image_desc(simgui_image_t img_id) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - _simgui_image_t* img = _simgui_lookup_image(img_id.id); - simgui_image_desc_t desc; - _simgui_clear(&desc, sizeof(desc)); - if (img) { - desc.image = img->image; - desc.sampler = img->sampler; - } - return desc; -} - -SOKOL_API_IMPL void* simgui_imtextureid(simgui_image_t img) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - return (void*)(uintptr_t)img.id; -} - -SOKOL_API_IMPL simgui_image_t simgui_image_from_imtextureid(void* imtextureid) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - simgui_image_t img = { (uint32_t)(uintptr_t) imtextureid }; - return img; -} - -SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->width > 0); - SOKOL_ASSERT(desc->height > 0); - _simgui.cur_dpi_scale = _simgui_def(desc->dpi_scale, 1.0f); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #else - ImGuiIO* io = igGetIO(); - #endif - io->DisplaySize.x = ((float)desc->width) / _simgui.cur_dpi_scale; - io->DisplaySize.y = ((float)desc->height) / _simgui.cur_dpi_scale; - io->DeltaTime = (float)desc->delta_time; - #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) - if (io->WantTextInput && !sapp_keyboard_shown()) { - sapp_show_keyboard(true); - } - if (!io->WantTextInput && sapp_keyboard_shown()) { - sapp_show_keyboard(false); - } - if (!_simgui.desc.disable_set_mouse_cursor) { - #if defined(__cplusplus) - ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - #else - ImGuiMouseCursor imgui_cursor = igGetMouseCursor(); - #endif - sapp_mouse_cursor cursor = sapp_get_mouse_cursor(); - switch (imgui_cursor) { - case ImGuiMouseCursor_Arrow: cursor = SAPP_MOUSECURSOR_ARROW; break; - case ImGuiMouseCursor_TextInput: cursor = SAPP_MOUSECURSOR_IBEAM; break; - case ImGuiMouseCursor_ResizeAll: cursor = SAPP_MOUSECURSOR_RESIZE_ALL; break; - case ImGuiMouseCursor_ResizeNS: cursor = SAPP_MOUSECURSOR_RESIZE_NS; break; - case ImGuiMouseCursor_ResizeEW: cursor = SAPP_MOUSECURSOR_RESIZE_EW; break; - case ImGuiMouseCursor_ResizeNESW: cursor = SAPP_MOUSECURSOR_RESIZE_NESW; break; - case ImGuiMouseCursor_ResizeNWSE: cursor = SAPP_MOUSECURSOR_RESIZE_NWSE; break; - case ImGuiMouseCursor_Hand: cursor = SAPP_MOUSECURSOR_POINTING_HAND; break; - case ImGuiMouseCursor_NotAllowed: cursor = SAPP_MOUSECURSOR_NOT_ALLOWED; break; - default: break; - } - sapp_set_mouse_cursor(cursor); - } - #endif - #if defined(__cplusplus) - ImGui::NewFrame(); - #else - igNewFrame(); - #endif -} - -static const _simgui_image_t* _simgui_bind_image_sampler(sg_bindings* bindings, ImTextureID tex_id) { - const _simgui_image_t* img = _simgui_lookup_image((uint32_t)(uintptr_t)tex_id); - if (img) { - bindings->fs.images[0] = img->image; - bindings->fs.samplers[0] = img->sampler; - } else { - bindings->fs.images[0] = _simgui.def_img; - bindings->fs.samplers[0] = _simgui.def_smp; - } - return img; -} - -static ImDrawList* _simgui_imdrawlist_at(ImDrawData* draw_data, int cl_index) { - #if defined(__cplusplus) - return draw_data->CmdLists[cl_index]; - #else - return draw_data->CmdLists.Data[cl_index]; - #endif -} - -SOKOL_API_IMPL void simgui_render(void) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGui::Render(); - ImDrawData* draw_data = ImGui::GetDrawData(); - ImGuiIO* io = &ImGui::GetIO(); - #else - igRender(); - ImDrawData* draw_data = igGetDrawData(); - ImGuiIO* io = igGetIO(); - #endif - if (0 == draw_data) { - return; - } - if (draw_data->CmdListsCount == 0) { - return; - } - /* copy vertices and indices into an intermediate buffer so that - they can be updated with a single sg_update_buffer() call each - (sg_append_buffer() has performance problems on some GL platforms), - also keep track of valid number of command lists in case of a - buffer overflow - */ - size_t all_vtx_size = 0; - size_t all_idx_size = 0; - int cmd_list_count = 0; - for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++, cmd_list_count++) { - ImDrawList* cl = _simgui_imdrawlist_at(draw_data, cl_index); - const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert); - const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx); - - // check for buffer overflow - if (((all_vtx_size + vtx_size) > _simgui.vertices.size) || - ((all_idx_size + idx_size) > _simgui.indices.size)) - { - break; - } - - // copy vertices and indices into common buffers - if (vtx_size > 0) { - const ImDrawVert* src_vtx_ptr = cl->VtxBuffer.Data; - void* dst_vtx_ptr = (void*) (((uint8_t*)_simgui.vertices.ptr) + all_vtx_size); - memcpy(dst_vtx_ptr, src_vtx_ptr, vtx_size); - } - if (idx_size > 0) { - const ImDrawIdx* src_idx_ptr = cl->IdxBuffer.Data; - void* dst_idx_ptr = (void*) (((uint8_t*)_simgui.indices.ptr) + all_idx_size); - memcpy(dst_idx_ptr, src_idx_ptr, idx_size); - } - all_vtx_size += vtx_size; - all_idx_size += idx_size; - } - if (0 == cmd_list_count) { - return; - } - - // update the sokol-gfx vertex- and index-buffer - sg_push_debug_group("sokol-imgui"); - if (all_vtx_size > 0) { - sg_range vtx_data = _simgui.vertices; - vtx_data.size = all_vtx_size; - sg_update_buffer(_simgui.vbuf, &vtx_data); - } - if (all_idx_size > 0) { - sg_range idx_data = _simgui.indices; - idx_data.size = all_idx_size; - sg_update_buffer(_simgui.ibuf, &idx_data); - } - - // render the ImGui command list - const float dpi_scale = _simgui.cur_dpi_scale; - const int fb_width = (int) (io->DisplaySize.x * dpi_scale); - const int fb_height = (int) (io->DisplaySize.y * dpi_scale); - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); - - sg_apply_pipeline(_simgui.def_pip); - _simgui_vs_params_t vs_params; - _simgui_clear((void*)&vs_params, sizeof(vs_params)); - vs_params.disp_size.x = io->DisplaySize.x; - vs_params.disp_size.y = io->DisplaySize.y; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); - sg_bindings bind; - _simgui_clear((void*)&bind, sizeof(bind)); - bind.vertex_buffers[0] = _simgui.vbuf; - bind.index_buffer = _simgui.ibuf; - ImTextureID tex_id = io->Fonts->TexID; - _simgui_bind_image_sampler(&bind, tex_id); - int vb_offset = 0; - int ib_offset = 0; - for (int cl_index = 0; cl_index < cmd_list_count; cl_index++) { - ImDrawList* cl = _simgui_imdrawlist_at(draw_data, cl_index); - - bind.vertex_buffer_offsets[0] = vb_offset; - bind.index_buffer_offset = ib_offset; - sg_apply_bindings(&bind); - - #if defined(__cplusplus) - const int num_cmds = cl->CmdBuffer.size(); - #else - const int num_cmds = cl->CmdBuffer.Size; - #endif - uint32_t vtx_offset = 0; - for (int cmd_index = 0; cmd_index < num_cmds; cmd_index++) { - ImDrawCmd* pcmd = &cl->CmdBuffer.Data[cmd_index]; - if (pcmd->UserCallback != 0) { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback != ImDrawCallback_ResetRenderState) { - pcmd->UserCallback(cl, pcmd); - // need to re-apply all state after calling a user callback - sg_reset_state_cache(); - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_pipeline(_simgui.def_pip); - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); - sg_apply_bindings(&bind); - } - } else { - if ((tex_id != pcmd->TextureId) || (vtx_offset != pcmd->VtxOffset)) { - tex_id = pcmd->TextureId; - vtx_offset = pcmd->VtxOffset; - const _simgui_image_t* img = _simgui_bind_image_sampler(&bind, tex_id); - if (img) { - sg_apply_pipeline(img->pip); - } else { - sg_apply_pipeline(_simgui.def_pip); - } - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); - bind.vertex_buffer_offsets[0] = vb_offset + (int)(pcmd->VtxOffset * sizeof(ImDrawVert)); - sg_apply_bindings(&bind); - } - const int scissor_x = (int) (pcmd->ClipRect.x * dpi_scale); - const int scissor_y = (int) (pcmd->ClipRect.y * dpi_scale); - const int scissor_w = (int) ((pcmd->ClipRect.z - pcmd->ClipRect.x) * dpi_scale); - const int scissor_h = (int) ((pcmd->ClipRect.w - pcmd->ClipRect.y) * dpi_scale); - sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true); - sg_draw((int)pcmd->IdxOffset, (int)pcmd->ElemCount, 1); - } - } - #if defined(__cplusplus) - const size_t vtx_size = (size_t)cl->VtxBuffer.size() * sizeof(ImDrawVert); - const size_t idx_size = (size_t)cl->IdxBuffer.size() * sizeof(ImDrawIdx); - #else - const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert); - const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx); - #endif - vb_offset += (int)vtx_size; - ib_offset += (int)idx_size; - } - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); - sg_pop_debug_group(); -} - -SOKOL_API_IMPL void simgui_add_focus_event(bool focus) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddFocusEvent(focus); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddFocusEvent(io, focus); - #endif -} - -SOKOL_API_IMPL void simgui_add_mouse_pos_event(float x, float y) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_Mouse); - #endif - io->AddMousePosEvent(x, y); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse); - #endif - ImGuiIO_AddMousePosEvent(io, x, y); - #endif -} - -SOKOL_API_IMPL void simgui_add_touch_pos_event(float x, float y) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); - #endif - io->AddMousePosEvent(x, y); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_TouchScreen); - #endif - ImGuiIO_AddMousePosEvent(io, x, y); - #endif -} - -SOKOL_API_IMPL void simgui_add_mouse_button_event(int mouse_button, bool down) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_Mouse); - #endif - io->AddMouseButtonEvent(mouse_button, down); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse); - #endif - ImGuiIO_AddMouseButtonEvent(io, mouse_button, down); - #endif -} - -SOKOL_API_IMPL void simgui_add_touch_button_event(int mouse_button, bool down) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); - #endif - io->AddMouseButtonEvent(mouse_button, down); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_TouchScreen); - #endif - ImGuiIO_AddMouseButtonEvent(io, mouse_button, down); - #endif -} - -SOKOL_API_IMPL void simgui_add_mouse_wheel_event(float wheel_x, float wheel_y) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_Mouse); - #endif - io->AddMouseWheelEvent(wheel_x, wheel_y); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse); - #endif - ImGuiIO_AddMouseWheelEvent(io, wheel_x, wheel_y); - #endif -} - -SOKOL_API_IMPL void simgui_add_key_event(int (*map_keycode)(int), int keycode, bool down) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - const ImGuiKey imgui_key = (ImGuiKey)map_keycode(keycode); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddKeyEvent(imgui_key, down); - io->SetKeyEventNativeData(imgui_key, keycode, 0, -1); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddKeyEvent(io, imgui_key, down); - ImGuiIO_SetKeyEventNativeData(io, imgui_key, keycode, 0, -1); - #endif -} - -SOKOL_API_IMPL void simgui_add_input_character(uint32_t c) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddInputCharacter(c); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddInputCharacter(io, c); - #endif -} - -SOKOL_API_IMPL void simgui_add_input_characters_utf8(const char* c) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddInputCharactersUTF8(c); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddInputCharactersUTF8(io, c); - #endif -} - -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) -_SOKOL_PRIVATE bool _simgui_is_ctrl(uint32_t modifiers) { - if (_simgui.is_osx) { - return 0 != (modifiers & SAPP_MODIFIER_SUPER); - } else { - return 0 != (modifiers & SAPP_MODIFIER_CTRL); - } -} - -_SOKOL_PRIVATE ImGuiKey _simgui_map_keycode(sapp_keycode key) { - switch (key) { - case SAPP_KEYCODE_SPACE: return ImGuiKey_Space; - case SAPP_KEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe; - case SAPP_KEYCODE_COMMA: return ImGuiKey_Comma; - case SAPP_KEYCODE_MINUS: return ImGuiKey_Minus; - case SAPP_KEYCODE_PERIOD: return ImGuiKey_Apostrophe; - case SAPP_KEYCODE_SLASH: return ImGuiKey_Slash; - case SAPP_KEYCODE_0: return ImGuiKey_0; - case SAPP_KEYCODE_1: return ImGuiKey_1; - case SAPP_KEYCODE_2: return ImGuiKey_2; - case SAPP_KEYCODE_3: return ImGuiKey_3; - case SAPP_KEYCODE_4: return ImGuiKey_4; - case SAPP_KEYCODE_5: return ImGuiKey_5; - case SAPP_KEYCODE_6: return ImGuiKey_6; - case SAPP_KEYCODE_7: return ImGuiKey_7; - case SAPP_KEYCODE_8: return ImGuiKey_8; - case SAPP_KEYCODE_9: return ImGuiKey_9; - case SAPP_KEYCODE_SEMICOLON: return ImGuiKey_Semicolon; - case SAPP_KEYCODE_EQUAL: return ImGuiKey_Equal; - case SAPP_KEYCODE_A: return ImGuiKey_A; - case SAPP_KEYCODE_B: return ImGuiKey_B; - case SAPP_KEYCODE_C: return ImGuiKey_C; - case SAPP_KEYCODE_D: return ImGuiKey_D; - case SAPP_KEYCODE_E: return ImGuiKey_E; - case SAPP_KEYCODE_F: return ImGuiKey_F; - case SAPP_KEYCODE_G: return ImGuiKey_G; - case SAPP_KEYCODE_H: return ImGuiKey_H; - case SAPP_KEYCODE_I: return ImGuiKey_I; - case SAPP_KEYCODE_J: return ImGuiKey_J; - case SAPP_KEYCODE_K: return ImGuiKey_K; - case SAPP_KEYCODE_L: return ImGuiKey_L; - case SAPP_KEYCODE_M: return ImGuiKey_M; - case SAPP_KEYCODE_N: return ImGuiKey_N; - case SAPP_KEYCODE_O: return ImGuiKey_O; - case SAPP_KEYCODE_P: return ImGuiKey_P; - case SAPP_KEYCODE_Q: return ImGuiKey_Q; - case SAPP_KEYCODE_R: return ImGuiKey_R; - case SAPP_KEYCODE_S: return ImGuiKey_S; - case SAPP_KEYCODE_T: return ImGuiKey_T; - case SAPP_KEYCODE_U: return ImGuiKey_U; - case SAPP_KEYCODE_V: return ImGuiKey_V; - case SAPP_KEYCODE_W: return ImGuiKey_W; - case SAPP_KEYCODE_X: return ImGuiKey_X; - case SAPP_KEYCODE_Y: return ImGuiKey_Y; - case SAPP_KEYCODE_Z: return ImGuiKey_Z; - case SAPP_KEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket; - case SAPP_KEYCODE_BACKSLASH: return ImGuiKey_Backslash; - case SAPP_KEYCODE_RIGHT_BRACKET:return ImGuiKey_RightBracket; - case SAPP_KEYCODE_GRAVE_ACCENT: return ImGuiKey_GraveAccent; - case SAPP_KEYCODE_ESCAPE: return ImGuiKey_Escape; - case SAPP_KEYCODE_ENTER: return ImGuiKey_Enter; - case SAPP_KEYCODE_TAB: return ImGuiKey_Tab; - case SAPP_KEYCODE_BACKSPACE: return ImGuiKey_Backspace; - case SAPP_KEYCODE_INSERT: return ImGuiKey_Insert; - case SAPP_KEYCODE_DELETE: return ImGuiKey_Delete; - case SAPP_KEYCODE_RIGHT: return ImGuiKey_RightArrow; - case SAPP_KEYCODE_LEFT: return ImGuiKey_LeftArrow; - case SAPP_KEYCODE_DOWN: return ImGuiKey_DownArrow; - case SAPP_KEYCODE_UP: return ImGuiKey_UpArrow; - case SAPP_KEYCODE_PAGE_UP: return ImGuiKey_PageUp; - case SAPP_KEYCODE_PAGE_DOWN: return ImGuiKey_PageDown; - case SAPP_KEYCODE_HOME: return ImGuiKey_Home; - case SAPP_KEYCODE_END: return ImGuiKey_End; - case SAPP_KEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock; - case SAPP_KEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock; - case SAPP_KEYCODE_NUM_LOCK: return ImGuiKey_NumLock; - case SAPP_KEYCODE_PRINT_SCREEN: return ImGuiKey_PrintScreen; - case SAPP_KEYCODE_PAUSE: return ImGuiKey_Pause; - case SAPP_KEYCODE_F1: return ImGuiKey_F1; - case SAPP_KEYCODE_F2: return ImGuiKey_F2; - case SAPP_KEYCODE_F3: return ImGuiKey_F3; - case SAPP_KEYCODE_F4: return ImGuiKey_F4; - case SAPP_KEYCODE_F5: return ImGuiKey_F5; - case SAPP_KEYCODE_F6: return ImGuiKey_F6; - case SAPP_KEYCODE_F7: return ImGuiKey_F7; - case SAPP_KEYCODE_F8: return ImGuiKey_F8; - case SAPP_KEYCODE_F9: return ImGuiKey_F9; - case SAPP_KEYCODE_F10: return ImGuiKey_F10; - case SAPP_KEYCODE_F11: return ImGuiKey_F11; - case SAPP_KEYCODE_F12: return ImGuiKey_F12; - case SAPP_KEYCODE_KP_0: return ImGuiKey_Keypad0; - case SAPP_KEYCODE_KP_1: return ImGuiKey_Keypad1; - case SAPP_KEYCODE_KP_2: return ImGuiKey_Keypad2; - case SAPP_KEYCODE_KP_3: return ImGuiKey_Keypad3; - case SAPP_KEYCODE_KP_4: return ImGuiKey_Keypad4; - case SAPP_KEYCODE_KP_5: return ImGuiKey_Keypad5; - case SAPP_KEYCODE_KP_6: return ImGuiKey_Keypad6; - case SAPP_KEYCODE_KP_7: return ImGuiKey_Keypad7; - case SAPP_KEYCODE_KP_8: return ImGuiKey_Keypad8; - case SAPP_KEYCODE_KP_9: return ImGuiKey_Keypad9; - case SAPP_KEYCODE_KP_DECIMAL: return ImGuiKey_KeypadDecimal; - case SAPP_KEYCODE_KP_DIVIDE: return ImGuiKey_KeypadDivide; - case SAPP_KEYCODE_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; - case SAPP_KEYCODE_KP_SUBTRACT: return ImGuiKey_KeypadSubtract; - case SAPP_KEYCODE_KP_ADD: return ImGuiKey_KeypadAdd; - case SAPP_KEYCODE_KP_ENTER: return ImGuiKey_KeypadEnter; - case SAPP_KEYCODE_KP_EQUAL: return ImGuiKey_KeypadEqual; - case SAPP_KEYCODE_LEFT_SHIFT: return ImGuiKey_LeftShift; - case SAPP_KEYCODE_LEFT_CONTROL: return ImGuiKey_LeftCtrl; - case SAPP_KEYCODE_LEFT_ALT: return ImGuiKey_LeftAlt; - case SAPP_KEYCODE_LEFT_SUPER: return ImGuiKey_LeftSuper; - case SAPP_KEYCODE_RIGHT_SHIFT: return ImGuiKey_RightShift; - case SAPP_KEYCODE_RIGHT_CONTROL:return ImGuiKey_RightCtrl; - case SAPP_KEYCODE_RIGHT_ALT: return ImGuiKey_RightAlt; - case SAPP_KEYCODE_RIGHT_SUPER: return ImGuiKey_RightSuper; - case SAPP_KEYCODE_MENU: return ImGuiKey_Menu; - default: return ImGuiKey_None; - } -} - -_SOKOL_PRIVATE void _simgui_add_sapp_key_event(ImGuiIO* io, sapp_keycode sapp_key, bool down) { - const ImGuiKey imgui_key = _simgui_map_keycode(sapp_key); - #if defined(__cplusplus) - io->AddKeyEvent(imgui_key, down); - io->SetKeyEventNativeData(imgui_key, (int)sapp_key, 0, -1); - #else - ImGuiIO_AddKeyEvent(io, imgui_key, down); - ImGuiIO_SetKeyEventNativeData(io, imgui_key, (int)sapp_key, 0, -1); - #endif -} - -_SOKOL_PRIVATE void _simgui_add_imgui_key_event(ImGuiIO* io, ImGuiKey imgui_key, bool down) { - #if defined(__cplusplus) - io->AddKeyEvent(imgui_key, down); - #else - ImGuiIO_AddKeyEvent(io, imgui_key, down); - #endif -} - -_SOKOL_PRIVATE void _simgui_update_modifiers(ImGuiIO* io, uint32_t mods) { - _simgui_add_imgui_key_event(io, ImGuiMod_Ctrl, (mods & SAPP_MODIFIER_CTRL) != 0); - _simgui_add_imgui_key_event(io, ImGuiMod_Shift, (mods & SAPP_MODIFIER_SHIFT) != 0); - _simgui_add_imgui_key_event(io, ImGuiMod_Alt, (mods & SAPP_MODIFIER_ALT) != 0); - _simgui_add_imgui_key_event(io, ImGuiMod_Super, (mods & SAPP_MODIFIER_SUPER) != 0); -} - -// returns Ctrl or Super, depending on platform -_SOKOL_PRIVATE ImGuiKey _simgui_copypaste_modifier(void) { - return _simgui.is_osx ? ImGuiMod_Super : ImGuiMod_Ctrl; -} - -SOKOL_API_IMPL int simgui_map_keycode(sapp_keycode keycode) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - return (int)_simgui_map_keycode(keycode); -} - -SOKOL_API_IMPL bool simgui_handle_event(const sapp_event* ev) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - const float dpi_scale = _simgui.cur_dpi_scale; - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #else - ImGuiIO* io = igGetIO(); - #endif - switch (ev->type) { - case SAPP_EVENTTYPE_FOCUSED: - simgui_add_focus_event(true); - break; - case SAPP_EVENTTYPE_UNFOCUSED: - simgui_add_focus_event(false); - break; - case SAPP_EVENTTYPE_MOUSE_DOWN: - simgui_add_mouse_pos_event(ev->mouse_x / dpi_scale, ev->mouse_y / dpi_scale); - simgui_add_mouse_button_event((int)ev->mouse_button, true); - _simgui_update_modifiers(io, ev->modifiers); - break; - case SAPP_EVENTTYPE_MOUSE_UP: - simgui_add_mouse_pos_event(ev->mouse_x / dpi_scale, ev->mouse_y / dpi_scale); - simgui_add_mouse_button_event((int)ev->mouse_button, false); - _simgui_update_modifiers(io, ev->modifiers); - break; - case SAPP_EVENTTYPE_MOUSE_MOVE: - simgui_add_mouse_pos_event(ev->mouse_x / dpi_scale, ev->mouse_y / dpi_scale); - break; - case SAPP_EVENTTYPE_MOUSE_ENTER: - case SAPP_EVENTTYPE_MOUSE_LEAVE: - // FIXME: since the sokol_app.h emscripten backend doesn't support - // mouse capture, mouse buttons must be released when the mouse leaves the - // browser window, so that they don't "stick" when released outside the window. - // A cleaner solution would be a new sokol_app.h function to query - // "platform behaviour flags". - #if defined(__EMSCRIPTEN__) - for (int i = 0; i < SAPP_MAX_MOUSEBUTTONS; i++) { - simgui_add_mouse_button_event(i, false); - } - #endif - break; - case SAPP_EVENTTYPE_MOUSE_SCROLL: - simgui_add_mouse_wheel_event(ev->scroll_x, ev->scroll_y); - break; - case SAPP_EVENTTYPE_TOUCHES_BEGAN: - simgui_add_touch_pos_event(ev->touches[0].pos_x / dpi_scale, ev->touches[0].pos_y / dpi_scale); - simgui_add_touch_button_event(0, true); - break; - case SAPP_EVENTTYPE_TOUCHES_MOVED: - simgui_add_touch_pos_event(ev->touches[0].pos_x / dpi_scale, ev->touches[0].pos_y / dpi_scale); - break; - case SAPP_EVENTTYPE_TOUCHES_ENDED: - simgui_add_touch_pos_event(ev->touches[0].pos_x / dpi_scale, ev->touches[0].pos_y / dpi_scale); - simgui_add_touch_button_event(0, false); - break; - case SAPP_EVENTTYPE_TOUCHES_CANCELLED: - simgui_add_touch_button_event(0, false); - break; - case SAPP_EVENTTYPE_KEY_DOWN: - _simgui_update_modifiers(io, ev->modifiers); - // intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED - if (!_simgui.desc.disable_paste_override) { - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { - break; - } - } - // on web platform, don't forward Ctrl-X, Ctrl-V to the browser - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { - sapp_consume_event(); - } - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { - sapp_consume_event(); - } - // it's ok to add ImGuiKey_None key events - _simgui_add_sapp_key_event(io, ev->key_code, true); - break; - case SAPP_EVENTTYPE_KEY_UP: - _simgui_update_modifiers(io, ev->modifiers); - // intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { - break; - } - // on web platform, don't forward Ctrl-X, Ctrl-V to the browser - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { - sapp_consume_event(); - } - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { - sapp_consume_event(); - } - // it's ok to add ImGuiKey_None key events - _simgui_add_sapp_key_event(io, ev->key_code, false); - break; - case SAPP_EVENTTYPE_CHAR: - /* on some platforms, special keys may be reported as - characters, which may confuse some ImGui widgets, - drop those, also don't forward characters if some - modifiers have been pressed - */ - _simgui_update_modifiers(io, ev->modifiers); - if ((ev->char_code >= 32) && - (ev->char_code != 127) && - (0 == (ev->modifiers & (SAPP_MODIFIER_ALT|SAPP_MODIFIER_CTRL|SAPP_MODIFIER_SUPER)))) - { - simgui_add_input_character(ev->char_code); - } - break; - case SAPP_EVENTTYPE_CLIPBOARD_PASTED: - // simulate a Ctrl-V key down/up - if (!_simgui.desc.disable_paste_override) { - _simgui_add_imgui_key_event(io, _simgui_copypaste_modifier(), true); - _simgui_add_imgui_key_event(io, ImGuiKey_V, true); - _simgui_add_imgui_key_event(io, ImGuiKey_V, false); - _simgui_add_imgui_key_event(io, _simgui_copypaste_modifier(), false); - } - break; - default: - break; - } - return io->WantCaptureKeyboard || io->WantCaptureMouse; -} -#endif // SOKOL_IMGUI_NO_SOKOL_APP - -#endif // SOKOL_IMPL diff --git a/source/engine/thirdparty/sokol/util/sokol_memtrack.h b/source/engine/thirdparty/sokol/util/sokol_memtrack.h deleted file mode 100644 index 47f70fc..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_memtrack.h +++ /dev/null @@ -1,167 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_MEMTRACK_IMPL) -#define SOKOL_MEMTRACK_IMPL -#endif -#ifndef SOKOL_MEMTRACK_INCLUDED -/* - sokol_memtrack.h -- memory allocation wrapper to track memory usage - of sokol libraries - - Project URL: https://github.com/floooh/sokol - - Optionally provide the following defines with your own implementations: - - SOKOL_MEMTRACK_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_MEMTRACK_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_memtrack.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - USAGE - ===== - Just plug the malloc/free wrapper functions into the desc.allocator - struct provided by most sokol header setup functions: - - sg_setup(&(sg_desc){ - //... - .allocator = { - .alloc_fn = smemtrack_alloc, - .free_fn = smemtrack_free, - } - }); - - Then call smemtrack_info() to get information about current number - of allocations and overall allocation size: - - const smemtrack_info_t info = smemtrack_info(); - const int num_allocs = info.num_allocs; - const int num_bytes = info.num_bytes; - - Note the sokol_memtrack.h can only track allocations issued by - the sokol headers, not allocations that happen under the hood - in system libraries. - - LICENSE - ======= - - zlib/libpng license - - Copyright (c) 2018 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_MEMTRACK_INCLUDED (1) -#include -#include // size_t - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_MEMTRACK_API_DECL) -#define SOKOL_MEMTRACK_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_MEMTRACK_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_MEMTRACK_IMPL) -#define SOKOL_MEMTRACK_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_MEMTRACK_API_DECL __declspec(dllimport) -#else -#define SOKOL_MEMTRACK_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct smemtrack_info_t { - int num_allocs; - int num_bytes; -} smemtrack_info_t; - -SOKOL_MEMTRACK_API_DECL smemtrack_info_t smemtrack_info(void); -SOKOL_MEMTRACK_API_DECL void* smemtrack_alloc(size_t size, void* user_data); -SOKOL_MEMTRACK_API_DECL void smemtrack_free(void* ptr, void* user_data); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif /* SOKOL_MEMTRACK_INCLUDED */ - -/*=== IMPLEMENTATION =========================================================*/ -#ifdef SOKOL_MEMTRACK_IMPL -#define SOKOL_MEMTRACK_IMPL_INCLUDED (1) -#include // malloc, free -#include // memset - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -// per-allocation header used to keep track of the allocation size -#define _SMEMTRACK_HEADER_SIZE (16) - -static struct { - smemtrack_info_t state; -} _smemtrack; - -SOKOL_API_IMPL void* smemtrack_alloc(size_t size, void* user_data) { - (void)user_data; - uint8_t* ptr = (uint8_t*) malloc(size + _SMEMTRACK_HEADER_SIZE); - if (ptr) { - // store allocation size (for allocation size tracking) - *(size_t*)ptr = size; - _smemtrack.state.num_allocs++; - _smemtrack.state.num_bytes += (int) size; - return ptr + _SMEMTRACK_HEADER_SIZE; - } - else { - // allocation failed, return null pointer - return ptr; - } -} - -SOKOL_API_IMPL void smemtrack_free(void* ptr, void* user_data) { - (void)user_data; - if (ptr) { - uint8_t* alloc_ptr = ((uint8_t*)ptr) - _SMEMTRACK_HEADER_SIZE; - size_t size = *(size_t*)alloc_ptr; - _smemtrack.state.num_allocs--; - _smemtrack.state.num_bytes -= (int) size; - free(alloc_ptr); - } -} - -SOKOL_API_IMPL smemtrack_info_t smemtrack_info(void) { - return _smemtrack.state; -} - -#endif /* SOKOL_MEMTRACK_IMPL */ diff --git a/source/engine/thirdparty/sokol/util/sokol_nuklear.h b/source/engine/thirdparty/sokol/util/sokol_nuklear.h deleted file mode 100644 index 04e73ea..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_nuklear.h +++ /dev/null @@ -1,2667 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_NUKLEAR_IMPL) -#define SOKOL_NUKLEAR_IMPL -#endif -#ifndef SOKOL_NUKLEAR_INCLUDED -/* - sokol_nuklear.h -- drop-in Nuklear renderer/event-handler for sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_NUKLEAR_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - The following defines are used by the implementation to select the - platform-specific embedded shader code (these are the same defines as - used by sokol_gfx.h and sokol_app.h): - - SOKOL_GLCORE33 - SOKOL_GLES3 - SOKOL_D3D11 - SOKOL_METAL - SOKOL_WGPU - - Optionally provide the following configuration defines before including the - implementation: - - SOKOL_NUKLEAR_NO_SOKOL_APP - don't depend on sokol_app.h (see below for details) - - Optionally provide the following macros before including the implementation - to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_NUKLEAR_API_DECL- public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_NUKLEAR_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_nuklear.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_NUKLEAR_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before sokol_nuklear.h (both before including - the declaration and implementation): - - sokol_gfx.h - sokol_app.h (except SOKOL_NUKLEAR_NO_SOKOL_APP) - nuklear.h - - NOTE: Unlike most other sokol-headers, the implementation must be compiled - as C, compiling as C++ isn't supported. The interface is callable - from C++ of course. - - - FEATURE OVERVIEW: - ================= - sokol_nuklear.h implements the initialization, rendering and event-handling - code for Nuklear (https://github.com/Immediate-Mode-UI/Nuklear) on top of - sokol_gfx.h and (optionally) sokol_app.h. - - The sokol_app.h dependency is optional and used for input event handling. - If you only use sokol_gfx.h but not sokol_app.h in your application, - define SOKOL_NUKLEAR_NO_SOKOL_APP before including the implementation - of sokol_nuklear.h, this will remove any dependency to sokol_app.h, but - you must feed input events into Nuklear yourself. - - sokol_nuklear.h is not thread-safe, all calls must be made from the - same thread where sokol_gfx.h is running. - - HOWTO: - ====== - - --- To initialize sokol-nuklear, call: - - snk_setup(const snk_desc_t* desc) - - This will initialize Nuklear and create sokol-gfx resources - (two buffers for vertices and indices, a font texture and a pipeline- - state-object). - - Use the following snk_desc_t members to configure behaviour: - - int max_vertices - The maximum number of vertices used for UI rendering, default is 65536. - sokol-nuklear will use this to compute the size of the vertex- - and index-buffers allocated via sokol_gfx.h - - int image_pool_size - Number of snk_image_t objects which can be alive at the same time. - The default is 256. - - sg_pixel_format color_format - The color pixel format of the render pass where the UI - will be rendered. The default is SG_PIXELFORMAT_RGBA8 - - sg_pixel_format depth_format - The depth-buffer pixel format of the render pass where - the UI will be rendered. The default is SG_PIXELFORMAT_DEPTHSTENCIL. - - int sample_count - The MSAA sample-count of the render pass where the UI - will be rendered. The default is 1. - - float dpi_scale - DPI scaling factor. Set this to the result of sapp_dpi_scale(). - To render in high resolution on a Retina Mac this would - typically be 2.0. The default value is 1.0 - - bool no_default_font - Set this to true if you don't want to use Nuklear's default - font. In this case you need to initialize the font - yourself after snk_setup() is called. - - --- At the start of a frame, call: - - struct nk_context *snk_new_frame() - - This updates Nuklear's event handling state and then returns - a Nuklear context pointer which you use to build the UI. For - example: - - struct nk_context *ctx = snk_new_frame(); - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), ... - - - --- at the end of the frame, before the sg_end_pass() where you - want to render the UI, call: - - snk_render(int width, int height) - - where 'width' and 'height' are the dimensions of the rendering surface. - For example, if you're using sokol_app.h and render to the default - framebuffer: - - snk_render(sapp_width(), sapp_height()); - - This will convert Nuklear's command list into a vertex and index buffer, - and then render that through sokol_gfx.h - - --- if you're using sokol_app.h, from inside the sokol_app.h event callback, - call: - - bool snk_handle_event(const sapp_event* ev); - - This will feed the event into Nuklear's event handling code, and return - true if the event was handled by Nuklear, or false if the event should - be handled by the application. - - --- finally, on application shutdown, call - - snk_shutdown() - - --- Note that for touch-based systems, like iOS, there is a wrapper around - nk_edit_string(...), called snk_edit_string(...) which will show - and hide the onscreen keyboard as required. - - - ON USER-PROVIDED IMAGES AND SAMPLERS - ==================================== - To render your own images via nk_image(), first create an snk_image_t - object from a sokol-gfx image and sampler object. - - // create a sokol-nuklear image object which associates an sg_image with an sg_sampler - snk_image_t snk_img = snk_make_image(&(snk_image_desc_t){ - .image = sg_make_image(...), - .sampler = sg_make_sampler(...), - }); - - // convert the returned image handle into an nk_handle object - struct nk_handle nk_hnd = snk_nkhandle(snk_img); - - // create a nuklear image from the generic handle (note that there a different helper functions for this) - struct nk_image nk_img = nk_image_handle(nk_hnd); - - // finally specify a Nuklear image UI object - nk_image(ctx, nk_img); - - snk_image_t objects are small and cheap (literally just the image and sampler - handle). - - You can omit the sampler handle in the snk_make_image() call, in this case a - default sampler will be used with nearest-filtering and clamp-to-edge. - - Trying to render with an invalid snk_image_t handle will render a small 8x8 - white default texture instead. - - To destroy a sokol-nuklear image object, call - - snk_destroy_image(snk_img); - - But please be aware that the image object needs to be around until snk_render() is called - in a frame (if this turns out to be too much of a hassle we could introduce some sort - of garbage collection where destroyed snk_image_t objects are kept around until - the snk_render() call). - - You can call: - - snk_image_desc_t desc = snk_query_image_desc(img) - - ...to get the original desc struct, useful if you need to get the sokol-gfx image - and sampler handle of the snk_image_t object. - - You can convert an nk_handle back into an snk_image_t handle: - - snk_image_t img = snk_image_from_nkhandle(nk_hnd); - - - 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); - } - - ... - snk_setup(&(snk_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_nuklear.h - itself though, not any allocations in Nuklear. - - - ERROR REPORTING AND LOGGING - =========================== - To get any logging information at all you need to provide a logging callback in the setup call - the easiest way is to use sokol_log.h: - - #include "sokol_log.h" - - snk_setup(&(snk_desc_t){ - .logger.func = slog_func - }); - - To override logging with your own callback, first write a logging function like this: - - void my_log(const char* tag, // e.g. 'snk' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SNK_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_nuklear.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-nuklear like this: - - snk_setup(&(snk_desc_t){ - .logger = { - .func = my_log, - .user_data = my_user_data, - } - }); - - The provided logging function must be reentrant (e.g. be callable from - different threads). - - If you don't want to provide your own custom logger it is highly recommended to use - the standard logger in sokol_log.h instead, otherwise you won't see any warnings or - errors. - - - LICENSE - ======= - - zlib/libpng license - - Copyright (c) 2020 Warren Merrifield - - 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_NUKLEAR_INCLUDED (1) -#include -#include -#include - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_nuklear.h" -#endif -#if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) && !defined(SOKOL_APP_INCLUDED) -#error "Please include sokol_app.h before sokol_nuklear.h" -#endif -#if !defined(NK_UNDEFINED) -#error "Please include nuklear.h before sokol_nuklear.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_NUKLEAR_API_DECL) -#define SOKOL_NUKLEAR_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_NUKLEAR_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_NUKLEAR_IMPL) -#define SOKOL_NUKLEAR_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_NUKLEAR_API_DECL __declspec(dllimport) -#else -#define SOKOL_NUKLEAR_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SNK_INVALID_ID = 0, -}; - -/* - snk_image_t - - A combined image-sampler pair used to inject custom images and samplers into Nuklear - - Create with snk_make_image(), and convert to an nk_handle via snk_nkhandle(). -*/ -typedef struct snk_image_t { uint32_t id; } snk_image_t; - -/* - snk_image_desc_t - - Descriptor struct for snk_make_image(). You must provide - at least an sg_image handle. Keeping the sg_sampler handle - zero-initialized will select the builtin default sampler - which uses linear filtering. -*/ -typedef struct snk_image_desc_t { - sg_image image; - sg_sampler sampler; -} snk_image_desc_t; - -/* - snk_log_item - - An enum with a unique item for each log message, warning, error - and validation layer message. -*/ -#define _SNK_LOG_ITEMS \ - _SNK_LOGITEM_XMACRO(OK, "Ok") \ - _SNK_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SNK_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \ - -#define _SNK_LOGITEM_XMACRO(item,msg) SNK_LOGITEM_##item, -typedef enum snk_log_item_t { - _SNK_LOG_ITEMS -} snk_log_item_t; -#undef _SNK_LOGITEM_XMACRO - -/* - snk_allocator_t - - Used in snk_desc_t to provide custom memory-alloc and -free functions - to sokol_nuklear.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 snk_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} snk_allocator_t; - -/* - snk_logger - - Used in snk_desc_t to provide a logging function. Please be aware - that without logging function, sokol-nuklear will be completely - silent, e.g. it will not report errors, warnings and - validation layer messages. For maximum error verbosity, - compile in debug mode (e.g. NDEBUG *not* defined) and install - a logger (for instance the standard logging function from sokol_log.h). -*/ -typedef struct snk_logger_t { - void (*func)( - const char* tag, // always "snk" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SNK_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_imgui.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} snk_logger_t; - - -typedef struct snk_desc_t { - int max_vertices; // default: 65536 - int image_pool_size; // default: 256 - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - float dpi_scale; - bool no_default_font; - snk_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - snk_logger_t logger; // optional log function override -} snk_desc_t; - -SOKOL_NUKLEAR_API_DECL void snk_setup(const snk_desc_t* desc); -SOKOL_NUKLEAR_API_DECL struct nk_context* snk_new_frame(void); -SOKOL_NUKLEAR_API_DECL void snk_render(int width, int height); -SOKOL_NUKLEAR_API_DECL snk_image_t snk_make_image(const snk_image_desc_t* desc); -SOKOL_NUKLEAR_API_DECL void snk_destroy_image(snk_image_t img); -SOKOL_NUKLEAR_API_DECL snk_image_desc_t snk_query_image_desc(snk_image_t img); -SOKOL_NUKLEAR_API_DECL nk_handle snk_nkhandle(snk_image_t img); -SOKOL_NUKLEAR_API_DECL snk_image_t snk_image_from_nkhandle(nk_handle handle); -#if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) -SOKOL_NUKLEAR_API_DECL bool snk_handle_event(const sapp_event* ev); -SOKOL_NUKLEAR_API_DECL nk_flags snk_edit_string(struct nk_context *ctx, nk_flags flags, char *memory, int *len, int max, nk_plugin_filter filter); -#endif -SOKOL_NUKLEAR_API_DECL void snk_shutdown(void); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for C++ */ -inline void snk_setup(const snk_desc_t& desc) { return snk_setup(&desc); } -inline snk_image_t snk_make_image(const snk_image_desc_t& desc) { return snk_make_image(&desc); } - -#endif -#endif /* SOKOL_NUKLEAR_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_NUKLEAR_IMPL -#define SOKOL_NUKLEAR_IMPL_INCLUDED (1) - -#if !defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) -#error "Please ensure that NK_INCLUDE_VERTEX_BUFFER_OUTPUT is #defined before including nuklear.h" -#endif - -#ifdef __cplusplus -#error "The sokol_nuklear.h implementation must be compiled as C." -#endif - -#include -#include // memset - -#if defined(__EMSCRIPTEN__) && !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) && !defined(SOKOL_DUMMY_BACKEND) -#include -#endif - -#ifndef SOKOL_API_IMPL -#define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#define _SNK_INIT_COOKIE (0xBABEBABE) -#define _SNK_INVALID_SLOT_INDEX (0) -#define _SNK_SLOT_SHIFT (16) -#define _SNK_MAX_POOL_SIZE (1<<_SNK_SLOT_SHIFT) -#define _SNK_SLOT_MASK (_SNK_MAX_POOL_SIZE-1) - -// helper macros -#define _snk_def(val, def) (((val) == 0) ? (def) : (val)) - -typedef struct _snk_vertex_t { - float pos[2]; - float uv[2]; - uint8_t col[4]; -} _snk_vertex_t; - -typedef struct _snk_vs_params_t { - float disp_size[2]; - uint8_t _pad_8[8]; -} _snk_vs_params_t; - -typedef enum { - _SNK_RESOURCESTATE_INITIAL, - _SNK_RESOURCESTATE_ALLOC, - _SNK_RESOURCESTATE_VALID, - _SNK_RESOURCESTATE_FAILED, - _SNK_RESOURCESTATE_INVALID, - _SNK_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF -} _snk_resource_state; - -typedef struct { - uint32_t id; - _snk_resource_state state; -} _snk_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _snk_pool_t; - -typedef struct { - _snk_slot_t slot; - sg_image image; - sg_sampler sampler; -} _snk_image_t; - -typedef struct { - _snk_pool_t pool; - _snk_image_t* items; -} _snk_image_pool_t; - -typedef struct { - uint32_t init_cookie; - snk_desc_t desc; - struct nk_context ctx; - struct nk_font_atlas atlas; - _snk_vs_params_t vs_params; - size_t vertex_buffer_size; - size_t index_buffer_size; - sg_buffer vbuf; - sg_buffer ibuf; - sg_image font_img; - sg_sampler font_smp; - snk_image_t default_font; - sg_image def_img; - sg_sampler def_smp; - sg_shader shd; - sg_pipeline pip; - bool is_osx; // true if running on OSX (or HTML5 OSX), needed for copy/paste - _snk_image_pool_t image_pool; - #if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) - int mouse_pos[2]; - float mouse_scroll[2]; - bool mouse_did_move; - bool mouse_did_scroll; - bool btn_down[NK_BUTTON_MAX]; - bool btn_up[NK_BUTTON_MAX]; - char char_buffer[NK_INPUT_MAX]; - bool keys_down[NK_KEY_MAX]; - bool keys_up[NK_KEY_MAX]; - #endif -} _snk_state_t; -static _snk_state_t _snuklear; - -/* - Embedded source code compiled with: - - sokol-shdc -i snuk.glsl -o snuk.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - vec2 disp_size; - }; - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv) * color; - } - @end - - @program snuk vs fs -*/ -#if defined(SOKOL_GLCORE33) -static const char _snk_vs_source_glsl330[341] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20, - 0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28, - 0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29,0x20,0x2d,0x20, - 0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63, - 0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e, - 0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20, - 0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b, - 0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _snk_fs_source_glsl330[177] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74, - 0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20, - 0x75,0x76,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -#elif defined(SOKOL_GLES3) -static const char _snk_vs_source_glsl300es[344] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20, - 0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f, - 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65, - 0x63,0x34,0x28,0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29, - 0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20, - 0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c, - 0x20,0x30,0x2e,0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _snk_fs_source_glsl300es[250] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _snk_vs_bytecode_metal_macos[3052] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x7b,0x12,0x23,0x17,0xd9,0x25,0x1c, - 0x1b,0x42,0x42,0x9f,0xbf,0x31,0xd2,0x2c,0x3a,0x55,0x22,0x1d,0x40,0xd8,0xc4,0xf8, - 0x20,0x49,0x60,0x6d,0x3c,0xea,0x4e,0x1c,0x34,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc8,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xaf,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x81,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0x02,0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00, - 0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x16,0x00,0x00,0x00, - 0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3, - 0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c,0x10,0x3c,0x33,0x00, - 0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x91,0x83,0xa4,0x29,0xa2,0x84,0xc9, - 0xaf,0xa4,0xff,0x01,0x22,0x80,0x91,0x50,0x10,0x83,0x08,0x84,0x50,0x8a,0x89,0x90, - 0x22,0x1b,0x08,0x98,0x23,0x00,0x83,0x14,0xc8,0x39,0x02,0x50,0x18,0x44,0x08,0x84, - 0x61,0x04,0x22,0x19,0x01,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0,0x03, - 0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87,0x71, - 0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38,0xd8, - 0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06, - 0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07, - 0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20, - 0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d, - 0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50,0x07, - 0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x6d, - 0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xa0, - 0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x30,0x07,0x72,0x30,0x84,0x39,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0xc8, - 0x02,0x01,0x00,0x00,0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84, - 0x32,0xa0,0x1d,0x01,0x20,0x1d,0x4b,0x68,0x02,0x00,0x00,0x00,0x79,0x18,0x00,0x00, - 0xea,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9, - 0xb9,0xb4,0x37,0xb7,0x21,0x46,0x42,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93, - 0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x24,0x01,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e, - 0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd, - 0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e, - 0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26, - 0x65,0x88,0x80,0x10,0x43,0x8c,0x24,0x48,0x86,0x44,0x60,0xd1,0x54,0x46,0x17,0xc6, - 0x36,0x04,0x41,0x8e,0x24,0x48,0x82,0x44,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6, - 0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36, - 0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d, - 0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65, - 0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd, - 0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95, - 0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x90,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b, - 0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98, - 0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e, - 0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84, - 0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21, - 0x11,0x22,0x21,0x13,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b, - 0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08, - 0x83,0x3c,0x88,0x85,0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee, - 0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d, - 0xda,0x9b,0xdb,0x10,0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85, - 0x64,0x08,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd, - 0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b, - 0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32, - 0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36, - 0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43, - 0xa8,0x44,0x40,0x3c,0xe4,0x4b,0x84,0x24,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90, - 0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x02,0xc4, - 0x43,0xbe,0x24,0x48,0x02,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63, - 0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x24,0x40,0xc0, - 0x00,0x89,0x90,0x0b,0x99,0x90,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66, - 0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e, - 0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39, - 0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3, - 0x37,0x26,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x43,0x94,0x44,0x48,0x86, - 0x44,0x40,0x24,0x64,0x0d,0x18,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5, - 0xc1,0x95,0x7d,0xcd,0xa5,0xe9,0x95,0xf1,0x0a,0x4b,0x93,0x73,0x09,0x93,0x3b,0xfb, - 0xa2,0xcb,0x83,0x2b,0xfb,0x0a,0x63,0x4b,0x3b,0x73,0xfb,0x9a,0x4b,0xd3,0x2b,0x63, - 0x62,0x37,0xf7,0x05,0x17,0x26,0x17,0xd6,0x36,0xc7,0xe1,0x4b,0x46,0x66,0x08,0x19, - 0x24,0x06,0x72,0x06,0x08,0x1a,0x24,0x03,0xf2,0x25,0x42,0x12,0x20,0x69,0x80,0xa8, - 0x01,0xc2,0x06,0x48,0x1b,0x24,0x03,0xe2,0x06,0xc9,0x80,0x44,0xc8,0x1b,0x20,0x13, - 0x02,0x07,0x43,0x10,0x44,0x0c,0x10,0x32,0x40,0xcc,0x00,0x89,0x83,0x21,0xc6,0x01, - 0x20,0x1d,0x22,0x07,0x7c,0xde,0xda,0xdc,0xd2,0xe0,0xde,0xe8,0xca,0xdc,0xe8,0x40, - 0xc6,0xd0,0xc2,0xe4,0xf8,0x4c,0xa5,0xb5,0xc1,0xb1,0x95,0x81,0x0c,0xad,0xac,0x80, - 0x50,0x09,0x05,0x05,0x0d,0x11,0x90,0x3a,0x18,0x62,0x20,0x74,0x80,0xd8,0xc1,0x72, - 0x0c,0x31,0x90,0x3b,0x40,0xee,0x60,0x39,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e, - 0x6e,0xd0,0x0e,0xef,0x40,0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1, - 0x70,0x0e,0xf3,0x30,0x45,0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b, - 0xa4,0x03,0x39,0x94,0x83,0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8, - 0x83,0x1b,0xd8,0x43,0x39,0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18, - 0x41,0x85,0x43,0x3a,0xc8,0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38, - 0x9c,0x43,0x39,0xfc,0x82,0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c, - 0x09,0x90,0x11,0x53,0x38,0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43, - 0x3a,0xb0,0x43,0x39,0xfc,0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c, - 0x4c,0x19,0x14,0xc6,0x19,0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8, - 0x03,0x3d,0x94,0x03,0x3e,0x4c,0x09,0xe6,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00, - 0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88, - 0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6, - 0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce, - 0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8, - 0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48, - 0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11, - 0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e, - 0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89, - 0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b, - 0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37, - 0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78, - 0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81, - 0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1, - 0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c, - 0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39, - 0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc, - 0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58, - 0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87, - 0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f, - 0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e, - 0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66, - 0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0, - 0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e, - 0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc, - 0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3, - 0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07, - 0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e, - 0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e, - 0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d, - 0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00, - 0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00, - 0x61,0x20,0x00,0x00,0x23,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00, - 0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10,0x42,0xf0,0x3c,0x94, - 0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82,0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30, - 0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08,0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73, - 0x10,0xd7,0x65,0x55,0x34,0x33,0x00,0x04,0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46, - 0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00,0xe3,0x0d,0x4c,0x64,0x51,0x40,0x2c,0x0a, - 0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9,0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c, - 0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41,0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40, - 0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5b,0x86,0x20,0xc0,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _snk_fs_bytecode_metal_macos[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xa1,0xce,0x6b,0xd1,0x1f,0x32,0x9e, - 0x8d,0x8d,0x1c,0xcc,0x19,0xcb,0xd3,0xb6,0x21,0x99,0x0b,0xb6,0x46,0x8b,0x87,0x98, - 0x8e,0x2d,0xb5,0x98,0x92,0x0a,0x81,0x7d,0xf3,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x0c,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x80,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81,0x00,0x00,0x00, - 0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70, - 0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42, - 0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45, - 0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84, - 0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0, - 0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32, - 0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe, - 0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d, - 0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c, - 0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e, - 0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34, - 0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72, - 0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28, - 0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91, - 0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1, - 0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13, - 0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3, - 0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46, - 0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d, - 0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8, - 0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba,0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60, - 0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0, - 0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b, - 0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1, - 0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e, - 0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1, - 0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c, - 0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61,0x07,0x76,0xb0,0x87, - 0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0x14,0x23,0x96,0x70, - 0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98, - 0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70,0x03,0x76,0x08,0x07,0x77,0x38,0x87, - 0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77, - 0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74,0x90,0x07,0x37,0x18,0x87,0x77,0x68, - 0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78,0x07,0x78,0xa0,0x87,0x74,0x78,0x07, - 0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98,0x70,0x48,0x07,0x79,0x70,0x03,0x73, - 0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77,0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00, - 0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00, - 0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4,0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00, - 0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91,0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6, - 0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _snk_vs_bytecode_metal_ios[3052] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x69,0x97,0x6b,0xac,0xd8,0xa2,0x51, - 0x33,0x7c,0x5f,0x96,0xb2,0xb1,0x06,0x06,0x7c,0xbb,0x5f,0x88,0xa0,0xeb,0x9f,0xea, - 0x6e,0x6b,0x70,0xa9,0x6e,0xef,0xe6,0xa4,0xea,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc0,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xad,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x20,0x02,0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00, - 0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00, - 0x16,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84, - 0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c, - 0x10,0x3c,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x91,0x83,0xa4, - 0x29,0xa2,0x84,0xc9,0xaf,0xa4,0xff,0x01,0x22,0x80,0x91,0x50,0x10,0x83,0x08,0x84, - 0x50,0x8a,0x89,0x90,0x22,0x1b,0x08,0x98,0x23,0x00,0x83,0x14,0xc8,0x39,0x02,0x50, - 0x18,0x44,0x08,0x84,0x61,0x04,0x22,0x19,0x01,0x00,0x00,0x00,0x13,0xa8,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e, - 0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0, - 0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0, - 0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6, - 0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07, - 0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6, - 0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07, - 0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0, - 0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20, - 0x07,0x43,0x98,0x03,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00,0x00, - 0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47, - 0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84,0x32,0xa0,0x1d,0x01, - 0x20,0x1d,0x4b,0x80,0x04,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xe9,0x00,0x00,0x00, - 0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7, - 0x21,0x46,0x42,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3, - 0x2b,0x1b,0x62,0x24,0x01,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4, - 0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac, - 0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10, - 0x43,0x8c,0x24,0x48,0x86,0x44,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e, - 0x24,0x48,0x82,0x44,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56, - 0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56, - 0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65, - 0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c, - 0x65,0x43,0x04,0x64,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1, - 0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95, - 0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x51,0x58, - 0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d, - 0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72, - 0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc, - 0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85, - 0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21,0x11,0x22,0x21,0x13,0x42, - 0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6, - 0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85,0x44, - 0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed, - 0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x05, - 0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85,0x64,0x08,0x47,0x28,0x2c, - 0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52, - 0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59, - 0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0, - 0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf, - 0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x44,0x40,0x3c,0xe4, - 0x4b,0x84,0x24,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90,0x30,0x60,0x42,0x57,0x86, - 0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x02,0xc4,0x43,0xbe,0x24,0x48,0x02, - 0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x24,0x40,0xc0,0x00,0x89,0x90,0x0b,0x99, - 0x90,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c, - 0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58, - 0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba, - 0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x26,0x64,0x69,0x73, - 0x70,0x5f,0x73,0x69,0x7a,0x65,0x43,0x94,0x44,0x48,0x86,0x44,0x40,0x24,0x64,0x0d, - 0x18,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0xcd,0xa5, - 0xe9,0x95,0xf1,0x0a,0x4b,0x93,0x73,0x09,0x93,0x3b,0xfb,0xa2,0xcb,0x83,0x2b,0xfb, - 0x0a,0x63,0x4b,0x3b,0x73,0xfb,0x9a,0x4b,0xd3,0x2b,0x63,0x62,0x37,0xf7,0x05,0x17, - 0x26,0x17,0xd6,0x36,0xc7,0xe1,0x4b,0x46,0x66,0x08,0x19,0x24,0x06,0x72,0x06,0x08, - 0x1a,0x24,0x03,0xf2,0x25,0x42,0x12,0x20,0x69,0x80,0xa8,0x01,0xc2,0x06,0x48,0x1b, - 0x24,0x03,0xe2,0x06,0xc9,0x80,0x44,0xc8,0x1b,0x20,0x13,0x02,0x07,0x43,0x10,0x44, - 0x0c,0x10,0x32,0x40,0xcc,0x00,0x89,0x83,0x21,0xc6,0x01,0x20,0x1d,0x22,0x07,0x7c, - 0xde,0xda,0xdc,0xd2,0xe0,0xde,0xe8,0xca,0xdc,0xe8,0x40,0xc6,0xd0,0xc2,0xe4,0xf8, - 0x4c,0xa5,0xb5,0xc1,0xb1,0x95,0x81,0x0c,0xad,0xac,0x80,0x50,0x09,0x05,0x05,0x0d, - 0x11,0x90,0x3a,0x18,0x62,0x20,0x74,0x80,0xd8,0xc1,0x72,0x0c,0x31,0x90,0x3b,0x40, - 0xee,0x60,0x39,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40, - 0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45, - 0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xa4,0x03,0x39,0x94,0x83, - 0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39, - 0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8, - 0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38,0x9c,0x43,0x39,0xfc,0x82, - 0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c,0x09,0x90,0x11,0x53,0x38, - 0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc, - 0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19, - 0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e, - 0x4c,0x09,0xe6,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c, - 0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07, - 0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e, - 0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43, - 0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c, - 0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76, - 0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e, - 0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8, - 0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4, - 0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68, - 0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07, - 0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71, - 0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5, - 0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4, - 0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90, - 0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43, - 0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b, - 0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78, - 0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2, - 0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20, - 0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0, - 0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83, - 0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07, - 0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61, - 0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d, - 0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39, - 0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79, - 0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3, - 0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4, - 0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8, - 0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83, - 0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00, - 0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x23,0x00,0x00,0x00, - 0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40, - 0x60,0x1c,0x73,0x10,0x42,0xf0,0x3c,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82, - 0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30,0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08, - 0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73,0x10,0xd7,0x65,0x55,0x34,0x33,0x00,0x04, - 0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46,0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00, - 0xe3,0x0d,0x4c,0x64,0x51,0x40,0x2c,0x0a,0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9, - 0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c,0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41, - 0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40,0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x5b,0x86,0x20,0xc0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _snk_fs_bytecode_metal_ios[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf0,0xa4,0xb3,0x95,0x4b,0xab,0x64, - 0x94,0xe7,0xa9,0x8a,0x69,0x27,0x6d,0x28,0x77,0x84,0x8d,0x3f,0xaf,0x7d,0x3c,0x39, - 0x31,0xc4,0xcb,0x53,0x6d,0xc0,0x0d,0xdf,0x08,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x04,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x7e,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87, - 0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9, - 0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07, - 0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20, - 0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72, - 0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07, - 0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10, - 0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07, - 0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98, - 0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03,0x04,0x80,0x00,0x00, - 0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98, - 0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02, - 0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00,0x00,0x79,0x18,0x00, - 0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d, - 0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c, - 0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2, - 0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d, - 0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9, - 0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc, - 0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb, - 0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e, - 0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34, - 0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb, - 0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb, - 0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6, - 0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1, - 0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46, - 0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e, - 0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f, - 0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba, - 0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f, - 0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e, - 0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21, - 0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f, - 0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5, - 0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1, - 0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1, - 0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07, - 0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79, - 0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70, - 0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87, - 0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74, - 0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78, - 0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98, - 0x70,0x48,0x07,0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77, - 0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4, - 0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00,0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91, - 0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6,0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const char _snk_vs_source_metal_sim[672] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, - 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, - 0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, - 0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, - 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62, - 0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x5b, - 0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32, - 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74, - 0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61, - 0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x32, - 0x32,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, - 0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f, - 0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x28,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73, - 0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x5f,0x32,0x32,0x2e,0x64,0x69,0x73,0x70, - 0x5f,0x73,0x69,0x7a,0x65,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28, - 0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x32, - 0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76, - 0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -static const char _snk_fs_source_metal_sim[436] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _snk_vs_bytecode_hlsl4[892] = { - 0x44,0x58,0x42,0x43,0x0d,0xbd,0x9e,0x9e,0x7d,0xc0,0x2b,0x54,0x88,0xf9,0xca,0x89, - 0x32,0xe4,0x0c,0x59,0x01,0x00,0x00,0x00,0x7c,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x60,0x01,0x00,0x00,0xd0,0x01,0x00,0x00, - 0x00,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xc0,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x98,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x88,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x32,0x32,0x5f,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a, - 0x65,0x00,0xab,0xab,0x01,0x00,0x03,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52, - 0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e, - 0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x28,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x4a,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00, - 0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x08, - 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x80,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a, - 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x0a,0x32,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x08, - 0xc2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x80,0x3f,0x3e,0x00,0x00,0x01, - 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _snk_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0x3a,0xa7,0x41,0x21,0xb4,0x2d,0xa7,0x6e,0xfe,0x31,0xb0,0xe0, - 0x14,0xe0,0xdf,0x5a,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_WGPU) -static const char _snk_vs_source_wgsl[1083] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28, - 0x30,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76, - 0x61,0x72,0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x32,0x32, - 0x20,0x3a,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x39, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x5f,0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x35,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x78,0x5f,0x32,0x32, - 0x2e,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x33,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d, - 0x20,0x28,0x28,0x28,0x78,0x5f,0x31,0x39,0x20,0x2f,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x30,0x2e,0x35,0x66,0x2c,0x20,0x30, - 0x2e,0x35,0x66,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x32,0x2e, - 0x30,0x66,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63, - 0x34,0x66,0x28,0x78,0x5f,0x33,0x33,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x33,0x33,0x2e, - 0x79,0x2c,0x20,0x30,0x2e,0x35,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a, - 0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x33,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x34,0x33,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x34,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x37,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75, - 0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61, - 0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c, - 0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78, - 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65, - 0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _snk_fs_source_wgsl[630] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x34,0x20,0x2a,0x20,0x78,0x5f, - 0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75, - 0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f, - 0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66, - 0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28, - 0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29, - 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _snk_vs_source_dummy = ""; -static const char* _snk_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -#if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) -static void _snk_clipboard_copy(nk_handle usr, const char *text, int len) { - (void)usr; - if (len == 0) { - return; - } - sapp_set_clipboard_string(text); -} - -static void _snk_clipboard_paste(nk_handle usr, struct nk_text_edit *edit) { - const char *text = sapp_get_clipboard_string(); - if (text) { - nk_textedit_paste(edit, text, nk_strlen(text)); - } - (void)usr; -} - -#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) -EM_JS(int, snk_js_is_osx, (void), { - if (navigator.userAgent.includes('Macintosh')) { - return 1; - } else { - return 0; - } -}); -#endif - -static bool _snk_is_osx(void) { - #if defined(SOKOL_DUMMY_BACKEND) - return false; - #elif defined(__EMSCRIPTEN__) - return snk_js_is_osx(); - #elif defined(__APPLE__) - return true; - #else - return false; - #endif -} -#endif // !SOKOL_NUKLEAR_NO_SOKOL_APP - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SNK_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _snk_log_messages[] = { - _SNK_LOG_ITEMS -}; -#undef _SNK_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SNK_PANIC(code) _snk_log(SNK_LOGITEM_ ##code, 0, 0, __LINE__) -#define _SNK_ERROR(code) _snk_log(SNK_LOGITEM_ ##code, 1, 0, __LINE__) -#define _SNK_WARN(code) _snk_log(SNK_LOGITEM_ ##code, 2, 0, __LINE__) -#define _SNK_INFO(code) _snk_log(SNK_LOGITEM_ ##code, 3, 0, __LINE__) -#define _SNK_LOGMSG(code,msg) _snk_log(SNK_LOGITEM_ ##code, 3, msg, __LINE__) - -static void _snk_log(snk_log_item_t log_item, uint32_t log_level, const char* msg, uint32_t line_nr) { - if (_snuklear.desc.logger.func) { - const char* filename = 0; - #if defined(SOKOL_DEBUG) - filename = __FILE__; - if (0 == msg) { - msg = _snk_log_messages[log_item]; - } - #endif - _snuklear.desc.logger.func("snk", log_level, log_item, msg, line_nr, filename, _snuklear.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _snk_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _snk_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_snuklear.desc.allocator.alloc_fn) { - ptr = _snuklear.desc.allocator.alloc_fn(size, _snuklear.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SNK_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _snk_malloc_clear(size_t size) { - void* ptr = _snk_malloc(size); - _snk_clear(ptr, size); - return ptr; -} - -static void _snk_free(void* ptr) { - if (_snuklear.desc.allocator.free_fn) { - _snuklear.desc.allocator.free_fn(ptr, _snuklear.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _snk_init_pool(_snk_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _snk_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _snk_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _snk_discard_pool(_snk_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _snk_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _snk_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _snk_pool_alloc_index(_snk_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SNK_INVALID_SLOT_INDEX; - } -} - -static void _snk_pool_free_index(_snk_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SNK_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* initialize a pool slot: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the handle id -*/ -static uint32_t _snk_slot_init(_snk_pool_t* pool, _snk_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SNK_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == _SNK_RESOURCESTATE_INITIAL) && (slot->id == SNK_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SNK_SLOT_SHIFT)|(slot_index & _SNK_SLOT_MASK); - slot->state = _SNK_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _snk_slot_index(uint32_t id) { - int slot_index = (int) (id & _SNK_SLOT_MASK); - SOKOL_ASSERT(_SNK_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -static void _snk_init_item_pool(_snk_pool_t* pool, int pool_size, void** items_ptr, size_t item_size_bytes) { - // NOTE: the pools will have an additional item, since slot 0 is reserved - SOKOL_ASSERT(pool && (pool->size == 0)); - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SNK_MAX_POOL_SIZE)); - SOKOL_ASSERT(items_ptr && (*items_ptr == 0)); - SOKOL_ASSERT(item_size_bytes > 0); - _snk_init_pool(pool, pool_size); - const size_t pool_size_bytes = item_size_bytes * (size_t)pool->size; - *items_ptr = _snk_malloc_clear(pool_size_bytes); -} - -static void _snk_discard_item_pool(_snk_pool_t* pool, void** items_ptr) { - SOKOL_ASSERT(pool && (pool->size != 0)); - SOKOL_ASSERT(items_ptr && (*items_ptr != 0)); - _snk_free(*items_ptr); *items_ptr = 0; - _snk_discard_pool(pool); -} - -static void _snk_setup_image_pool(int pool_size) { - _snk_image_pool_t* p = &_snuklear.image_pool; - _snk_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_snk_image_t)); -} - -static void _snk_discard_image_pool(void) { - _snk_image_pool_t* p = &_snuklear.image_pool; - _snk_discard_item_pool(&p->pool, (void**)&p->items); -} - -static snk_image_t _snk_make_image_handle(uint32_t id) { - snk_image_t handle = { id }; - return handle; -} - -static _snk_image_t* _snk_image_at(uint32_t id) { - SOKOL_ASSERT(SNK_INVALID_ID != id); - const _snk_image_pool_t* p = &_snuklear.image_pool; - int slot_index = _snk_slot_index(id); - SOKOL_ASSERT((slot_index > _SNK_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _snk_image_t* _snk_lookup_image(uint32_t id) { - if (SNK_INVALID_ID != id) { - _snk_image_t* img = _snk_image_at(id); - if (img->slot.id == id) { - return img; - } - } - return 0; -} - -static snk_image_t _snk_alloc_image(void) { - _snk_image_pool_t* p = &_snuklear.image_pool; - int slot_index = _snk_pool_alloc_index(&p->pool); - if (_SNK_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _snk_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _snk_make_image_handle(id); - } else { - // pool exhausted - return _snk_make_image_handle(SNK_INVALID_ID); - } -} - -static _snk_resource_state _snk_init_image(_snk_image_t* img, const snk_image_desc_t* desc) { - SOKOL_ASSERT(img && (img->slot.state == _SNK_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - img->image = desc->image; - img->sampler = desc->sampler; - return _SNK_RESOURCESTATE_VALID; -} - -static void _snk_deinit_image(_snk_image_t* img) { - SOKOL_ASSERT(img); - img->image.id = SNK_INVALID_ID; - img->sampler.id = SNK_INVALID_ID; -} - -static void _snk_destroy_image(snk_image_t img_id) { - _snk_image_t* img = _snk_lookup_image(img_id.id); - if (img) { - _snk_deinit_image(img); - _snk_image_pool_t* p = &_snuklear.image_pool; - _snk_clear(img, sizeof(_snk_image_t)); - _snk_pool_free_index(&p->pool, _snk_slot_index(img_id.id)); - } -} - -static void _snk_destroy_all_images(void) { - _snk_image_pool_t* p = &_snuklear.image_pool; - for (int i = 0; i < p->pool.size; i++) { - _snk_image_t* img = &p->items[i]; - _snk_destroy_image(_snk_make_image_handle(img->slot.id)); - } -} - -static snk_image_desc_t _snk_image_desc_defaults(const snk_image_desc_t* desc) { - SOKOL_ASSERT(desc); - snk_image_desc_t res = *desc; - res.image.id = _snk_def(res.image.id, _snuklear.def_img.id); - res.sampler.id = _snk_def(res.sampler.id, _snuklear.def_smp.id); - return res; -} - -static snk_desc_t _snk_desc_defaults(const snk_desc_t* desc) { - SOKOL_ASSERT(desc); - snk_desc_t res = *desc; - res.max_vertices = _snk_def(res.max_vertices, 65536); - res.dpi_scale = _snk_def(res.dpi_scale, 1.0f); - res.image_pool_size = _snk_def(res.image_pool_size, 256); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void snk_setup(const snk_desc_t* desc) { - SOKOL_ASSERT(desc); - _snk_clear(&_snuklear, sizeof(_snuklear)); - _snuklear.init_cookie = _SNK_INIT_COOKIE; - _snuklear.desc = _snk_desc_defaults(desc); - #if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) - _snuklear.is_osx = _snk_is_osx(); - #endif - // can keep color_format, depth_format and sample_count as is, - // since sokol_gfx.h will do its own default-value handling - - _snk_setup_image_pool(_snuklear.desc.image_pool_size); - - // initialize Nuklear - nk_bool init_res = nk_init_default(&_snuklear.ctx, 0); - SOKOL_ASSERT(1 == init_res); (void)init_res; // silence unused warning in release mode -#if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) - _snuklear.ctx.clip.copy = _snk_clipboard_copy; - _snuklear.ctx.clip.paste = _snk_clipboard_paste; -#endif - - // create sokol-gfx resources - sg_push_debug_group("sokol-nuklear"); - - // vertex buffer - _snuklear.vertex_buffer_size = (size_t)_snuklear.desc.max_vertices * sizeof(_snk_vertex_t); - _snuklear.vbuf = sg_make_buffer(&(sg_buffer_desc){ - .usage = SG_USAGE_STREAM, - .size = _snuklear.vertex_buffer_size, - .label = "sokol-nuklear-vertices" - }); - - // index buffer - _snuklear.index_buffer_size = (size_t)_snuklear.desc.max_vertices * 3 * sizeof(uint16_t); - _snuklear.ibuf = sg_make_buffer(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_INDEXBUFFER, - .usage = SG_USAGE_STREAM, - .size = _snuklear.index_buffer_size, - .label = "sokol-nuklear-indices" - }); - - // default font sampler - _snuklear.font_smp = sg_make_sampler(&(sg_sampler_desc){ - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .wrap_u = SG_WRAP_CLAMP_TO_EDGE, - .wrap_v = SG_WRAP_CLAMP_TO_EDGE, - .label = "sokol-nuklear-font-sampler", - }); - - // default user-image sampler - _snuklear.def_smp = sg_make_sampler(&(sg_sampler_desc){ - .min_filter = SG_FILTER_NEAREST, - .mag_filter = SG_FILTER_NEAREST, - .wrap_u = SG_WRAP_CLAMP_TO_EDGE, - .wrap_v = SG_WRAP_CLAMP_TO_EDGE, - .label = "sokol-nuklear-default-sampler", - }); - - // default font texture - if (!_snuklear.desc.no_default_font) { - nk_font_atlas_init_default(&_snuklear.atlas); - nk_font_atlas_begin(&_snuklear.atlas); - int font_width = 0, font_height = 0; - const void* pixels = nk_font_atlas_bake(&_snuklear.atlas, &font_width, &font_height, NK_FONT_ATLAS_RGBA32); - SOKOL_ASSERT((font_width > 0) && (font_height > 0)); - _snuklear.font_img = sg_make_image(&(sg_image_desc){ - .width = font_width, - .height = font_height, - .pixel_format = SG_PIXELFORMAT_RGBA8, - .data.subimage[0][0] = { - .ptr = pixels, - .size = (size_t)(font_width * font_height) * sizeof(uint32_t) - }, - .label = "sokol-nuklear-font" - }); - _snuklear.default_font = snk_make_image(&(snk_image_desc_t){ - .image = _snuklear.font_img, - .sampler = _snuklear.font_smp, - }); - nk_font_atlas_end(&_snuklear.atlas, snk_nkhandle(_snuklear.default_font), 0); - nk_font_atlas_cleanup(&_snuklear.atlas); - if (_snuklear.atlas.default_font) { - nk_style_set_font(&_snuklear.ctx, &_snuklear.atlas.default_font->handle); - } - } - - // default user image - static uint32_t def_pixels[64]; - memset(def_pixels, 0xFF, sizeof(def_pixels)); - _snuklear.def_img = sg_make_image(&(sg_image_desc){ - .width = 8, - .height = 8, - .pixel_format = SG_PIXELFORMAT_RGBA8, - .data.subimage[0][0] = SG_RANGE(def_pixels), - .label = "sokol-nuklear-default-image", - }); - - // shader - #if defined SOKOL_METAL - const char* vs_entry = "main0"; - const char* fs_entry = "main0"; - #else - const char* vs_entry = "main"; - const char* fs_entry = "main"; - #endif - sg_range vs_bytecode = { .ptr = 0, .size = 0 }; - sg_range fs_bytecode = { .ptr = 0, .size = 0 }; - const char* vs_source = 0; - const char* fs_source = 0; - #if defined(SOKOL_GLCORE33) - vs_source = _snk_vs_source_glsl330; - fs_source = _snk_fs_source_glsl330; - #elif defined(SOKOL_GLES3) - vs_source = _snk_vs_source_glsl300es; - fs_source = _snk_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - vs_bytecode = SG_RANGE(_snk_vs_bytecode_metal_macos); - fs_bytecode = SG_RANGE(_snk_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - vs_bytecode = SG_RANGE(_snk_vs_bytecode_metal_ios); - fs_bytecode = SG_RANGE(_snk_fs_bytecode_metal_ios); - break; - default: - vs_source = _snk_vs_source_metal_sim; - fs_source = _snk_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - vs_bytecode = SG_RANGE(_snk_vs_bytecode_hlsl4); - fs_bytecode = SG_RANGE(_snk_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - vs_source = _snk_vs_source_wgsl; - fs_source = _snk_fs_source_wgsl; - #else - vs_source = _snk_vs_source_dummy; - fs_source = _snk_fs_source_dummy; - #endif - _snuklear.shd = sg_make_shader(&(sg_shader_desc){ - .attrs = { - [0] = { .name = "position", .sem_name = "TEXCOORD", .sem_index = 0 }, - [1] = { .name = "texcoord0", .sem_name = "TEXCOORD", .sem_index = 1 }, - [2] = { .name = "color0", .sem_name = "TEXCOORD", .sem_index = 2 }, - }, - .vs = { - .source = vs_source, - .bytecode = vs_bytecode, - .entry = vs_entry, - .d3d11_target = "vs_4_0", - .uniform_blocks[0] = { - .size = sizeof(_snk_vs_params_t), - .uniforms[0] = { - .name = "vs_params", - .type = SG_UNIFORMTYPE_FLOAT4, - .array_count = 1, - } - }, - }, - .fs = { - .source = fs_source, - .bytecode = fs_bytecode, - .entry = fs_entry, - .d3d11_target = "ps_4_0", - .images[0] = { .used = true, .image_type = SG_IMAGETYPE_2D, .sample_type = SG_IMAGESAMPLETYPE_FLOAT }, - .samplers[0] = { .used = true, .sampler_type = SG_SAMPLERTYPE_FILTERING }, - .image_sampler_pairs[0] = { .used = true, .glsl_name = "tex_smp", .image_slot = 0, .sampler_slot = 0 }, - }, - .label = "sokol-nuklear-shader" - }); - - // pipeline object - _snuklear.pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .attrs = { - [0] = { .offset = offsetof(_snk_vertex_t, pos), .format=SG_VERTEXFORMAT_FLOAT2 }, - [1] = { .offset = offsetof(_snk_vertex_t, uv), .format=SG_VERTEXFORMAT_FLOAT2 }, - [2] = { .offset = offsetof(_snk_vertex_t, col), .format=SG_VERTEXFORMAT_UBYTE4N } - } - }, - .shader = _snuklear.shd, - .index_type = SG_INDEXTYPE_UINT16, - .sample_count = _snuklear.desc.sample_count, - .depth.pixel_format = _snuklear.desc.depth_format, - .colors[0] = { - .pixel_format = _snuklear.desc.color_format, - .write_mask = SG_COLORMASK_RGB, - .blend = { - .enabled = true, - .src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA, - .dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, - } - }, - .label = "sokol-nuklear-pipeline" - }); - - sg_pop_debug_group(); -} - -SOKOL_API_IMPL void snk_shutdown(void) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - nk_free(&_snuklear.ctx); - nk_font_atlas_clear(&_snuklear.atlas); - - // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID - sg_push_debug_group("sokol-nuklear"); - sg_destroy_pipeline(_snuklear.pip); - sg_destroy_shader(_snuklear.shd); - sg_destroy_sampler(_snuklear.font_smp); - sg_destroy_image(_snuklear.font_img); - sg_destroy_sampler(_snuklear.def_smp); - sg_destroy_image(_snuklear.def_img); - sg_destroy_buffer(_snuklear.ibuf); - sg_destroy_buffer(_snuklear.vbuf); - sg_pop_debug_group(); - _snk_destroy_all_images(); - _snk_discard_image_pool(); - _snuklear.init_cookie = 0; -} - -SOKOL_API_IMPL struct nk_context* snk_new_frame(void) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - #if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) - nk_input_begin(&_snuklear.ctx); - if (_snuklear.mouse_did_move) { - nk_input_motion(&_snuklear.ctx, _snuklear.mouse_pos[0], _snuklear.mouse_pos[1]); - _snuklear.mouse_did_move = false; - } - if (_snuklear.mouse_did_scroll) { - nk_input_scroll(&_snuklear.ctx, nk_vec2(_snuklear.mouse_scroll[0], _snuklear.mouse_scroll[1])); - _snuklear.mouse_did_scroll = false; - } - for (int i = 0; i < NK_BUTTON_MAX; i++) { - if (_snuklear.btn_down[i]) { - _snuklear.btn_down[i] = false; - nk_input_button(&_snuklear.ctx, (enum nk_buttons)i, _snuklear.mouse_pos[0], _snuklear.mouse_pos[1], 1); - } else if (_snuklear.btn_up[i]) { - _snuklear.btn_up[i] = false; - nk_input_button(&_snuklear.ctx, (enum nk_buttons)i, _snuklear.mouse_pos[0], _snuklear.mouse_pos[1], 0); - } - } - const size_t char_buffer_len = strlen(_snuklear.char_buffer); - if (char_buffer_len > 0) { - for (size_t i = 0; i < char_buffer_len; i++) { - nk_input_char(&_snuklear.ctx, _snuklear.char_buffer[i]); - } - _snk_clear(_snuklear.char_buffer, NK_INPUT_MAX); - } - for (int i = 0; i < NK_KEY_MAX; i++) { - if (_snuklear.keys_down[i]) { - nk_input_key(&_snuklear.ctx, (enum nk_keys)i, true); - _snuklear.keys_down[i] = 0; - } - if (_snuklear.keys_up[i]) { - nk_input_key(&_snuklear.ctx, (enum nk_keys)i, false); - _snuklear.keys_up[i] = 0; - } - } - nk_input_end(&_snuklear.ctx); - #endif - - nk_clear(&_snuklear.ctx); - return &_snuklear.ctx; -} - -SOKOL_API_IMPL snk_image_t snk_make_image(const snk_image_desc_t* desc) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - SOKOL_ASSERT(desc); - const snk_image_desc_t desc_def = _snk_image_desc_defaults(desc); - snk_image_t img_id = _snk_alloc_image(); - _snk_image_t* img = _snk_lookup_image(img_id.id); - if (img) { - img->slot.state = _snk_init_image(img, &desc_def); - SOKOL_ASSERT((img->slot.state == _SNK_RESOURCESTATE_VALID) || (img->slot.state == _SNK_RESOURCESTATE_FAILED)); - } else { - _SNK_ERROR(IMAGE_POOL_EXHAUSTED); - } - return img_id; -} - -SOKOL_API_IMPL void snk_destroy_image(snk_image_t img_id) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - _snk_destroy_image(img_id); -} - -SOKOL_API_IMPL snk_image_desc_t snk_query_image_desc(snk_image_t img_id) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - _snk_image_t* img = _snk_lookup_image(img_id.id); - if (img) { - return (snk_image_desc_t){ - .image = img->image, - .sampler = img->sampler, - }; - } else { - return (snk_image_desc_t){0}; - } -} - -SOKOL_API_IMPL nk_handle snk_nkhandle(snk_image_t img) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - return (nk_handle) { .id = (int)img.id }; -} - -SOKOL_API_IMPL snk_image_t snk_image_from_nkhandle(nk_handle h) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - return (snk_image_t){ .id = (uint32_t) h.id }; -} - -static void _snk_bind_image_sampler(sg_bindings* bindings, nk_handle h) { - _snk_image_t* img = _snk_lookup_image((uint32_t)h.id); - if (img) { - bindings->fs.images[0] = img->image; - bindings->fs.samplers[0] = img->sampler; - } else { - bindings->fs.images[0] = _snuklear.def_img; - bindings->fs.samplers[0] = _snuklear.def_smp; - } -} - -SOKOL_API_IMPL void snk_render(int width, int height) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct _snk_vertex_t, pos)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct _snk_vertex_t, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct _snk_vertex_t, col)}, - {NK_VERTEX_LAYOUT_END} - }; - struct nk_convert_config cfg = { - .shape_AA = NK_ANTI_ALIASING_ON, - .line_AA = NK_ANTI_ALIASING_ON, - .vertex_layout = vertex_layout, - .vertex_size = sizeof(_snk_vertex_t), - .vertex_alignment = 4, - .circle_segment_count = 22, - .curve_segment_count = 22, - .arc_segment_count = 22, - .global_alpha = 1.0f - }; - - _snuklear.vs_params.disp_size[0] = (float)width; - _snuklear.vs_params.disp_size[1] = (float)height; - - // Setup vert/index buffers and convert - struct nk_buffer cmds, verts, idx; - nk_buffer_init_default(&cmds); - nk_buffer_init_default(&verts); - nk_buffer_init_default(&idx); - nk_convert(&_snuklear.ctx, &cmds, &verts, &idx, &cfg); - - // Check for vertex- and index-buffer overflow, assert in debug-mode, - // otherwise silently skip rendering - const bool vertex_buffer_overflow = nk_buffer_total(&verts) > _snuklear.vertex_buffer_size; - const bool index_buffer_overflow = nk_buffer_total(&idx) > _snuklear.index_buffer_size; - SOKOL_ASSERT(!vertex_buffer_overflow && !index_buffer_overflow); - if (!vertex_buffer_overflow && !index_buffer_overflow) { - - // Setup rendering - sg_update_buffer(_snuklear.vbuf, &(sg_range){ nk_buffer_memory_const(&verts), nk_buffer_total(&verts) }); - sg_update_buffer(_snuklear.ibuf, &(sg_range){ nk_buffer_memory_const(&idx), nk_buffer_total(&idx) }); - const float dpi_scale = _snuklear.desc.dpi_scale; - const int fb_width = (int)(_snuklear.vs_params.disp_size[0] * dpi_scale); - const int fb_height = (int)(_snuklear.vs_params.disp_size[1] * dpi_scale); - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); - sg_apply_pipeline(_snuklear.pip); - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &SG_RANGE(_snuklear.vs_params)); - - // Iterate through the command list, rendering each one - const struct nk_draw_command* cmd = NULL; - int idx_offset = 0; - sg_bindings bindings = { - .vertex_buffers[0] = _snuklear.vbuf, - .index_buffer = _snuklear.ibuf, - .index_buffer_offset = idx_offset - }; - nk_draw_foreach(cmd, &_snuklear.ctx, &cmds) { - if (cmd->elem_count > 0) { - _snk_bind_image_sampler(&bindings, cmd->texture); - sg_apply_bindings(&bindings); - sg_apply_scissor_rectf(cmd->clip_rect.x * dpi_scale, - cmd->clip_rect.y * dpi_scale, - cmd->clip_rect.w * dpi_scale, - cmd->clip_rect.h * dpi_scale, - true); - sg_draw(0, (int)cmd->elem_count, 1); - bindings.index_buffer_offset += (int)cmd->elem_count * (int)sizeof(uint16_t); - } - } - sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); - } - - // Cleanup - nk_buffer_free(&cmds); - nk_buffer_free(&verts); - nk_buffer_free(&idx); -} - -#if !defined(SOKOL_NUKLEAR_NO_SOKOL_APP) -_SOKOL_PRIVATE bool _snk_is_ctrl(uint32_t modifiers) { - if (_snuklear.is_osx) { - return 0 != (modifiers & SAPP_MODIFIER_SUPER); - } else { - return 0 != (modifiers & SAPP_MODIFIER_CTRL); - } -} - -_SOKOL_PRIVATE void _snk_append_char(uint32_t char_code) { - size_t idx = strlen(_snuklear.char_buffer); - if (idxkey_code) { - case SAPP_KEYCODE_C: - if (_snk_is_ctrl(ev->modifiers)) { - return NK_KEY_COPY; - } else { - return NK_KEY_NONE; - } - break; - case SAPP_KEYCODE_X: - if (_snk_is_ctrl(ev->modifiers)) { - return NK_KEY_CUT; - } else { - return NK_KEY_NONE; - } - break; - case SAPP_KEYCODE_A: - if (_snk_is_ctrl(ev->modifiers)) { - return NK_KEY_TEXT_SELECT_ALL; - } else { - return NK_KEY_NONE; - } - break; - case SAPP_KEYCODE_Z: - if (_snk_is_ctrl(ev->modifiers)) { - if (ev->modifiers & SAPP_MODIFIER_SHIFT) { - return NK_KEY_TEXT_REDO; - } else { - return NK_KEY_TEXT_UNDO; - } - } else { - return NK_KEY_NONE; - } - break; - case SAPP_KEYCODE_DELETE: return NK_KEY_DEL; - case SAPP_KEYCODE_ENTER: return NK_KEY_ENTER; - case SAPP_KEYCODE_TAB: return NK_KEY_TAB; - case SAPP_KEYCODE_BACKSPACE: return NK_KEY_BACKSPACE; - case SAPP_KEYCODE_UP: return NK_KEY_UP; - case SAPP_KEYCODE_DOWN: return NK_KEY_DOWN; - case SAPP_KEYCODE_LEFT: return NK_KEY_LEFT; - case SAPP_KEYCODE_RIGHT: return NK_KEY_RIGHT; - case SAPP_KEYCODE_LEFT_SHIFT: return NK_KEY_SHIFT; - case SAPP_KEYCODE_RIGHT_SHIFT: return NK_KEY_SHIFT; - case SAPP_KEYCODE_LEFT_CONTROL: return NK_KEY_CTRL; - case SAPP_KEYCODE_RIGHT_CONTROL: return NK_KEY_CTRL; - default: - return NK_KEY_NONE; - } -} - -SOKOL_API_IMPL bool snk_handle_event(const sapp_event* ev) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - const float dpi_scale = _snuklear.desc.dpi_scale; - switch (ev->type) { - case SAPP_EVENTTYPE_MOUSE_DOWN: - _snuklear.mouse_pos[0] = (int) (ev->mouse_x / dpi_scale); - _snuklear.mouse_pos[1] = (int) (ev->mouse_y / dpi_scale); - switch (ev->mouse_button) { - case SAPP_MOUSEBUTTON_LEFT: - _snuklear.btn_down[NK_BUTTON_LEFT] = true; - break; - case SAPP_MOUSEBUTTON_RIGHT: - _snuklear.btn_down[NK_BUTTON_RIGHT] = true; - break; - case SAPP_MOUSEBUTTON_MIDDLE: - _snuklear.btn_down[NK_BUTTON_MIDDLE] = true; - break; - default: - break; - } - break; - case SAPP_EVENTTYPE_MOUSE_UP: - _snuklear.mouse_pos[0] = (int) (ev->mouse_x / dpi_scale); - _snuklear.mouse_pos[1] = (int) (ev->mouse_y / dpi_scale); - switch (ev->mouse_button) { - case SAPP_MOUSEBUTTON_LEFT: - _snuklear.btn_up[NK_BUTTON_LEFT] = true; - break; - case SAPP_MOUSEBUTTON_RIGHT: - _snuklear.btn_up[NK_BUTTON_RIGHT] = true; - break; - case SAPP_MOUSEBUTTON_MIDDLE: - _snuklear.btn_up[NK_BUTTON_MIDDLE] = true; - break; - default: - break; - } - break; - case SAPP_EVENTTYPE_MOUSE_MOVE: - _snuklear.mouse_pos[0] = (int) (ev->mouse_x / dpi_scale); - _snuklear.mouse_pos[1] = (int) (ev->mouse_y / dpi_scale); - _snuklear.mouse_did_move = true; - break; - case SAPP_EVENTTYPE_MOUSE_ENTER: - case SAPP_EVENTTYPE_MOUSE_LEAVE: - for (int i = 0; i < NK_BUTTON_MAX; i++) { - _snuklear.btn_down[i] = false; - _snuklear.btn_up[i] = false; - } - break; - case SAPP_EVENTTYPE_MOUSE_SCROLL: - _snuklear.mouse_scroll[0] = ev->scroll_x; - _snuklear.mouse_scroll[1] = ev->scroll_y; - _snuklear.mouse_did_scroll = true; - break; - case SAPP_EVENTTYPE_TOUCHES_BEGAN: - _snuklear.btn_down[NK_BUTTON_LEFT] = true; - _snuklear.mouse_pos[0] = (int) (ev->touches[0].pos_x / dpi_scale); - _snuklear.mouse_pos[1] = (int) (ev->touches[0].pos_y / dpi_scale); - _snuklear.mouse_did_move = true; - break; - case SAPP_EVENTTYPE_TOUCHES_MOVED: - _snuklear.mouse_pos[0] = (int) (ev->touches[0].pos_x / dpi_scale); - _snuklear.mouse_pos[1] = (int) (ev->touches[0].pos_y / dpi_scale); - _snuklear.mouse_did_move = true; - break; - case SAPP_EVENTTYPE_TOUCHES_ENDED: - _snuklear.btn_up[NK_BUTTON_LEFT] = true; - _snuklear.mouse_pos[0] = (int) (ev->touches[0].pos_x / dpi_scale); - _snuklear.mouse_pos[1] = (int) (ev->touches[0].pos_y / dpi_scale); - _snuklear.mouse_did_move = true; - break; - case SAPP_EVENTTYPE_TOUCHES_CANCELLED: - _snuklear.btn_up[NK_BUTTON_LEFT] = false; - _snuklear.btn_down[NK_BUTTON_LEFT] = false; - break; - case SAPP_EVENTTYPE_KEY_DOWN: - /* intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED */ - if (_snk_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { - break; - } - /* on web platform, don't forward Ctrl-X, Ctrl-V to the browser */ - if (_snk_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { - sapp_consume_event(); - } - if (_snk_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { - sapp_consume_event(); - } - _snuklear.keys_down[_snk_event_to_nuklearkey(ev)] = true; - break; - case SAPP_EVENTTYPE_KEY_UP: - /* intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED */ - if (_snk_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { - break; - } - /* on web platform, don't forward Ctrl-X, Ctrl-V to the browser */ - if (_snk_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { - sapp_consume_event(); - } - if (_snk_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { - sapp_consume_event(); - } - _snuklear.keys_up[_snk_event_to_nuklearkey(ev)] = true; - break; - case SAPP_EVENTTYPE_CHAR: - if ((ev->char_code >= 32) && - (ev->char_code != 127) && - (0 == (ev->modifiers & (SAPP_MODIFIER_ALT|SAPP_MODIFIER_CTRL|SAPP_MODIFIER_SUPER)))) - { - _snk_append_char(ev->char_code); - } - break; - case SAPP_EVENTTYPE_CLIPBOARD_PASTED: - _snuklear.keys_down[NK_KEY_PASTE] = _snuklear.keys_up[NK_KEY_PASTE] = true; - break; - default: - break; - } - return nk_item_is_any_active(&_snuklear.ctx); -} - -SOKOL_API_IMPL nk_flags snk_edit_string(struct nk_context *ctx, nk_flags flags, char *memory, int *len, int max, nk_plugin_filter filter) { - SOKOL_ASSERT(_SNK_INIT_COOKIE == _snuklear.init_cookie); - nk_flags event = nk_edit_string(ctx, flags, memory, len, max, filter); - if ((event & NK_EDIT_ACTIVATED) && !sapp_keyboard_shown()) { - sapp_show_keyboard(true); - } - if ((event & NK_EDIT_DEACTIVATED) && sapp_keyboard_shown()) { - sapp_show_keyboard(false); - } - return event; -} -#endif // SOKOL_NUKLEAR_NO_SOKOL_APP - -#endif // SOKOL_IMPL diff --git a/source/engine/thirdparty/sokol/util/sokol_shape.h b/source/engine/thirdparty/sokol/util/sokol_shape.h deleted file mode 100644 index d1676dd..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_shape.h +++ /dev/null @@ -1,1431 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_SHAPE_IMPL) -#define SOKOL_SHAPE_IMPL -#endif -#ifndef SOKOL_SHAPE_INCLUDED -/* - sokol_shape.h -- create simple primitive shapes for sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_SHAPE_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Include the following headers before including sokol_shape.h: - - sokol_gfx.h - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_SHAPE_API_DECL- public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_SHAPE_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_shape.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_SHAPE_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - FEATURE OVERVIEW - ================ - sokol_shape.h creates vertices and indices for simple shapes and - builds structs which can be plugged into sokol-gfx resource - creation functions: - - The following shape types are supported: - - - plane - - cube - - sphere (with poles, not geodesic) - - cylinder - - torus (donut) - - Generated vertices look like this: - - typedef struct sshape_vertex_t { - float x, y, z; - uint32_t normal; // packed normal as BYTE4N - uint16_t u, v; // packed uv coords as USHORT2N - uint32_t color; // packed color as UBYTE4N (r,g,b,a); - } sshape_vertex_t; - - Indices are generally 16-bits wide (SG_INDEXTYPE_UINT16) and the indices - are written as triangle-lists (SG_PRIMITIVETYPE_TRIANGLES). - - EXAMPLES: - ========= - - Create multiple shapes into the same vertex- and index-buffer and - render with separate draw calls: - - https://github.com/floooh/sokol-samples/blob/master/sapp/shapes-sapp.c - - Same as the above, but pre-transform shapes and merge them into a single - shape that's rendered with a single draw call. - - https://github.com/floooh/sokol-samples/blob/master/sapp/shapes-transform-sapp.c - - STEP-BY-STEP: - ============= - - Setup an sshape_buffer_t struct with pointers to memory buffers where - generated vertices and indices will be written to: - - ```c - sshape_vertex_t vertices[512]; - uint16_t indices[4096]; - - sshape_buffer_t buf = { - .vertices = { - .buffer = SSHAPE_RANGE(vertices), - }, - .indices = { - .buffer = SSHAPE_RANGE(indices), - } - }; - ``` - - To find out how big those memory buffers must be (in case you want - to allocate dynamically) call the following functions: - - ```c - sshape_sizes_t sshape_plane_sizes(uint32_t tiles); - sshape_sizes_t sshape_box_sizes(uint32_t tiles); - sshape_sizes_t sshape_sphere_sizes(uint32_t slices, uint32_t stacks); - sshape_sizes_t sshape_cylinder_sizes(uint32_t slices, uint32_t stacks); - sshape_sizes_t sshape_torus_sizes(uint32_t sides, uint32_t rings); - ``` - - The returned sshape_sizes_t struct contains vertex- and index-counts - as well as the equivalent buffer sizes in bytes. For instance: - - ```c - sshape_sizes_t sizes = sshape_sphere_sizes(36, 12); - uint32_t num_vertices = sizes.vertices.num; - uint32_t num_indices = sizes.indices.num; - uint32_t vertex_buffer_size = sizes.vertices.size; - uint32_t index_buffer_size = sizes.indices.size; - ``` - - With the sshape_buffer_t struct that was setup earlier, call any - of the shape-builder functions: - - ```c - sshape_buffer_t sshape_build_plane(const sshape_buffer_t* buf, const sshape_plane_t* params); - sshape_buffer_t sshape_build_box(const sshape_buffer_t* buf, const sshape_box_t* params); - sshape_buffer_t sshape_build_sphere(const sshape_buffer_t* buf, const sshape_sphere_t* params); - sshape_buffer_t sshape_build_cylinder(const sshape_buffer_t* buf, const sshape_cylinder_t* params); - sshape_buffer_t sshape_build_torus(const sshape_buffer_t* buf, const sshape_torus_t* params); - ``` - - Note how the sshape_buffer_t struct is both an input value and the - return value. This can be used to append multiple shapes into the - same vertex- and index-buffers (more on this later). - - The second argument is a struct which holds creation parameters. - - For instance to build a sphere with radius 2, 36 "cake slices" and 12 stacks: - - ```c - sshape_buffer_t buf = ...; - buf = sshape_build_sphere(&buf, &(sshape_sphere_t){ - .radius = 2.0f, - .slices = 36, - .stacks = 12, - }); - ``` - - If the provided buffers are big enough to hold all generated vertices and - indices, the "valid" field in the result will be true: - - ```c - assert(buf.valid); - ``` - - The shape creation parameters have "useful defaults", refer to the - actual C struct declarations below to look up those defaults. - - You can also provide additional creation parameters, like a common vertex - color, a debug-helper to randomize colors, tell the shape builder function - to merge the new shape with the previous shape into the same draw-element-range, - or a 4x4 transform matrix to move, rotate and scale the generated vertices: - - ```c - sshape_buffer_t buf = ...; - buf = sshape_build_sphere(&buf, &(sshape_sphere_t){ - .radius = 2.0f, - .slices = 36, - .stacks = 12, - // merge with previous shape into a single element-range - .merge = true, - // set vertex color to red+opaque - .color = sshape_color_4f(1.0f, 0.0f, 0.0f, 1.0f), - // set position to y = 2.0 - .transform = { - .m = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 2.0f, 0.0f, 1.0f }, - } - } - }); - assert(buf.valid); - ``` - - The following helper functions can be used to build a packed - color value or to convert from external matrix types: - - ```c - uint32_t sshape_color_4f(float r, float g, float b, float a); - uint32_t sshape_color_3f(float r, float g, float b); - uint32_t sshape_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); - uint32_t sshape_color_3b(uint8_t r, uint8_t g, uint8_t b); - sshape_mat4_t sshape_mat4(const float m[16]); - sshape_mat4_t sshape_mat4_transpose(const float m[16]); - ``` - - After the shape builder function has been called, the following functions - are used to extract the build result for plugging into sokol_gfx.h: - - ```c - sshape_element_range_t sshape_element_range(const sshape_buffer_t* buf); - sg_buffer_desc sshape_vertex_buffer_desc(const sshape_buffer_t* buf); - sg_buffer_desc sshape_index_buffer_desc(const sshape_buffer_t* buf); - sg_vertex_buffer_layout_state sshape_vertex_buffer_layout_state(void); - sg_vertex_attr_state sshape_position_vertex_attr_state(void); - sg_vertex_attr_state sshape_normal_vertex_attr_state(void); - sg_vertex_attr_state sshape_texcoord_vertex_attr_state(void); - sg_vertex_attr_state sshape_color_vertex_attr_state(void); - ``` - - The sshape_element_range_t struct contains the base-index and number of - indices which can be plugged into the sg_draw() call: - - ```c - sshape_element_range_t elms = sshape_element_range(&buf); - ... - sg_draw(elms.base_element, elms.num_elements, 1); - ``` - - To create sokol-gfx vertex- and index-buffers from the generated - shape data: - - ```c - // create sokol-gfx vertex buffer - sg_buffer_desc vbuf_desc = sshape_vertex_buffer_desc(&buf); - sg_buffer vbuf = sg_make_buffer(&vbuf_desc); - - // create sokol-gfx index buffer - sg_buffer_desc ibuf_desc = sshape_index_buffer_desc(&buf); - sg_buffer ibuf = sg_make_buffer(&ibuf_desc); - ``` - - The remaining functions are used to populate the vertex-layout item - in sg_pipeline_desc, note that these functions don't depend on the - created geometry, they always return the same result: - - ```c - sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .buffers[0] = sshape_vertex_buffer_layout_state(), - .attrs = { - [0] = sshape_position_vertex_attr_state(), - [1] = ssape_normal_vertex_attr_state(), - [2] = sshape_texcoord_vertex_attr_state(), - [3] = sshape_color_vertex_attr_state() - } - }, - ... - }); - ``` - - Note that you don't have to use all generated vertex attributes in the - pipeline's vertex layout, the sg_vertex_buffer_layout_state struct returned - by sshape_vertex_buffer_layout_state() contains the correct vertex stride - to skip vertex components. - - WRITING MULTIPLE SHAPES INTO THE SAME BUFFER - ============================================ - You can merge multiple shapes into the same vertex- and - index-buffers and either render them as a single shape, or - in separate draw calls. - - To build a single shape made of two cubes which can be rendered - in a single draw-call: - - ``` - sshape_vertex_t vertices[128]; - uint16_t indices[16]; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vertices), - .indices.buffer = SSHAPE_RANGE(indices) - }; - - // first cube at pos x=-2.0 (with default size of 1x1x1) - buf = sshape_build_cube(&buf, &(sshape_box_t){ - .transform = { - .m = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - {-2.0f, 0.0f, 0.0f, 1.0f }, - } - } - }); - // ...and append another cube at pos pos=+1.0 - // NOTE the .merge = true, this tells the shape builder - // function to not advance the current shape start offset - buf = sshape_build_cube(&buf, &(sshape_box_t){ - .merge = true, - .transform = { - .m = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - {-2.0f, 0.0f, 0.0f, 1.0f }, - } - } - }); - assert(buf.valid); - - // skipping buffer- and pipeline-creation... - - sshape_element_range_t elms = sshape_element_range(&buf); - sg_draw(elms.base_element, elms.num_elements, 1); - ``` - - To render the two cubes in separate draw-calls, the element-ranges used - in the sg_draw() calls must be captured right after calling the - builder-functions: - - ```c - sshape_vertex_t vertices[128]; - uint16_t indices[16]; - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vertices), - .indices.buffer = SSHAPE_RANGE(indices) - }; - - // build a red cube... - buf = sshape_build_cube(&buf, &(sshape_box_t){ - .color = sshape_color_3b(255, 0, 0) - }); - sshape_element_range_t red_cube = sshape_element_range(&buf); - - // append a green cube to the same vertex-/index-buffer: - buf = sshape_build_cube(&bud, &sshape_box_t){ - .color = sshape_color_3b(0, 255, 0); - }); - sshape_element_range_t green_cube = sshape_element_range(&buf); - - // skipping buffer- and pipeline-creation... - - sg_draw(red_cube.base_element, red_cube.num_elements, 1); - sg_draw(green_cube.base_element, green_cube.num_elements, 1); - ``` - - ...that's about all :) - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2020 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_SHAPE_INCLUDED -#include // size_t, offsetof -#include -#include - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_shape.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_SHAPE_API_DECL) -#define SOKOL_SHAPE_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_SHAPE_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_SHAPE_IMPL) -#define SOKOL_SHAPE_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_SHAPE_API_DECL __declspec(dllimport) -#else -#define SOKOL_SHAPE_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sshape_range is a pointer-size-pair struct used to pass memory - blobs into sokol-shape. When initialized from a value type - (array or struct), use the SSHAPE_RANGE() macro to build - an sshape_range struct. -*/ -typedef struct sshape_range { - const void* ptr; - size_t size; -} sshape_range; - -// disabling this for every includer isn't great, but the warning is also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ -#endif -#if defined(__cplusplus) -#define SSHAPE_RANGE(x) sshape_range{ &x, sizeof(x) } -#else -#define SSHAPE_RANGE(x) (sshape_range){ &x, sizeof(x) } -#endif - -/* a 4x4 matrix wrapper struct */ -typedef struct sshape_mat4_t { float m[4][4]; } sshape_mat4_t; - -/* vertex layout of the generated geometry */ -typedef struct sshape_vertex_t { - float x, y, z; - uint32_t normal; // packed normal as BYTE4N - uint16_t u, v; // packed uv coords as USHORT2N - uint32_t color; // packed color as UBYTE4N (r,g,b,a); -} sshape_vertex_t; - -/* a range of draw-elements (sg_draw(int base_element, int num_element, ...)) */ -typedef struct sshape_element_range_t { - int base_element; - int num_elements; -} sshape_element_range_t; - -/* number of elements and byte size of build actions */ -typedef struct sshape_sizes_item_t { - uint32_t num; // number of elements - uint32_t size; // the same as size in bytes -} sshape_sizes_item_t; - -typedef struct sshape_sizes_t { - sshape_sizes_item_t vertices; - sshape_sizes_item_t indices; -} sshape_sizes_t; - -/* in/out struct to keep track of mesh-build state */ -typedef struct sshape_buffer_item_t { - sshape_range buffer; // pointer/size pair of output buffer - size_t data_size; // size in bytes of valid data in buffer - size_t shape_offset; // data offset of the most recent shape -} sshape_buffer_item_t; - -typedef struct sshape_buffer_t { - bool valid; - sshape_buffer_item_t vertices; - sshape_buffer_item_t indices; -} sshape_buffer_t; - -/* creation parameters for the different shape types */ -typedef struct sshape_plane_t { - float width, depth; // default: 1.0 - uint16_t tiles; // default: 1 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_plane_t; - -typedef struct sshape_box_t { - float width, height, depth; // default: 1.0 - uint16_t tiles; // default: 1 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_box_t; - -typedef struct sshape_sphere_t { - float radius; // default: 0.5 - uint16_t slices; // default: 5 - uint16_t stacks; // default: 4 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_sphere_t; - -typedef struct sshape_cylinder_t { - float radius; // default: 0.5 - float height; // default: 1.0 - uint16_t slices; // default: 5 - uint16_t stacks; // default: 1 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_cylinder_t; - -typedef struct sshape_torus_t { - float radius; // default: 0.5f - float ring_radius; // default: 0.2f - uint16_t sides; // default: 5 - uint16_t rings; // default: 5 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_torus_t; - -/* shape builder functions */ -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_plane(const sshape_buffer_t* buf, const sshape_plane_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_box(const sshape_buffer_t* buf, const sshape_box_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_sphere(const sshape_buffer_t* buf, const sshape_sphere_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_cylinder(const sshape_buffer_t* buf, const sshape_cylinder_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_torus(const sshape_buffer_t* buf, const sshape_torus_t* params); - -/* query required vertex- and index-buffer sizes in bytes */ -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_plane_sizes(uint32_t tiles); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_box_sizes(uint32_t tiles); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_sphere_sizes(uint32_t slices, uint32_t stacks); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_cylinder_sizes(uint32_t slices, uint32_t stacks); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_torus_sizes(uint32_t sides, uint32_t rings); - -/* extract sokol-gfx desc structs and primitive ranges from build state */ -SOKOL_SHAPE_API_DECL sshape_element_range_t sshape_element_range(const sshape_buffer_t* buf); -SOKOL_SHAPE_API_DECL sg_buffer_desc sshape_vertex_buffer_desc(const sshape_buffer_t* buf); -SOKOL_SHAPE_API_DECL sg_buffer_desc sshape_index_buffer_desc(const sshape_buffer_t* buf); -SOKOL_SHAPE_API_DECL sg_vertex_buffer_layout_state sshape_vertex_buffer_layout_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_position_vertex_attr_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_normal_vertex_attr_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_texcoord_vertex_attr_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_color_vertex_attr_state(void); - -/* helper functions to build packed color value from floats or bytes */ -SOKOL_SHAPE_API_DECL uint32_t sshape_color_4f(float r, float g, float b, float a); -SOKOL_SHAPE_API_DECL uint32_t sshape_color_3f(float r, float g, float b); -SOKOL_SHAPE_API_DECL uint32_t sshape_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_SHAPE_API_DECL uint32_t sshape_color_3b(uint8_t r, uint8_t g, uint8_t b); - -/* adapter function for filling matrix struct from generic float[16] array */ -SOKOL_SHAPE_API_DECL sshape_mat4_t sshape_mat4(const float m[16]); -SOKOL_SHAPE_API_DECL sshape_mat4_t sshape_mat4_transpose(const float m[16]); - -#ifdef __cplusplus -} // extern "C" - -// FIXME: C++ helper functions - -#endif -#endif // SOKOL_SHAPE_INCLUDED - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_SHAPE_IMPL -#define SOKOL_SHAPE_IMPL_INCLUDED (1) - -#include // memcpy -#include // sinf, cosf - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-field-initializers" -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#define _sshape_def(val, def) (((val) == 0) ? (def) : (val)) -#define _sshape_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) -#define _sshape_white (0xFFFFFFFF) - -typedef struct { float x, y, z, w; } _sshape_vec4_t; -typedef struct { float x, y; } _sshape_vec2_t; - -static inline float _sshape_clamp(float v) { - if (v < 0.0f) return 0.0f; - else if (v > 1.0f) return 1.0f; - else return v; -} - -static inline uint32_t _sshape_pack_ub4_ubyte4n(uint8_t x, uint8_t y, uint8_t z, uint8_t w) { - return (uint32_t)(((uint32_t)w<<24)|((uint32_t)z<<16)|((uint32_t)y<<8)|x); -} - -static inline uint32_t _sshape_pack_f4_ubyte4n(float x, float y, float z, float w) { - uint8_t x8 = (uint8_t) (x * 255.0f); - uint8_t y8 = (uint8_t) (y * 255.0f); - uint8_t z8 = (uint8_t) (z * 255.0f); - uint8_t w8 = (uint8_t) (w * 255.0f); - return _sshape_pack_ub4_ubyte4n(x8, y8, z8, w8); -} - -static inline uint32_t _sshape_pack_f4_byte4n(float x, float y, float z, float w) { - int8_t x8 = (int8_t) (x * 127.0f); - int8_t y8 = (int8_t) (y * 127.0f); - int8_t z8 = (int8_t) (z * 127.0f); - int8_t w8 = (int8_t) (w * 127.0f); - return _sshape_pack_ub4_ubyte4n((uint8_t)x8, (uint8_t)y8, (uint8_t)z8, (uint8_t)w8); -} - -static inline uint16_t _sshape_pack_f_ushortn(float x) { - return (uint16_t) (x * 65535.0f); -} - -static inline _sshape_vec4_t _sshape_vec4(float x, float y, float z, float w) { - _sshape_vec4_t v = { x, y, z, w }; - return v; -} - -static inline _sshape_vec4_t _sshape_vec4_norm(_sshape_vec4_t v) { - float l = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); - if (l != 0.0f) { - return _sshape_vec4(v.x/l, v.y/l, v.z/l, v.w/l); - } - else { - return _sshape_vec4(0.0f, 1.0f, 0.0f, 0.0f); - } -} - -static inline _sshape_vec2_t _sshape_vec2(float x, float y) { - _sshape_vec2_t v = { x, y }; - return v; -} - -static bool _sshape_mat4_isnull(const sshape_mat4_t* m) { - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - if (0.0f != m->m[y][x]) { - return false; - } - } - } - return true; -} - -static sshape_mat4_t _sshape_mat4_identity(void) { - sshape_mat4_t m = { - { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 1.0f } - } - }; - return m; -} - -static _sshape_vec4_t _sshape_mat4_mul(const sshape_mat4_t* m, _sshape_vec4_t v) { - _sshape_vec4_t res = { - m->m[0][0]*v.x + m->m[1][0]*v.y + m->m[2][0]*v.z + m->m[3][0]*v.w, - m->m[0][1]*v.x + m->m[1][1]*v.y + m->m[2][1]*v.z + m->m[3][1]*v.w, - m->m[0][2]*v.x + m->m[1][2]*v.y + m->m[2][2]*v.z + m->m[3][2]*v.w, - m->m[0][3]*v.x + m->m[1][3]*v.y + m->m[2][3]*v.z + m->m[3][3]*v.w - }; - return res; -} - -static uint32_t _sshape_plane_num_vertices(uint32_t tiles) { - return (tiles + 1) * (tiles + 1); -} - -static uint32_t _sshape_plane_num_indices(uint32_t tiles) { - return tiles * tiles * 2 * 3; -} - -static uint32_t _sshape_box_num_vertices(uint32_t tiles) { - return (tiles + 1) * (tiles + 1) * 6; -} - -static uint32_t _sshape_box_num_indices(uint32_t tiles) { - return tiles * tiles * 2 * 6 * 3; -} - -static uint32_t _sshape_sphere_num_vertices(uint32_t slices, uint32_t stacks) { - return (slices + 1) * (stacks + 1); -} - -static uint32_t _sshape_sphere_num_indices(uint32_t slices, uint32_t stacks) { - return ((2 * slices * stacks) - (2 * slices)) * 3; -} - -static uint32_t _sshape_cylinder_num_vertices(uint32_t slices, uint32_t stacks) { - return (slices + 1) * (stacks + 5); -} - -static uint32_t _sshape_cylinder_num_indices(uint32_t slices, uint32_t stacks) { - return ((2 * slices * stacks) + (2 * slices)) * 3; -} - -static uint32_t _sshape_torus_num_vertices(uint32_t sides, uint32_t rings) { - return (sides + 1) * (rings + 1); -} - -static uint32_t _sshape_torus_num_indices(uint32_t sides, uint32_t rings) { - return sides * rings * 2 * 3; -} - -static bool _sshape_validate_buffer_item(const sshape_buffer_item_t* item, uint32_t build_size) { - if (0 == item->buffer.ptr) { - return false; - } - if (0 == item->buffer.size) { - return false; - } - if ((item->data_size + build_size) > item->buffer.size) { - return false; - } - if (item->shape_offset > item->data_size) { - return false; - } - return true; -} - -static bool _sshape_validate_buffer(const sshape_buffer_t* buf, uint32_t num_vertices, uint32_t num_indices) { - if (!_sshape_validate_buffer_item(&buf->vertices, num_vertices * sizeof(sshape_vertex_t))) { - return false; - } - if (!_sshape_validate_buffer_item(&buf->indices, num_indices * sizeof(uint16_t))) { - return false; - } - return true; -} - -static void _sshape_advance_offset(sshape_buffer_item_t* item) { - item->shape_offset = item->data_size; -} - -static uint16_t _sshape_base_index(const sshape_buffer_t* buf) { - return (uint16_t) (buf->vertices.data_size / sizeof(sshape_vertex_t)); -} - -static sshape_plane_t _sshape_plane_defaults(const sshape_plane_t* params) { - sshape_plane_t res = *params; - res.width = _sshape_def_flt(res.width, 1.0f); - res.depth = _sshape_def_flt(res.depth, 1.0f); - res.tiles = _sshape_def(res.tiles, 1); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_box_t _sshape_box_defaults(const sshape_box_t* params) { - sshape_box_t res = *params; - res.width = _sshape_def_flt(res.width, 1.0f); - res.height = _sshape_def_flt(res.height, 1.0f); - res.depth = _sshape_def_flt(res.depth, 1.0f); - res.tiles = _sshape_def(res.tiles, 1); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_sphere_t _sshape_sphere_defaults(const sshape_sphere_t* params) { - sshape_sphere_t res = *params; - res.radius = _sshape_def_flt(res.radius, 0.5f); - res.slices = _sshape_def(res.slices, 5); - res.stacks = _sshape_def(res.stacks, 4); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_cylinder_t _sshape_cylinder_defaults(const sshape_cylinder_t* params) { - sshape_cylinder_t res = *params; - res.radius = _sshape_def_flt(res.radius, 0.5f); - res.height = _sshape_def_flt(res.height, 1.0f); - res.slices = _sshape_def(res.slices, 5); - res.stacks = _sshape_def(res.stacks, 1); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_torus_t _sshape_torus_defaults(const sshape_torus_t* params) { - sshape_torus_t res = *params; - res.radius = _sshape_def_flt(res.radius, 0.5f); - res.ring_radius = _sshape_def_flt(res.ring_radius, 0.2f); - res.sides = _sshape_def_flt(res.sides, 5); - res.rings = _sshape_def_flt(res.rings, 5); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static void _sshape_add_vertex(sshape_buffer_t* buf, _sshape_vec4_t pos, _sshape_vec4_t norm, _sshape_vec2_t uv, uint32_t color) { - size_t offset = buf->vertices.data_size; - SOKOL_ASSERT((offset + sizeof(sshape_vertex_t)) <= buf->vertices.buffer.size); - buf->vertices.data_size += sizeof(sshape_vertex_t); - sshape_vertex_t* v_ptr = (sshape_vertex_t*) ((uint8_t*)buf->vertices.buffer.ptr + offset); - v_ptr->x = pos.x; - v_ptr->y = pos.y; - v_ptr->z = pos.z; - v_ptr->normal = _sshape_pack_f4_byte4n(norm.x, norm.y, norm.z, norm.w); - v_ptr->u = _sshape_pack_f_ushortn(uv.x); - v_ptr->v = _sshape_pack_f_ushortn(uv.y); - v_ptr->color = color; -} - -static void _sshape_add_triangle(sshape_buffer_t* buf, uint16_t i0, uint16_t i1, uint16_t i2) { - size_t offset = buf->indices.data_size; - SOKOL_ASSERT((offset + 3*sizeof(uint16_t)) <= buf->indices.buffer.size); - buf->indices.data_size += 3*sizeof(uint16_t); - uint16_t* i_ptr = (uint16_t*) ((uint8_t*)buf->indices.buffer.ptr + offset); - i_ptr[0] = i0; - i_ptr[1] = i1; - i_ptr[2] = i2; -} - -static uint32_t _sshape_rand_color(uint32_t* xorshift_state) { - // xorshift32 - uint32_t x = *xorshift_state; - x ^= x<<13; - x ^= x>>17; - x ^= x<<5; - *xorshift_state = x; - - // rand => bright color with alpha 1.0 - x |= 0xFF000000; - return x; - -} - -/*=== PUBLIC API FUNCTIONS ===================================================*/ -SOKOL_API_IMPL uint32_t sshape_color_4f(float r, float g, float b, float a) { - return _sshape_pack_f4_ubyte4n(_sshape_clamp(r), _sshape_clamp(g), _sshape_clamp(b), _sshape_clamp(a)); -} - -SOKOL_API_IMPL uint32_t sshape_color_3f(float r, float g, float b) { - return _sshape_pack_f4_ubyte4n(_sshape_clamp(r), _sshape_clamp(g), _sshape_clamp(b), 1.0f); -} - -SOKOL_API_IMPL uint32_t sshape_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return _sshape_pack_ub4_ubyte4n(r, g, b, a); -} - -SOKOL_API_IMPL uint32_t sshape_color_3b(uint8_t r, uint8_t g, uint8_t b) { - return _sshape_pack_ub4_ubyte4n(r, g, b, 255); -} - -SOKOL_API_IMPL sshape_mat4_t sshape_mat4(const float m[16]) { - sshape_mat4_t res; - memcpy(&res.m[0][0], &m[0], 64); - return res; -} - -SOKOL_API_IMPL sshape_mat4_t sshape_mat4_transpose(const float m[16]) { - sshape_mat4_t res; - for (int c = 0; c < 4; c++) { - for (int r = 0; r < 4; r++) { - res.m[r][c] = m[c*4 + r]; - } - } - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_plane_sizes(uint32_t tiles) { - SOKOL_ASSERT(tiles >= 1); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_plane_num_vertices(tiles); - res.indices.num = _sshape_plane_num_indices(tiles); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_box_sizes(uint32_t tiles) { - SOKOL_ASSERT(tiles >= 1); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_box_num_vertices(tiles); - res.indices.num = _sshape_box_num_indices(tiles); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_sphere_sizes(uint32_t slices, uint32_t stacks) { - SOKOL_ASSERT((slices >= 3) && (stacks >= 2)); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_sphere_num_vertices(slices, stacks); - res.indices.num = _sshape_sphere_num_indices(slices, stacks); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_cylinder_sizes(uint32_t slices, uint32_t stacks) { - SOKOL_ASSERT((slices >= 3) && (stacks >= 1)); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_cylinder_num_vertices(slices, stacks); - res.indices.num = _sshape_cylinder_num_indices(slices, stacks); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_torus_sizes(uint32_t sides, uint32_t rings) { - SOKOL_ASSERT((sides >= 3) && (rings >= 3)); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_torus_num_vertices(sides, rings); - res.indices.num = _sshape_torus_num_indices(sides, rings); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -/* - Geometry layout for plane (4 tiles): - +--+--+--+--+ - |\ |\ |\ |\ | - | \| \| \| \| - +--+--+--+--+ 25 vertices (tiles + 1) * (tiles + 1) - |\ |\ |\ |\ | 32 triangles (tiles + 1) * (tiles + 1) * 2 - | \| \| \| \| - +--+--+--+--+ - |\ |\ |\ |\ | - | \| \| \| \| - +--+--+--+--+ - |\ |\ |\ |\ | - | \| \| \| \| - +--+--+--+--+ -*/ -SOKOL_API_IMPL sshape_buffer_t sshape_build_plane(const sshape_buffer_t* in_buf, const sshape_plane_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_plane_t params = _sshape_plane_defaults(in_params); - const uint32_t num_vertices = _sshape_plane_num_vertices(params.tiles); - const uint32_t num_indices = _sshape_plane_num_indices(params.tiles); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - // write vertices - uint32_t rand_seed = 0x12345678; - const float x0 = -params.width * 0.5f; - const float z0 = params.depth * 0.5f; - const float dx = params.width / params.tiles; - const float dz = -params.depth / params.tiles; - const float duv = 1.0f / params.tiles; - _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, _sshape_vec4(0.0f, 1.0f, 0.0f, 0.0f))); - for (uint32_t ix = 0; ix <= params.tiles; ix++) { - for (uint32_t iz = 0; iz <= params.tiles; iz++) { - const _sshape_vec4_t pos = _sshape_vec4(x0 + dx*ix, 0.0f, z0 + dz*iz, 1.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(duv*ix, duv*iz); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - - // write indices - for (uint16_t j = 0; j < params.tiles; j++) { - for (uint16_t i = 0; i < params.tiles; i++) { - const uint16_t i0 = start_index + (j * (params.tiles + 1)) + i; - const uint16_t i1 = i0 + 1; - const uint16_t i2 = i0 + params.tiles + 1; - const uint16_t i3 = i2 + 1; - _sshape_add_triangle(&buf, i0, i1, i3); - _sshape_add_triangle(&buf, i0, i3, i2); - } - } - return buf; -} - -SOKOL_API_IMPL sshape_buffer_t sshape_build_box(const sshape_buffer_t* in_buf, const sshape_box_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_box_t params = _sshape_box_defaults(in_params); - const uint32_t num_vertices = _sshape_box_num_vertices(params.tiles); - const uint32_t num_indices = _sshape_box_num_indices(params.tiles); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - // build vertices - uint32_t rand_seed = 0x12345678; - const float x0 = -params.width * 0.5f; - const float x1 = params.width * 0.5f; - const float y0 = -params.height * 0.5f; - const float y1 = params.height * 0.5f; - const float z0 = -params.depth * 0.5f; - const float z1 = params.depth * 0.5f; - const float dx = params.width / params.tiles; - const float dy = params.height / params.tiles; - const float dz = params.depth / params.tiles; - const float duv = 1.0f / params.tiles; - - // bottom/top vertices - for (uint32_t top_bottom = 0; top_bottom < 2; top_bottom++) { - _sshape_vec4_t pos = _sshape_vec4(0.0f, (0==top_bottom) ? y0:y1, 0.0f, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4(0.0f, (0==top_bottom) ? -1.0f:1.0f, 0.0f, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - for (uint32_t ix = 0; ix <= params.tiles; ix++) { - pos.x = (0==top_bottom) ? (x0 + dx * ix) : (x1 - dx * ix); - for (uint32_t iz = 0; iz <= params.tiles; iz++) { - pos.z = z0 + dz * iz; - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(ix * duv, iz * duv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - } - - // left/right vertices - for (uint32_t left_right = 0; left_right < 2; left_right++) { - _sshape_vec4_t pos = _sshape_vec4((0==left_right) ? x0:x1, 0.0f, 0.0f, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4((0==left_right) ? -1.0f:1.0f, 0.0f, 0.0f, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - for (uint32_t iy = 0; iy <= params.tiles; iy++) { - pos.y = (0==left_right) ? (y1 - dy * iy) : (y0 + dy * iy); - for (uint32_t iz = 0; iz <= params.tiles; iz++) { - pos.z = z0 + dz * iz; - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(iy * duv, iz * duv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - } - - // front/back vertices - for (uint32_t front_back = 0; front_back < 2; front_back++) { - _sshape_vec4_t pos = _sshape_vec4(0.0f, 0.0f, (0==front_back) ? z0:z1, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4(0.0f, 0.0f, (0==front_back) ? -1.0f:1.0f, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - for (uint32_t ix = 0; ix <= params.tiles; ix++) { - pos.x = (0==front_back) ? (x1 - dx * ix) : (x0 + dx * ix); - for (uint32_t iy = 0; iy <= params.tiles; iy++) { - pos.y = y0 + dy * iy; - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(ix * duv, iy * duv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - } - - // build indices - const uint16_t verts_per_face = (params.tiles + 1) * (params.tiles + 1); - for (uint16_t face = 0; face < 6; face++) { - uint16_t face_start_index = start_index + face * verts_per_face; - for (uint16_t j = 0; j < params.tiles; j++) { - for (uint16_t i = 0; i < params.tiles; i++) { - const uint16_t i0 = face_start_index + (j * (params.tiles + 1)) + i; - const uint16_t i1 = i0 + 1; - const uint16_t i2 = i0 + params.tiles + 1; - const uint16_t i3 = i2 + 1; - _sshape_add_triangle(&buf, i0, i1, i3); - _sshape_add_triangle(&buf, i0, i3, i2); - } - } - } - return buf; -} - -/* - Geometry layout for spheres is as follows (for 5 slices, 4 stacks): - - + + + + + + north pole - |\ |\ |\ |\ |\ - | \| \| \| \| \ - +--+--+--+--+--+ 30 vertices (slices + 1) * (stacks + 1) - |\ |\ |\ |\ |\ | 30 triangles (2 * slices * stacks) - (2 * slices) - | \| \| \| \| \| 2 orphaned vertices - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ - \ |\ |\ |\ |\ | - \| \| \| \| \| - + + + + + + south pole -*/ -SOKOL_API_IMPL sshape_buffer_t sshape_build_sphere(const sshape_buffer_t* in_buf, const sshape_sphere_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_sphere_t params = _sshape_sphere_defaults(in_params); - const uint32_t num_vertices = _sshape_sphere_num_vertices(params.slices, params.stacks); - const uint32_t num_indices = _sshape_sphere_num_indices(params.slices, params.stacks); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - uint32_t rand_seed = 0x12345678; - const float pi = 3.14159265358979323846f; - const float two_pi = 2.0f * pi; - const float du = 1.0f / params.slices; - const float dv = 1.0f / params.stacks; - - // generate vertices - for (uint32_t stack = 0; stack <= params.stacks; stack++) { - const float stack_angle = (pi * stack) / params.stacks; - const float sin_stack = sinf(stack_angle); - const float cos_stack = cosf(stack_angle); - for (uint32_t slice = 0; slice <= params.slices; slice++) { - const float slice_angle = (two_pi * slice) / params.slices; - const float sin_slice = sinf(slice_angle); - const float cos_slice = cosf(slice_angle); - const _sshape_vec4_t norm = _sshape_vec4(-sin_slice * sin_stack, cos_stack, cos_slice * sin_stack, 0.0f); - const _sshape_vec4_t pos = _sshape_vec4(norm.x * params.radius, norm.y * params.radius, norm.z * params.radius, 1.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(1.0f - slice * du, 1.0f - stack * dv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - - // generate indices - { - // north-pole triangles - const uint16_t row_a = start_index; - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice, row_b + slice + 1); - } - } - // stack triangles - for (uint16_t stack = 1; stack < params.stacks - 1; stack++) { - const uint16_t row_a = start_index + stack * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_a + slice + 1); - _sshape_add_triangle(&buf, row_a + slice, row_b + slice, row_b + slice + 1); - } - } - { - // south-pole triangles - const uint16_t row_a = start_index + (params.stacks - 1) * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_a + slice + 1); - } - } - return buf; -} - -/* - Geometry for cylinders is as follows (2 stacks, 5 slices): - - + + + + + + - |\ |\ |\ |\ |\ - | \| \| \| \| \ - +--+--+--+--+--+ - +--+--+--+--+--+ 42 vertices (2 wasted) (slices + 1) * (stacks + 5) - |\ |\ |\ |\ |\ | 30 triangles (2 * slices * stacks) + (2 * slices) - | \| \| \| \| \| - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ - +--+--+--+--+--+ - \ |\ |\ |\ |\ | - \| \| \| \| \| - + + + + + + -*/ -static void _sshape_build_cylinder_cap_pole(sshape_buffer_t* buf, const sshape_cylinder_t* params, float pos_y, float norm_y, float du, float v, uint32_t* rand_seed) { - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms->transform, _sshape_vec4(0.0f, norm_y, 0.0f, 0.0f))); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms->transform, _sshape_vec4(0.0f, pos_y, 0.0f, 1.0f)); - for (uint32_t slice = 0; slice <= params->slices; slice++) { - const _sshape_vec2_t uv = _sshape_vec2(slice * du, 1.0f - v); - const uint32_t color = params->random_colors ? _sshape_rand_color(rand_seed) : params->color; - _sshape_add_vertex(buf, tpos, tnorm, uv, color); - } -} - -static void _sshape_build_cylinder_cap_ring(sshape_buffer_t* buf, const sshape_cylinder_t* params, float pos_y, float norm_y, float du, float v, uint32_t* rand_seed) { - const float two_pi = 2.0f * 3.14159265358979323846f; - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms->transform, _sshape_vec4(0.0f, norm_y, 0.0f, 0.0f))); - for (uint32_t slice = 0; slice <= params->slices; slice++) { - const float slice_angle = (two_pi * slice) / params->slices; - const float sin_slice = sinf(slice_angle); - const float cos_slice = cosf(slice_angle); - const _sshape_vec4_t pos = _sshape_vec4(sin_slice * params->radius, pos_y, cos_slice * params->radius, 1.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms->transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(slice * du, 1.0f - v); - const uint32_t color = params->random_colors ? _sshape_rand_color(rand_seed) : params->color; - _sshape_add_vertex(buf, tpos, tnorm, uv, color); - } -} - -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_cylinder(const sshape_buffer_t* in_buf, const sshape_cylinder_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_cylinder_t params = _sshape_cylinder_defaults(in_params); - const uint32_t num_vertices = _sshape_cylinder_num_vertices(params.slices, params.stacks); - const uint32_t num_indices = _sshape_cylinder_num_indices(params.slices, params.stacks); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - uint32_t rand_seed = 0x12345678; - const float two_pi = 2.0f * 3.14159265358979323846f; - const float du = 1.0f / params.slices; - const float dv = 1.0f / (params.stacks + 2); - const float y0 = params.height * 0.5f; - const float y1 = -params.height * 0.5f; - const float dy = params.height / params.stacks; - - // generate vertices - _sshape_build_cylinder_cap_pole(&buf, ¶ms, y0, 1.0f, du, 0.0f, &rand_seed); - _sshape_build_cylinder_cap_ring(&buf, ¶ms, y0, 1.0f, du, dv, &rand_seed); - for (uint32_t stack = 0; stack <= params.stacks; stack++) { - const float y = y0 - dy * stack; - const float v = dv * stack + dv; - for (uint32_t slice = 0; slice <= params.slices; slice++) { - const float slice_angle = (two_pi * slice) / params.slices; - const float sin_slice = sinf(slice_angle); - const float cos_slice = cosf(slice_angle); - const _sshape_vec4_t pos = _sshape_vec4(sin_slice * params.radius, y, cos_slice * params.radius, 1.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec4_t norm = _sshape_vec4(sin_slice, 0.0f, cos_slice, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - const _sshape_vec2_t uv = _sshape_vec2(slice * du, 1.0f - v); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - _sshape_build_cylinder_cap_ring(&buf, ¶ms, y1, -1.0f, du, 1.0f - dv, &rand_seed); - _sshape_build_cylinder_cap_pole(&buf, ¶ms, y1, -1.0f, du, 1.0f, &rand_seed); - - // generate indices - { - // top-cap indices - const uint16_t row_a = start_index; - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_b + slice); - } - } - // shaft triangles - for (uint16_t stack = 0; stack < params.stacks; stack++) { - const uint16_t row_a = start_index + (stack + 2) * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_a + slice + 1, row_b + slice + 1); - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_b + slice); - } - } - { - // bottom-cap indices - const uint16_t row_a = start_index + (params.stacks + 3) * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_a + slice + 1, row_b + slice + 1); - } - } - return buf; -} - -/* - Geometry layout for torus (sides = 4, rings = 5): - - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ 30 vertices (sides + 1) * (rings + 1) - |\ |\ |\ |\ |\ | 40 triangles (2 * sides * rings) - | \| \| \| \| \| - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ -*/ -SOKOL_API_IMPL sshape_buffer_t sshape_build_torus(const sshape_buffer_t* in_buf, const sshape_torus_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_torus_t params = _sshape_torus_defaults(in_params); - const uint32_t num_vertices = _sshape_torus_num_vertices(params.sides, params.rings); - const uint32_t num_indices = _sshape_torus_num_indices(params.sides, params.rings); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - uint32_t rand_seed = 0x12345678; - const float two_pi = 2.0f * 3.14159265358979323846f; - const float dv = 1.0f / params.sides; - const float du = 1.0f / params.rings; - - // generate vertices - for (uint32_t side = 0; side <= params.sides; side++) { - const float phi = (side * two_pi) / params.sides; - const float sin_phi = sinf(phi); - const float cos_phi = cosf(phi); - for (uint32_t ring = 0; ring <= params.rings; ring++) { - const float theta = (ring * two_pi) / params.rings; - const float sin_theta = sinf(theta); - const float cos_theta = cosf(theta); - - // torus surface position - const float spx = sin_theta * (params.radius - (params.ring_radius * cos_phi)); - const float spy = sin_phi * params.ring_radius; - const float spz = cos_theta * (params.radius - (params.ring_radius * cos_phi)); - - // torus position with ring-radius zero (for normal computation) - const float ipx = sin_theta * params.radius; - const float ipy = 0.0f; - const float ipz = cos_theta * params.radius; - - const _sshape_vec4_t pos = _sshape_vec4(spx, spy, spz, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4(spx - ipx, spy - ipy, spz - ipz, 0.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - const _sshape_vec2_t uv = _sshape_vec2(ring * du, 1.0f - side * dv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - - // generate indices - for (uint16_t side = 0; side < params.sides; side++) { - const uint16_t row_a = start_index + side * (params.rings + 1); - const uint16_t row_b = row_a + params.rings + 1; - for (uint16_t ring = 0; ring < params.rings; ring++) { - _sshape_add_triangle(&buf, row_a + ring, row_a + ring + 1, row_b + ring + 1); - _sshape_add_triangle(&buf, row_a + ring, row_b + ring + 1, row_b + ring); - } - } - return buf; -} - -SOKOL_API_IMPL sg_buffer_desc sshape_vertex_buffer_desc(const sshape_buffer_t* buf) { - SOKOL_ASSERT(buf && buf->valid); - sg_buffer_desc desc = { 0 }; - if (buf->valid) { - desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - desc.usage = SG_USAGE_IMMUTABLE; - desc.data.ptr = buf->vertices.buffer.ptr; - desc.data.size = buf->vertices.data_size; - } - return desc; -} - -SOKOL_API_IMPL sg_buffer_desc sshape_index_buffer_desc(const sshape_buffer_t* buf) { - SOKOL_ASSERT(buf && buf->valid); - sg_buffer_desc desc = { 0 }; - if (buf->valid) { - desc.type = SG_BUFFERTYPE_INDEXBUFFER; - desc.usage = SG_USAGE_IMMUTABLE; - desc.data.ptr = buf->indices.buffer.ptr; - desc.data.size = buf->indices.data_size; - } - return desc; -} - -SOKOL_SHAPE_API_DECL sshape_element_range_t sshape_element_range(const sshape_buffer_t* buf) { - SOKOL_ASSERT(buf && buf->valid); - SOKOL_ASSERT(buf->indices.shape_offset < buf->indices.data_size); - SOKOL_ASSERT(0 == (buf->indices.shape_offset & (sizeof(uint16_t) - 1))); - SOKOL_ASSERT(0 == (buf->indices.data_size & (sizeof(uint16_t) - 1))); - sshape_element_range_t range = { 0 }; - range.base_element = (int) (buf->indices.shape_offset / sizeof(uint16_t)); - if (buf->valid) { - range.num_elements = (int) ((buf->indices.data_size - buf->indices.shape_offset) / sizeof(uint16_t)); - } - else { - range.num_elements = 0; - } - return range; -} - -SOKOL_API_IMPL sg_vertex_buffer_layout_state sshape_vertex_buffer_layout_state(void) { - sg_vertex_buffer_layout_state state = { 0 }; - state.stride = sizeof(sshape_vertex_t); - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_position_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, x); - state.format = SG_VERTEXFORMAT_FLOAT3; - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_normal_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, normal); - state.format = SG_VERTEXFORMAT_BYTE4N; - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_texcoord_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, u); - state.format = SG_VERTEXFORMAT_USHORT2N; - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_color_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, color); - state.format = SG_VERTEXFORMAT_UBYTE4N; - return state; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -#endif // SOKOL_SHAPE_IMPL diff --git a/source/engine/thirdparty/sokol/util/sokol_spine.h b/source/engine/thirdparty/sokol/util/sokol_spine.h deleted file mode 100644 index f76d2bf..0000000 --- a/source/engine/thirdparty/sokol/util/sokol_spine.h +++ /dev/null @@ -1,5941 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_SPINE_IMPL) -#define SOKOL_SPINE_IMPL -#endif -#ifndef SOKOL_SPINE_INCLUDED -/* - sokol_spine.h -- a sokol-gfx renderer for the spine-c runtime - (see https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-c) - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_SPINE_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - The following defines are used by the implementation to select the - platform-specific embedded shader code (these are the same defines as - used by sokol_gfx.h and sokol_app.h): - - SOKOL_GLCORE33 - SOKOL_GLES3 - SOKOL_D3D11 - SOKOL_METAL - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_SPINE_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_SPINE_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - If sokol_spine.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_SPINE_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before including sokol_spine.h: - - sokol_gfx.h - - Include the following headers before include the sokol_spine.h *IMPLEMENTATION*: - - spine/spine.h - - You'll also need to compile and link with the spine-c runtime: - - https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-c/spine-c - - - FEATURE OVERVIEW - ================ - sokol_spine.h is a sokol-gfx renderer and 'handle wrapper' for Spine - (http://en.esotericsoftware.com/spine-in-depth) on top of the - spine-c runtime: http://en.esotericsoftware.com/spine-c (source code: - https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-c/spine-c). - - The sokol-gfx renderer allows to manage multiple contexts for rendering - Spine scenes into different sokol-gfx render passes (similar to sokol-gl and - sokol-debugtext), allows to split rendering into layers to mix Spine - rendering with other rendering operations, and it automatically batches - adjacent draw calls for Spine objects that use the same texture and in the - same layer. - - Sokol-spine wraps 'raw' spine-c objects with tagged index handles. This - eliminates the risk of memory corruption via dangling pointers. Any - API calls involving invalid objects either result in a no-op, or - in a proper error. - - The sokol-spine API exposes four 'base object types', and a number of - 'subobject types' which are owned by base objects. - - Base object types are: - - - sspine_atlas: A wrapper around a spine-c spAtlas object, each spAtlas - object owns at least one spAtlasPage object, and each spAtlasPage object - owns exactly one sokol-gfx image object. - - - sspine_skeleton: A skeleton object requires an atlas object for creation, - and is a wrapper around one spine-c spSkeletonData and one - spAnimationStateData object. both contain the shared static data for - individual spine instances - - - sspine_instance: Instance objects are created from skeleton objects. - Instances are the objects that are actually getting rendered. Each instance - tracks its own transformation and animation state, but otherwise just - references shared data of the skeleton object it was created from. An - sspine_instance object is a wrapper around one spine-c spSkeleton, - spAnimationState and spSkeletonClipping object each. - - - sspine_skinset: Skin-set objects are collections of skins which define - the look of an instance. Some Spine scenes consist of combinable skins - (for instance a human character could offer different skins for different - types of clothing, hats, scarfs, shirts, pants, and so on..., and a skin - set would represent a specific outfit). - - Subobject types allow to inspect and manipulate Spine objects in more detail: - - - sspine_anim: Each skeleton object usually offers animations which can - then be scheduled and mixed on an instance. - - - sspine_bone: Bone objects are the hierarchical transform nodes of - a skeleton. The sokol-spine API allows both to inspect the shared - static bone attributes of an sspine_skeleton object, as well as - inspecting and manipulating the per-instance bone attributes - on an sspine_instance object. - - - sspine_event: A running Spine animation may fire 'events' at certain - positions in time (for instance a 'footstep' event whenever a foot - hits the ground). Events can be used to play sound effects (or visual - effects) at the right time. - - - sspine_iktarget: Allows to set the target position for a group of - bones controlled by inverse kinematics. - - There's a couple of other subobject types which are mostly useful to - inspect the interior structure of skeletons. Those will be explained - in detail further down. - - MINIMAL API USAGE OVERVIEW - ========================== - During initialization: - - - call sspine_setup() after initializing sokol-gfx - - create an atlas object from a Spine atlas file with sspine_make_atlas() - - load and initialize the sokol-gfx image objects referenced by the atlas - - create a skeleton object from a Spine skeleton file with sspine_make_skeleton() - - create at least one instance object with sspine_make_instance() - - In the frame loop, outside of sokol-gfx render passes: - - - if needed, move instances around with sspine_set_position() - - if needed, schedule new animations with sspine_set_animation() and sspine_add_animation() - - each frame, advance the current instance animation state with sspine_update_instance() - - each frame, render instances with sspine_draw_instance_in_layer(), this just records - vertices, indices and draw commands into internal buffers, but does no actual - sokol-gfx rendering - - In the frame loop, inside a sokol-gfx render pass: - - - call sspine_draw_layer() to draw all previously recorded instances in a specific layer - - On shutdown: - - - call sspine_shutdown(), ideally before shutting down sokol-gfx - - QUICKSTART STEP BY STEP - ======================= - For a simple demo program using sokol_app.h, sokol_gfx.h and sokol_fetch.h, - see here: [TODO: add link to spine-simple-sapp wasm demo]. - - - sokol_spine.h must be included after sokol_gfx.h (this is true both - for the declaration and implementation): - - #include "sokol_gfx.h" - #include "sokol_spine.h" - - - ...and sokol_gfx.h must be initialized before sokol_spine.h: - - sg_setup(&(sg_desc){ ... }); - sspine_setup(&(sspine_desc){ ... }); - - - You should always provide a logging callback to sokol-spine, otherwise - no warning or errors will be logged. The easiest way is to use sokol_log.h - for this: - - #include "sokol_log.h" - - sspine_setup(&(sspine_desc){ - .logger = { - .func = slog_func - } - }); - - - You can tweak the memory usage of sokol-spine by limiting or expanding the - maximum number of vertices, draw commands and pool sizes: - - sspine_setup(&(sspine_desc){ - .max_vertices = 1024, // default: (1<<16) = 65536 - .max_commands = 128, // default: (1<<14) = 16384 - .context_pool_size = 1, // default: 4 - .atlas_pool_size = 1, // default: 64 - .skeleton_pool_size = 1, // default: 64 - .skinset_pool_size = 1, // default: 64 - .instance_pool_size = 16, // default: 1024 - .logger = { - .func = slog_func, - } - }); - - Sokol-spine uses 32-bit vertex-indices for rendering - (SG_INDEXTYPE_UINT32), so that the maximum number of Spine vertices - in a frame isn't limited to (1<<16). - - - You can override memory allocation and logging with your own - functions, this is explained in detail further down: - - sspine_setup(&(sspine_desc){ - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - }, - .logger = { - .log_func = my_log_func, - .user_data = ..., - } - }); - - - After initialization, the first thing you need is an sspine_atlas object. - Sokol-spine doesn't concern itself with file IO, it expects all external - data to be provided as pointer/size pairs: - - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = { - .ptr = ..., // pointer to Spine atlas file data in memory - .size = ..., // atlas file data size in bytes - } - }); - assert(sspine_atlas_valid(atlas)); - - If you load the atlas data asynchronously, you can still run your - per-frame rendering code without waiting for the atlas data to be loaded - and the atlas to be created. This works because calling sokol-spine - functions with 'invalid' object handles is a valid no-op. - - - Optionally you can override some or all of the atlas texture creation parameters: - - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = { ... }, - .overrides = { - .min_filter = SG_FILTER_NEAREST, - .mag_filter = SG_FILTER_NEAREST, - .mipmap_filter = SG_FILTER_NONE, - .wrap_u = SG_WRAP_MIRROR, - .wrap_v = SG_WRAP_MIRROR, - .premul_alpha_enabled = ..., - .premul_alpha_disabled = ..., - } - }); - - - The atlas file itself doesn't contain any texture data, it only contains - filenames of the required textures. Sokol-spine has already allocated - a sokol-gfx sg_image and sg_sample handle for each required texture, but the - actual loading and initialization must be performed by user code: - - // iterate over atlas textures and initialize sokol-gfx image objects - // with existing handles - const int num = sspine_num_images(atlas); - for (int i = 0; i < num; i++) { - const sspine_image img = sspine_image_by_index(atlas, i); - const sspine_image_info img_info = sspine_get_image_info(img); - assert(img_info.valid); - assert(!img_info.filename.truncated); - - // the filename is now in img_info.filename.cstr, 'somehow' - // load and decode the image data into memory, and then - // initialize the sokol-gfx image from the existing sg_image handle - // in img_info.sgimage: - sg_init_image(img_info.sgimage, &(sg_image_desc){ - .width = ..., - .height = ..., - .pixel_format = ..., - .data.subimage[0][0] = { - .ptr = ..., // pointer to decoded image pixel data - .size = ..., // size of decoded image pixel data in bytes - } - }); - - // ...and same procedure for the sampler object - sg_init_sampler(img_info.sgsampler, &(sg_image_desc){ - .min_filter = img_info.min_filter, - .mag_filter = img_info.mag_filter, - .mipmap_filter = img_info.mipmap_filter, - .wrap_u = img_info.wrap_u, - .wrap_v = img_info.wrap_v, - }); - } - - If you load the image data asynchronously, you can still simply start rendering - before the image data is loaded. This works because sokol-gfx will silently drop - any rendering operations that involve 'incomplete' objects. - - - Once an atlas object has been created (independently from loading any image data), - an sspine_skeleton object is needed next. This requires a valid atlas object - handle as input, and a pointer to the Spine skeleton file data loaded into memory. - - Spine skeleton files come in two flavours: binary or json, for binary data, - a ptr/size pair must be provided: - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, // atlas must be a valid sspine_atlas handle - .binary_data = { - .ptr = ..., // pointer to binary skeleton data in memory - .size = ..., // size of binary skeleton data in bytes - } - }); - assert(sspine_skeleton_valid(skeleton)); - - For JSON skeleton file data, the data must be provided as a zero-terminated C string: - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .json_data = ..., // JSON skeleton data as zero-terminated(!) C-string - }); - - Like with all sokol-spine objects, if you load the skeleton data asynchronously - and only then create a skeleton object, you can already start rendering before - the data is loaded and the Spine objects have been created. Any operations - involving 'incomplete' handles will be dropped. - - - You can pre-scale the Spine scene size, and you can provide a default cross-fade - duration for animation mixing: - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .binary_data = { ... }, - .prescale = 0.5f, // scale to half-size - .anim_default_mix = 0.2f, // default anim mixing cross-fade duration 0.2 seconds - }); - - - Once the skeleton object has been created, it's finally time to create one or many instance objects. - If you want to independently render and animate the 'same' Spine object many times in a frame, - you should only create one sspine_skeleton object, and then as many sspine_instance object - as needed from the shared skeleton object: - - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = skeleton, // must be a valid skeleton handle - }); - assert(sspine_instance_valid(instance)); - - After creation, the sspine_instance will have a 'default skin' set as its appearance. - - - To set the position of an instance: - - sspine_set_position(inst, (sspine_vec2){ .x=..., .y=... }); - - Sokol-spine doesn't define a specific unit (like pixels or meters), instead the - rendering coordinate system is defined later at 'render time'. - - - To schedule an initial looping animation by its name: - - // first lookup up the animation by name on the skeleton: - sspine_anim anim = sspine_anim_by_name(skeleton, "walk"); - assert(sspine_anim_valid(anim)); - - // then schedule the animation on the instance, on mixer track 0, as looping: - sspine_set_animation(instance, anim, 0, true); - - Scheduling and mixing animations will be explained in more detail further down. - - - To advance and mix instance animations: - - sspine_update_instance(instance, delta_time_in_seconds); - - Usually you'd call this each frame for each active instance with the - frame duration in seconds. - - - Now it's finally time to 'render' the instance at its current position and - animation state: - - sspine_draw_instance_in_layer(instance, 0); - - Instances are generally rendered into numbered virtual 'render layers' (in this - case, layer 0). Layers are useful for interleaving sokol-spine rendering - with other rendering commands (like background and foreground tile maps, - sprites or text). - - - It's important to note that no actual sokol-gfx rendering happens in - sspine_draw_instance_in_layer(), instead only vertices, indices and - draw commands are recorded into internal memory buffes. - - - The only sokol-spine function which *must* (and should) be called inside - a sokol-gfx rendering pass is sspine_draw_layer(). - - This renders all draw commands that have been recorded previously in a - specific layer via sspine_draw_instance_in_layer(). - - const sspine_layer_transform tform = { ... }; - - sg_begin_default_pass(...); - sspine_draw_layer(0, tform); - sg_end_pass(); - sg_commit(); - - IMPORTANT: DO *NOT* MIX any calls to sspine_draw_instance_in_layer() - with sspine_draw_layer(), as this will confuse the internal draw command - recording. Ideally, move all sokol-gfx pass rendering (including all - sspine_draw_layer() calls) towards the end of the frame, separate from - any other sokol-spine calls. - - The sspine_layer_transform struct defines the layer's screen space coordinate - system. For instance to map Spine coordinates to framebuffer pixels, with the - origin in the screen center, you'd setup the layer transform like this: - - const float width = sapp_widthf(); - const float height = sapp_heightf(); - const sspine_layer_transform tform = { - .size = { .x = width, .y = height }, - .origin = { .x = width * 0.5f, .y = height * 0.5f }, - }; - - With this pixel mapping, the Spine scene would *not* scale with window size, - which often is not very useful. Instead it might make more sense to render - to a fixed 'virtual' resolution, for instance 1024 * 768: - - const sspine_layer_transform tform = { - .size = { .x = 1024.0f, .y = 768.0f }, - .origin = { .x = 512.0f, .y = 384.0f }, - }; - - How to configure a virtual resolution with a fixed aspect ratio is - left as an exercise to the reader ;) - - - That's it for basic sokol-spine setup and rendering. Any existing objects - will automatically be cleaned up when calling sspine_shutdown(), this - should be called before shutting down sokol-gfx, but this is not required: - - sspine_shutdown(); - sg_shutdown(); - - - You can explicitly destroy the base object types if you don't need them - any longer. This will cause the underlying spine-c objects to be - freed and the memory to be returned to the operating system: - - sspine_destroy_instance(instance); - sspine_destroy_skinset(skinset); - sspine_destroy_skeleton(skeleton); - sspine_destroy_atlas(atlas); - - You can destroy these objects in any order without causing memory corruption - issues. Instead any dependent object handles will simply become invalid (e.g. - if you destroy an atlas object, all skeletons and instances created from - this atlas will 'technically' still exist, but their handles will resolve to - 'invalid' and all sokol-spine calls involving these handles will silently fail). - - For instance: - - // create an atlas, skeleton and instance - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ ... }); - assert(sspine_atlas_valid(atlas)); - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - ... - }); - assert(sspine_skeleton_valid(skeleton)); - - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = skeleton, - }); - assert(sspine_instance_valid(instance)); - - // destroy the atlas object: - sspine_destroy_atlas(atlas); - - // the skeleton and instance handle should now be invalid, but - // otherwise, nothing bad will happen: - if (!sspine_skeleton_valid(skeleton)) { - ... - } - if (!sspine_instance_valid(instance)) { - ... - } - - RENDERER DETAILS - ================ - Any rendering related work happens in the functions sspine_draw_instance_in_layer() and - sspine_draw_layer(). - - sspine_draw_instance_in_layer() will result in vertices, indices and internal - draw commands which will be recorded into internal memory buffers (e.g. - no sokol-gfx functions will be called here). - - If possible, batching will be performed by merging a new draw command with - the previously recorded draw command. For two draw commands to be merged, - the following conditions must be tru: - - - rendering needs to go into the same layer - - the same atlas texture must be used - - the blend mode must be compatible (the Spine blending modes - 'normal' and 'additive' can be merged, but not 'multiply') - - the same premultiplied alpha mode must be used - - To make the most out of batching: - - - use Spine objects which only have a single atlas texture - and blend mode across all slots - - group sspine_draw_instance_in_layer() calls by layer - - After all instances have been 'rendered' (or rather: recorded) into layers, - the actually rendering happens inside a sokol-gfx pass by calling the - function sspine_draw_layer() for each layer in 'z order' (e.g. the layer - index doesn't matter for z-ordering, only the order how sspine_draw_layer() is - called). - - Only the first call to sspine_draw_layer() in a frame will copy the recorded - vertices and indices into sokol-gfx buffers. - - Each call to sspine_draw_layer() will iterate over all recorded (and - hopefully well-batched) draw commands, skip any draw commands with a - non-matching layer index, and draw only those with a matching layer by - calling: - - - if the pipeline object has changed: - - sg_apply_pipeline() - - sg_apply_uniforms() for the vertex stage - - if the atlas texture has changed: - - sg_apply_bindings() - - if the premultiplied-alpha mode has changed: - - sg_apply_uniforms() for the fragment stage - - and finally sg_draw() - - The main purpose of render layers is to mix Spine rendering with other - render operations. In the not too distant future, the same render layer idea - will also be implemented at least for sokol-gl and sokol-debugtext. - - FIXME: does this section need more details about layer transforms? - - RENDERING WITH CONTEXTS - ======================= - At first glance, render contexts may look like more heavy-weight - render layers, but they serve a different purpose: they are useful - if Spine rendering needs to happen in different sokol-gfx render passes - with different pixel formats and MSAA sample counts. - - All Spine rendering happens within a context, even you don't call any - of the context API functions, in this case, an internal 'default context' - will be used. - - Each context has its own internal vertex-, index- and command buffer and - all context state is completely independent from any other contexts. - - To create a new context object, call: - - sspine_context ctx = sspine_make_context(&(sspine_context_desc){ - .max_vertices = ..., - .max_commands = ..., - .color_format = SG_PIXELFORMAT_..., - .depth_format = SG_PIXELFORMAT_..., - .sample_count = ..., - .color_write_mask = SG_COLORMASK_..., - }); - - The color_format, depth_format and sample_count items must be compatible - with the sokol-gfx render pass you're going to render into. - - If you omit the color_format, depth_format and sample_count designators, - the new context will be compatible with the sokol-gfx default pass - (which is most likely not what you want, unless your offscreen render passes - exactly match the default pass attributes). - - Once a context has been created, it can be made active with: - - sspine_set_context(ctx); - - To set the default context again: - - sspine_set_contxt(sspine_default_context()); - - ...and to get the currently active context: - - sspine_context cur_ctx = sspine_get_context(); - - The currently active context only matter for two functions: - - - sspine_draw_instance_in_layer() - - sspine_draw_layer() - - Alternatively you can bypass the currently set context with these - alternative functions: - - - sspine_context_draw_layer_in_instance(ctx, ...) - - sspine_context_draw_layer(ctx, ...) - - These explicitly take a context argument, completely ignore - and don't change the active context. - - You can query some information about a context with the function: - - sspine_context_info info = ssgpine_get_context_info(ctx); - - This returns the current number of recorded vertices, indices - and draw commands. - - RESOURCE STATES: - ================ - Similar to sokol-gfx, you can query the current 'resource state' of Spine - objects: - - sspine_resource_state sspine_get_atlas_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_skeleton_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_instance_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_skinset_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_context_resource_state(sspine_atlas atlas); - - This returns one of - - - SSPINE_RESOURCE_VALID: the object is valid and ready to use - - SSPINE_RESOURCE_FAILED: the object creation has failed - - SSPINE_RESOURCE_INVALID: the object or one of its dependencies is - invalid, it either no longer exists, or the handle hasn't been - initialized with a call to one of the object creation functions - - MISC HELPER FUNCTIONS: - ====================== - There's a couple of helper functions which don't fit into a big enough category - of their own: - - You can ask a skeleton for the atlas it has been created from: - - sspine_atlas atlas = sspine_get_skeleton_atlas(skeleton); - - ...and likewise, ask an instance for the skeleton it has been created from: - - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - - ...and finally you can convert a layer transform struct into a 4x4 projection - matrix that's memory-layout compatible with sokol-gl: - - const sspine_layer_transform tform = { ... }; - const sspine_mat4 proj = sspine_layer_transform_to_mat4(&tform); - sgl_matrix_mode_projection(); - sgl_load_matrix(proj.m); - - ANIMATIONS - ========== - Animations have their own handle type sspine_anim. A valid sspine_anim - handle is either obtained by looking up an animation by name from a skeleton: - - sspine_anim anim = sspine_anim_by_name(skeleton, "walk"); - - ...or by index: - - sspine_anim anim = sspine_anim_by_index(skeleton, 0); - - The returned anim handle will be invalid if an animation of that name doesn't - exist, or the provided index is out-of-range: - - if (!sspine_anim_is_valid(anim)) { - // animation handle is not valid - } - - An animation handle will also become invalid when the skeleton object it was - created is destroyed, or otherwise becomes invalid. - - You can iterate over all animations in a skeleton: - - const int num_anims = sspine_num_anims(skeleton); - for (int anim_index = 0; anim_index < num_anims; anim_index++) { - sspine_anim anim = sspine_anim_by_index(skeleton, anim_index); - ... - } - - Since sspine_anim is a 'fat handle' (it houses a skeleton handle and an index), - there's a helper function which checks if two anim handles are equal: - - if (sspine_anim_equal(anim0, anim1)) { - ... - } - - To query information about an animation: - - const sspine_anim_info info = sspine_get_anim_info(anim); - if (info.valid) { - printf("index: %d, duration: %f, name: %s", info.index, info.duration, info.name.cstr); - } - - Scheduling and mixing animations is controlled through the following functions: - - void sspine_clear_animation_tracks(sspine_instance instance); - void sspine_clear_animation_track(sspine_instance instance, int track_index); - void sspine_set_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop); - void sspine_add_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop, float delay); - void sspine_set_empty_animation(sspine_instance instance, int track_index, float mix_duration); - void sspine_add_empty_animation(sspine_instance instance, int track_index, float mix_duration, float delay); - - Please refer to the spine-c documentation to get an idea what these functions do: - - http://en.esotericsoftware.com/spine-c#Applying-animations - - EVENTS - ====== - For a general idea of Spine events, see here: http://esotericsoftware.com/spine-events - - After calling sspine_update_instance() to advance the currently configured animations, - you can poll for triggered events like this: - - const int num_triggered_events = sspine_num_triggered_events(instance); - for (int i = 0; i < num_triggered_events; i++) { - const sspine_triggered_event_info info = sspine_get_triggered_event_info(instance, i); - if (info.valid) { - ... - } - } - - The returned sspine_triggered_event_info struct gives you the current runtime properties - of the event (in case the event has keyed properties). For the actual list of event - properties please see the actual sspine_triggered_event_info struct declaration. - - It's also possible to inspect the static event definition on a skeleton, this works - the same as iterating through animations. You can lookup an event by name, - get the number of events, lookup an event by its index, and get detailed - information about an event: - - int sspine_num_events(sspine_skeleton skeleton); - sspine_event sspine_event_by_name(sspine_skeleton skeleton, const char* name); - sspine_event sspine_event_by_index(sspine_skeleton skeleton, int index); - bool sspine_event_valid(sspine_event event); - bool sspine_event_equal(sspine_event first, sspine_event second); - sspine_event_info sspine_get_event_info(sspine_event event); - - (FIXME: shouldn't the event info struct contains an sspine_anim handle?) - - IK TARGETS - ========== - The IK target function group allows to iterate over the IK targets that have been - defined on a skeleton, find an IK target by name, get detailed information about - an IK target, and most importantly, set the world space position of an IK target - which updates the position of all bones influenced by the IK target: - - int sspine_num_iktargets(sspine_skeleton skeleton); - sspine_iktarget sspine_iktarget_by_name(sspine_skeleton skeleton, const char* name); - sspine_iktarget sspine_iktarget_by_index(sspine_skeleton skeleton, int index); - bool sspine_iktarget_valid(sspine_iktarget iktarget); - bool sspine_iktarget_equal(sspine_iktarget first, sspine_iktarget second); - sspine_iktarget_info sspine_get_iktarget_info(sspine_iktarget iktarget); - void sspine_set_iktarget_world_pos(sspine_instance instance, sspine_iktarget iktarget, sspine_vec2 world_pos); - - BONES - ===== - Skeleton bones are wrapped with an sspine_bone handle which can be created from - a skeleton handle, and either a bone name: - - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - assert(sspine_bone_valid(bone)); - - ...or a bone index: - - sspine_bone bone = sspine_bone_by_index(skeleton, 0); - assert(sspine_bone_valid(bone)); - - ...to iterate over all bones of a skeleton and query information about each - bone: - - const int num_bones = sspine_num_bones(skeleton); - for (int bone_index = 0; bone_index < num_bones; bone_index++) { - sspine_bone bone = sspine_bone_by_index(skeleton, bone_index); - const sspine_bone_info info = sspine_get_bone_info(skeleton, bone); - if (info.valid) { - ... - } - } - - The sspine_bone_info struct provides the shared, static bone state in the skeleton (like - the name, a parent bone handle, bone length, pose transform and a color attribute), - but doesn't contain any dynamic information of per-instance bones. - - To manipulate the per-instance bone attributes use the following setter functions: - - void sspine_set_bone_transform(sspine_instance instance, sspine_bone bone, const sspine_bone_transform* transform); - void sspine_set_bone_position(sspine_instance instance, sspine_bone bone, sspine_vec2 position); - void sspine_set_bone_rotation(sspine_instance instance, sspine_bone bone, float rotation); - void sspine_set_bone_scale(sspine_instance instance, sspine_bone bone, sspine_vec2 scale); - void sspine_set_bone_shear(sspine_instance instance, sspine_bone bone, sspine_vec2 shear); - - ...and to query the per-instance bone attributes, the following getters: - - sspine_bone_transform sspine_get_bone_transform(sspine_instance instance, sspine_bone bone); - sspine_vec2 sspine_get_bone_position(sspine_instance instance, sspine_bone bone); - float sspine_get_bone_rotation(sspine_instance instance, sspine_bone bone); - sspine_vec2 sspine_get_bone_scale(sspine_instance instance, sspine_bone bone); - sspine_vec2 sspine_get_bone_shear(sspine_instance instance, sspine_bone bone); - - These functions all work in the local bone coordinate system (relative to a bone's parent bone). - - To transform positions between bone-local and global space use the following helper functions: - - sspine_vec2 sspine_bone_local_to_world(sspine_instance instance, sspine_bone bone, sspine_vec2 local_pos); - sspine_vec2 sspine_bone_world_to_local(sspine_instance instance, sspine_bone bone, sspine_vec2 world_pos); - - ...and as a convenience, there's a helper function which obtains the bone position in global space - directly: - - sspine_vec2 sspine_get_bone_world_position(sspine_instance instance, sspine_bone bone); - - SKINS AND SKINSETS - ================== - Skins are named pieces of geometry which can be turned on and off, what makes Spine skins a bit - confusing is that they are hierarchical. A skin can itself be a collection of other skins. Setting - the 'root skin' will also make all 'child skins' visible. In sokol-spine collections of skins are - managed through dedicated 'skin set' objects. Under the hood they create a 'root skin' where the - skins of the skin set are attached to, but from the outside it just looks like a 'flat' collection - of skins without the tricky hierarchical management. - - Like other 'subobjects', skin handles can be obtained by the skin name from a skeleton handle: - - sspine_skin skin = sspine_skin_by_name(skeleton, "jacket"); - assert(sspine_skin_valid(skin)); - - ...or by a skin index: - - sspine_skin skin = sspine_skin_by_index(skeleton, 0); - assert(sspine_skin_valid(skin)); - - ...you can iterate over all skins of a skeleton and query some information about the skin: - - const int num_skins = sspine_num_skins(skeleton); - for (int skin_index = 0; skin_index < num_skins; skin_index++) { - sspine_skin skin = sspine_skin_by_index(skin_index); - sspine_skin_info info = sspine_get_skin_info(skin); - if (info.valid) { - ... - } - } - - Currently, the only useful query item is the skin name though. - - To make a skin visible on an instance, just call: - - sspine_set_skin(instance, skin); - - ...this will first deactivate the previous skin before setting a new skin. - - A more powerful way to configure the skin visibility is through 'skin sets'. Skin - sets are simply flat collections of skins which should be made visible at once. - A new skin set is created like this: - - sspine_skinset skinset = sspine_make_skinset(&(sspine_skinset_desc){ - .skeleton = skeleton, - .skins = { - sspine_skin_by_name(skeleton, "blue-jacket"), - sspine_skin_by_name(skeleton, "green-pants"), - sspine_skin_by_name(skeleton, "blonde-hair"), - ... - } - }); - assert(sspine_skinset_valid(skinset)) - - ...then simply set the skinset on an instance to reconfigure the appearance - of the instance: - - sspine_set_skinset(instance, skinset); - - The functions sspine_set_skinset() and sspine_set_skin() will cancel each other. - Calling sspine_set_skinset() deactivates the effect of sspine_set_skin() and - vice versa. - - - ERROR REPORTING AND LOGGING - =========================== - To get any logging information at all you need to provide a logging callback in the setup call, - the easiest way is to use sokol_log.h: - - #include "sokol_log.h" - - sspine_setup(&(sspine_desc){ .logger.func = slog_func }); - - To override logging with your own callback, first write a logging function like this: - - void my_log(const char* tag, // e.g. 'sspine' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SSPINE_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_spine.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-spine like this: - - sspine_setup(&(sspine_desc){ - .logger = { - .func = my_log, - .user_data = my_user_data, - } - }); - - The provided logging function must be reentrant (e.g. be callable from - different threads). - - If you don't want to provide your own custom logger it is highly recommended to use - the standard logger in sokol_log.h instead, otherwise you won't see any warnings or - errors. - - - MEMORY ALLOCATION OVERRIDE - ========================== - You can override the memory allocation functions at initialization time - like this: - - void* my_alloc(size_t size, void* user_data) { - return malloc(size); - } - - void my_free(void* ptr, void* user_data) { - free(ptr); - } - - ... - sspine_setup(&(sspine_desc){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_gfx.h - itself though, not any allocations in OS libraries. - - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2022 Andre Weissflog - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from the - use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ -#define SOKOL_SPINE_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_spine.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_SPINE_API_DECL) -#define SOKOL_SPINE_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_SPINE_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_SPINE_IMPL) -#define SOKOL_SPINE_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_SPINE_API_DECL __declspec(dllimport) -#else -#define SOKOL_SPINE_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SSPINE_INVALID_ID = 0, - SSPINE_MAX_SKINSET_SKINS = 32, - SSPINE_MAX_STRING_SIZE = 61, // see sspine_string struct -}; - -typedef struct sspine_context { uint32_t id; } sspine_context; -typedef struct sspine_atlas { uint32_t id; } sspine_atlas; -typedef struct sspine_skeleton { uint32_t id; } sspine_skeleton; -typedef struct sspine_instance { uint32_t id; } sspine_instance; -typedef struct sspine_skinset { uint32_t id; } sspine_skinset; - -typedef struct sspine_image { uint32_t atlas_id; int index; } sspine_image; -typedef struct sspine_atlas_page { uint32_t atlas_id; int index; } sspine_atlas_page; -typedef struct sspine_anim { uint32_t skeleton_id; int index; } sspine_anim; -typedef struct sspine_bone { uint32_t skeleton_id; int index; } sspine_bone; -typedef struct sspine_slot { uint32_t skeleton_id; int index; } sspine_slot; -typedef struct sspine_event { uint32_t skeleton_id; int index; } sspine_event; -typedef struct sspine_iktarget { uint32_t skeleton_id; int index; } sspine_iktarget; -typedef struct sspine_skin { uint32_t skeleton_id; int index; } sspine_skin; - -typedef struct sspine_range { const void* ptr; size_t size; } sspine_range; -typedef struct sspine_vec2 { float x, y; } sspine_vec2; -typedef struct sspine_mat4 { float m[16]; } sspine_mat4; -typedef sg_color sspine_color; - -typedef struct sspine_string { - bool valid; - bool truncated; - uint8_t len; - char cstr[SSPINE_MAX_STRING_SIZE]; -} sspine_string; - -typedef enum sspine_resource_state { - SSPINE_RESOURCESTATE_INITIAL, - SSPINE_RESOURCESTATE_ALLOC, - SSPINE_RESOURCESTATE_VALID, - SSPINE_RESOURCESTATE_FAILED, - SSPINE_RESOURCESTATE_INVALID, - _SSPINE_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF -} sspine_resource_state; - -// log item codes via x-macro magic -#define _SSPINE_LOG_ITEMS \ - _SSPINE_LOGITEM_XMACRO(OK, "Ok")\ - _SSPINE_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed")\ - _SSPINE_LOGITEM_XMACRO(CONTEXT_POOL_EXHAUSTED, "context pool exhausted (adjust via sspine_desc.context_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(ATLAS_POOL_EXHAUSTED, "atlas pool exhausted (adjust via sspine_desc.atlas_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_POOL_EXHAUSTED, "skeleton pool exhausted (adjust via sspine_desc.skeleton_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_POOL_EXHAUSTED, "skinset pool exhausted (adjust via sspine_desc.skinset_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_POOL_EXHAUSTED, "instance pool exhausted (adjust via sspine_desc.instance_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(CANNOT_DESTROY_DEFAULT_CONTEXT, "cannot destroy default context")\ - _SSPINE_LOGITEM_XMACRO(ATLAS_DESC_NO_DATA, "no data provided in sspine_atlas_desc.data")\ - _SSPINE_LOGITEM_XMACRO(SPINE_ATLAS_CREATION_FAILED, "spAtlas_create() failed")\ - _SSPINE_LOGITEM_XMACRO(SG_ALLOC_IMAGE_FAILED, "sg_alloc_image() failed")\ - _SSPINE_LOGITEM_XMACRO(SG_ALLOC_SAMPLER_FAILED, "sg_alloc_sampler() failed")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_DESC_NO_DATA, "no data provided in sspine_skeleton_desc.json_data or .binary_data")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_DESC_NO_ATLAS, "no atlas object provided in sspine_skeleton_desc.atlas")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_ATLAS_NOT_VALID, "sspine_skeleton_desc.atlas is not in valid state")\ - _SSPINE_LOGITEM_XMACRO(CREATE_SKELETON_DATA_FROM_JSON_FAILED, "spSkeletonJson_readSkeletonData() failed")\ - _SSPINE_LOGITEM_XMACRO(CREATE_SKELETON_DATA_FROM_BINARY_FAILED, "spSkeletonBinary_readSkeletonData() failed")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_DESC_NO_SKELETON, "no skeleton object provided in sspine_skinset_desc.skeleton")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_SKELETON_NOT_VALID, "sspine_skinset_desc.skeleton is not in valid state")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_INVALID_SKIN_HANDLE, "invalid skin handle in sspine_skinset_desc.skins[]")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_DESC_NO_SKELETON, "no skeleton object provided in sspine_instance_desc.skeleton")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_SKELETON_NOT_VALID, "sspine_instance_desc.skeleton is not in valid state")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_ATLAS_NOT_VALID, "skeleton's atlas object no longer valid via sspine_instance_desc.skeleton")\ - _SSPINE_LOGITEM_XMACRO(SPINE_SKELETON_CREATION_FAILED, "spSkeleton_create() failed")\ - _SSPINE_LOGITEM_XMACRO(SPINE_ANIMATIONSTATE_CREATION_FAILED, "spAnimationState_create() failed")\ - _SSPINE_LOGITEM_XMACRO(SPINE_SKELETONCLIPPING_CREATION_FAILED, "spSkeletonClipping_create() failed")\ - _SSPINE_LOGITEM_XMACRO(COMMAND_BUFFER_FULL, "command buffer full (adjust via sspine_desc.max_commands)")\ - _SSPINE_LOGITEM_XMACRO(VERTEX_BUFFER_FULL, "vertex buffer (adjust via sspine_desc.max_vertices)")\ - _SSPINE_LOGITEM_XMACRO(INDEX_BUFFER_FULL, "index buffer full (adjust via sspine_desc.max_vertices)")\ - _SSPINE_LOGITEM_XMACRO(STRING_TRUNCATED, "a string has been truncated")\ - _SSPINE_LOGITEM_XMACRO(ADD_COMMIT_LISTENER_FAILED, "sg_add_commit_listener() failed")\ - -#define _SSPINE_LOGITEM_XMACRO(item,msg) SSPINE_LOGITEM_##item, -typedef enum sspine_log_item { - _SSPINE_LOG_ITEMS -} sspine_log_item; -#undef _SSPINE_LOGITEM_XMACRO - -typedef struct sspine_layer_transform { - sspine_vec2 size; - sspine_vec2 origin; -} sspine_layer_transform; - -typedef struct sspine_bone_transform { - sspine_vec2 position; - float rotation; // in degrees - sspine_vec2 scale; - sspine_vec2 shear; // in degrees -} sspine_bone_transform; - -typedef struct sspine_context_desc { - int max_vertices; - int max_commands; - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_color_mask color_write_mask; -} sspine_context_desc; - -typedef struct sspine_context_info { - int num_vertices; // current number of vertices - int num_indices; // current number of indices - int num_commands; // current number of commands -} sspine_context_info; - -typedef struct sspine_image_info { - bool valid; - sg_image sgimage; - sg_sampler sgsampler; - sg_filter min_filter; - sg_filter mag_filter; - sg_filter mipmap_filter; - sg_wrap wrap_u; - sg_wrap wrap_v; - int width; - int height; - bool premul_alpha; - sspine_string filename; -} sspine_image_info; - -typedef struct sspine_atlas_overrides { - sg_filter min_filter; - sg_filter mag_filter; - sg_filter mipmap_filter; - sg_wrap wrap_u; - sg_wrap wrap_v; - bool premul_alpha_enabled; - bool premul_alpha_disabled; -} sspine_atlas_overrides; - -typedef struct sspine_atlas_desc { - sspine_range data; - sspine_atlas_overrides override; -} sspine_atlas_desc; - -typedef struct sspine_atlas_page_info { - bool valid; - sspine_atlas atlas; - sspine_image_info image; - sspine_atlas_overrides overrides; -} sspine_atlas_page_info; - -typedef struct sspine_skeleton_desc { - sspine_atlas atlas; - float prescale; - float anim_default_mix; - const char* json_data; - sspine_range binary_data; -} sspine_skeleton_desc; - -typedef struct sspine_skinset_desc { - sspine_skeleton skeleton; - sspine_skin skins[SSPINE_MAX_SKINSET_SKINS]; -} sspine_skinset_desc; - -typedef struct sspine_anim_info { - bool valid; - int index; - float duration; - sspine_string name; -} sspine_anim_info; - -typedef struct sspine_bone_info { - bool valid; - int index; - sspine_bone parent_bone; - float length; - sspine_bone_transform pose; - sspine_color color; - sspine_string name; -} sspine_bone_info; - -typedef struct sspine_slot_info { - bool valid; - int index; - sspine_bone bone; - sspine_color color; - sspine_string attachment_name; - sspine_string name; -} sspine_slot_info; - -typedef struct sspine_iktarget_info { - bool valid; - int index; - sspine_bone target_bone; - sspine_string name; -} sspine_iktarget_info; - -typedef struct sspine_skin_info { - bool valid; - int index; - sspine_string name; -} sspine_skin_info; - -typedef struct sspine_event_info { - bool valid; - int index; - int int_value; - float float_value; - float volume; - float balance; - sspine_string name; - sspine_string string_value; - sspine_string audio_path; -} sspine_event_info; - -typedef struct sspine_triggered_event_info { - bool valid; - sspine_event event; - float time; - int int_value; - float float_value; - float volume; - float balance; - sspine_string string_value; -} sspine_triggered_event_info; - -typedef struct sspine_instance_desc { - sspine_skeleton skeleton; -} sspine_instance_desc; - -typedef struct sspine_allocator { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sspine_allocator; - -typedef struct sspine_logger { - void (*func)( - const char* tag, // always "sspine" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SSPINE_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_spine.h - const char* filename_or_null, // the source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sspine_logger; - -typedef struct sspine_desc { - int max_vertices; - int max_commands; - int context_pool_size; - int atlas_pool_size; - int skeleton_pool_size; - int skinset_pool_size; - int instance_pool_size; - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_color_mask color_write_mask; - sspine_allocator allocator; // optional allocation override functions (default: malloc/free) - sspine_logger logger; // optional logging function (default: NO LOGGING!) -} sspine_desc; - -// setup/shutdown -SOKOL_SPINE_API_DECL void sspine_setup(const sspine_desc* desc); -SOKOL_SPINE_API_DECL void sspine_shutdown(void); - -// context functions -SOKOL_SPINE_API_DECL sspine_context sspine_make_context(const sspine_context_desc* desc); -SOKOL_SPINE_API_DECL void sspine_destroy_context(sspine_context ctx); -SOKOL_SPINE_API_DECL void sspine_set_context(sspine_context ctx); -SOKOL_SPINE_API_DECL sspine_context sspine_get_context(void); -SOKOL_SPINE_API_DECL sspine_context sspine_default_context(void); -SOKOL_SPINE_API_DECL sspine_context_info sspine_get_context_info(sspine_context ctx); - -// create and destroy spine objects -SOKOL_SPINE_API_DECL sspine_atlas sspine_make_atlas(const sspine_atlas_desc* desc); -SOKOL_SPINE_API_DECL sspine_skeleton sspine_make_skeleton(const sspine_skeleton_desc* desc); -SOKOL_SPINE_API_DECL sspine_skinset sspine_make_skinset(const sspine_skinset_desc* desc); -SOKOL_SPINE_API_DECL sspine_instance sspine_make_instance(const sspine_instance_desc* desc); -SOKOL_SPINE_API_DECL void sspine_destroy_atlas(sspine_atlas atlas); -SOKOL_SPINE_API_DECL void sspine_destroy_skeleton(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL void sspine_destroy_skinset(sspine_skinset skinset); -SOKOL_SPINE_API_DECL void sspine_destroy_instance(sspine_instance instance); - -// configure instance appearance via skinsets -SOKOL_SPINE_API_DECL void sspine_set_skinset(sspine_instance instance, sspine_skinset skinset); - -// update instance animations before drawing -SOKOL_SPINE_API_DECL void sspine_update_instance(sspine_instance instance, float delta_time); - -// iterate over triggered events after updating an instance -SOKOL_SPINE_API_DECL int sspine_num_triggered_events(sspine_instance instance); -SOKOL_SPINE_API_DECL sspine_triggered_event_info sspine_get_triggered_event_info(sspine_instance instance, int triggered_event_index); - -// draw instance into current or explicit context -SOKOL_SPINE_API_DECL void sspine_draw_instance_in_layer(sspine_instance instance, int layer); -SOKOL_SPINE_API_DECL void sspine_context_draw_instance_in_layer(sspine_context ctx, sspine_instance instance, int layer); - -// helper function to convert sspine_layer_transform into projection matrix -SOKOL_SPINE_API_DECL sspine_mat4 sspine_layer_transform_to_mat4(const sspine_layer_transform* tform); - -// draw a layer in current context or explicit context (call once per context and frame in sokol-gfx pass) -SOKOL_SPINE_API_DECL void sspine_draw_layer(int layer, const sspine_layer_transform* tform); -SOKOL_SPINE_API_DECL void sspine_context_draw_layer(sspine_context ctx, int layer, const sspine_layer_transform* tform); - -// get current resource state (INITIAL, ALLOC, VALID, FAILED, INVALID) -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_context_resource_state(sspine_context context); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_atlas_resource_state(sspine_atlas atlas); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_skeleton_resource_state(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_skinset_resource_state(sspine_skinset skinset); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_instance_resource_state(sspine_instance instance); - -// shortcut for sspine_get_*_state() == SSPINE_RESOURCESTATE_VALID -SOKOL_SPINE_API_DECL bool sspine_context_valid(sspine_context context); -SOKOL_SPINE_API_DECL bool sspine_atlas_valid(sspine_atlas atlas); -SOKOL_SPINE_API_DECL bool sspine_skeleton_valid(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL bool sspine_instance_valid(sspine_instance instance); -SOKOL_SPINE_API_DECL bool sspine_skinset_valid(sspine_skinset skinset); - -// get dependency objects -SOKOL_SPINE_API_DECL sspine_atlas sspine_get_skeleton_atlas(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_skeleton sspine_get_instance_skeleton(sspine_instance instance); - -// atlas images -SOKOL_SPINE_API_DECL int sspine_num_images(sspine_atlas atlas); -SOKOL_SPINE_API_DECL sspine_image sspine_image_by_index(sspine_atlas atlas, int index); -SOKOL_SPINE_API_DECL bool sspine_image_valid(sspine_image image); -SOKOL_SPINE_API_DECL bool sspine_image_equal(sspine_image first, sspine_image second); -SOKOL_SPINE_API_DECL sspine_image_info sspine_get_image_info(sspine_image image); - -// atlas page functions -SOKOL_SPINE_API_DECL int sspine_num_atlas_pages(sspine_atlas atlas); -SOKOL_SPINE_API_DECL sspine_atlas_page sspine_atlas_page_by_index(sspine_atlas atlas, int index); -SOKOL_SPINE_API_DECL bool sspine_atlas_page_valid(sspine_atlas_page page); -SOKOL_SPINE_API_DECL bool sspine_atlas_page_equal(sspine_atlas_page first, sspine_atlas_page second); -SOKOL_SPINE_API_DECL sspine_atlas_page_info sspine_get_atlas_page_info(sspine_atlas_page page); - -// instance transform functions -SOKOL_SPINE_API_DECL void sspine_set_position(sspine_instance instance, sspine_vec2 position); -SOKOL_SPINE_API_DECL void sspine_set_scale(sspine_instance instance, sspine_vec2 scale); -SOKOL_SPINE_API_DECL void sspine_set_color(sspine_instance instance, sspine_color color); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_position(sspine_instance instance); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_scale(sspine_instance instance); -SOKOL_SPINE_API_DECL sspine_color sspine_get_color(sspine_instance instance); - -// instance animation functions -SOKOL_SPINE_API_DECL int sspine_num_anims(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_anim sspine_anim_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_anim sspine_anim_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_anim_valid(sspine_anim anim); -SOKOL_SPINE_API_DECL bool sspine_anim_equal(sspine_anim first, sspine_anim second); -SOKOL_SPINE_API_DECL sspine_anim_info sspine_get_anim_info(sspine_anim anim); -SOKOL_SPINE_API_DECL void sspine_clear_animation_tracks(sspine_instance instance); -SOKOL_SPINE_API_DECL void sspine_clear_animation_track(sspine_instance instance, int track_index); -SOKOL_SPINE_API_DECL void sspine_set_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop); -SOKOL_SPINE_API_DECL void sspine_add_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop, float delay); -SOKOL_SPINE_API_DECL void sspine_set_empty_animation(sspine_instance instance, int track_index, float mix_duration); -SOKOL_SPINE_API_DECL void sspine_add_empty_animation(sspine_instance instance, int track_index, float mix_duration, float delay); - -// bone functions -SOKOL_SPINE_API_DECL int sspine_num_bones(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_bone sspine_bone_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_bone sspine_bone_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_bone_valid(sspine_bone bone); -SOKOL_SPINE_API_DECL bool sspine_bone_equal(sspine_bone first, sspine_bone second); -SOKOL_SPINE_API_DECL sspine_bone_info sspine_get_bone_info(sspine_bone bone); -SOKOL_SPINE_API_DECL void sspine_set_bone_transform(sspine_instance instance, sspine_bone bone, const sspine_bone_transform* transform); -SOKOL_SPINE_API_DECL void sspine_set_bone_position(sspine_instance instance, sspine_bone bone, sspine_vec2 position); -SOKOL_SPINE_API_DECL void sspine_set_bone_rotation(sspine_instance instance, sspine_bone bone, float rotation); -SOKOL_SPINE_API_DECL void sspine_set_bone_scale(sspine_instance instance, sspine_bone bone, sspine_vec2 scale); -SOKOL_SPINE_API_DECL void sspine_set_bone_shear(sspine_instance instance, sspine_bone bone, sspine_vec2 shear); -SOKOL_SPINE_API_DECL sspine_bone_transform sspine_get_bone_transform(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_position(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL float sspine_get_bone_rotation(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_scale(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_shear(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_world_position(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_bone_local_to_world(sspine_instance instance, sspine_bone bone, sspine_vec2 local_pos); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_bone_world_to_local(sspine_instance instance, sspine_bone bone, sspine_vec2 world_pos); - -// slot functions -SOKOL_SPINE_API_DECL int sspine_num_slots(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_slot sspine_slot_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_slot sspine_slot_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_slot_valid(sspine_slot slot); -SOKOL_SPINE_API_DECL bool sspine_slot_equal(sspine_slot first, sspine_slot second); -SOKOL_SPINE_API_DECL sspine_slot_info sspine_get_slot_info(sspine_slot slot); -SOKOL_SPINE_API_DECL void sspine_set_slot_color(sspine_instance instance, sspine_slot slot, sspine_color color); -SOKOL_SPINE_API_DECL sspine_color sspine_get_slot_color(sspine_instance instance, sspine_slot slot); - -// event functions -SOKOL_SPINE_API_DECL int sspine_num_events(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_event sspine_event_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_event sspine_event_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_event_valid(sspine_event event); -SOKOL_SPINE_API_DECL bool sspine_event_equal(sspine_event first, sspine_event second); -SOKOL_SPINE_API_DECL sspine_event_info sspine_get_event_info(sspine_event event); - -// ik target functions -SOKOL_SPINE_API_DECL int sspine_num_iktargets(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_iktarget sspine_iktarget_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_iktarget sspine_iktarget_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_iktarget_valid(sspine_iktarget iktarget); -SOKOL_SPINE_API_DECL bool sspine_iktarget_equal(sspine_iktarget first, sspine_iktarget second); -SOKOL_SPINE_API_DECL sspine_iktarget_info sspine_get_iktarget_info(sspine_iktarget iktarget); -SOKOL_SPINE_API_DECL void sspine_set_iktarget_world_pos(sspine_instance instance, sspine_iktarget iktarget, sspine_vec2 world_pos); - -// skin functions -SOKOL_SPINE_API_DECL int sspine_num_skins(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_skin sspine_skin_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_skin sspine_skin_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_skin_valid(sspine_skin skin); -SOKOL_SPINE_API_DECL bool sspine_skin_equal(sspine_skin first, sspine_skin second); -SOKOL_SPINE_API_DECL sspine_skin_info sspine_get_skin_info(sspine_skin skin); -SOKOL_SPINE_API_DECL void sspine_set_skin(sspine_instance instance, sspine_skin skin); - -#ifdef __cplusplus -} // extern "C" -#endif - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_SPINE_IMPL -#define SOKOL_SPINE_IMPL_INCLUDED (1) - -#if !defined(SPINE_SPINE_H_) -#error "Please include spine/spine.h before the sokol_spine.h implementation" -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG (1) - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef SOKOL_UNUSED - #define SOKOL_UNUSED(x) (void)(x) -#endif - -#include // malloc/free -#include // memset, strcmp - -// ███████╗██╗ ██╗ █████╗ ██████╗ ███████╗██████╗ ███████╗ -// ██╔════╝██║ ██║██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔════╝ -// ███████╗███████║███████║██║ ██║█████╗ ██████╔╝███████╗ -// ╚════██║██╔══██║██╔══██║██║ ██║██╔══╝ ██╔══██╗╚════██║ -// ███████║██║ ██║██║ ██║██████╔╝███████╗██║ ██║███████║ -// ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝ -// -// >>shaders -/* - Embedded source compiled with: - - sokol-shdc -i sspine.glsl -o sspine.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - @vs vs - uniform vs_params { - mat4 mvp; - }; - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = mvp * vec4(position, 0.0, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - uniform fs_params { - float pma; - }; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - vec4 c0 = texture(sampler2D(tex, smp), uv) * color; - vec4 c1 = vec4(c0.rgb * c0.a, c0.a) * color; - frag_color = mix(c0, c1, pma); - } - @end - - @program sspine vs fs -*/ -#if defined(SOKOL_GLCORE33) -static const char _sspine_vs_source_glsl330[352] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20, - 0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72, - 0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e, - 0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -static const char _sspine_fs_source_glsl330[308] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d, - 0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73, - 0x6d,0x70,0x3b,0x0a,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b, - 0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72, - 0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20, - 0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x63, - 0x34,0x20,0x5f,0x32,0x38,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20, - 0x5f,0x33,0x37,0x20,0x3d,0x20,0x5f,0x32,0x38,0x2e,0x77,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x6d,0x69, - 0x78,0x28,0x5f,0x32,0x38,0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x32,0x38,0x2e, - 0x78,0x79,0x7a,0x20,0x2a,0x20,0x5f,0x33,0x37,0x2c,0x20,0x5f,0x33,0x37,0x29,0x20, - 0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x66,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x29,0x29,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const char _sspine_vs_source_glsl300es[355] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20, - 0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f, - 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61, - 0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63, - 0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c, - 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d, - 0x0a,0x0a,0x00, -}; -static const char _sspine_fs_source_glsl300es[399] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63, - 0x34,0x20,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a, - 0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61, - 0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b, - 0x0a,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20, - 0x75,0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75, - 0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61, - 0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68, - 0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x32,0x38,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76, - 0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x68, - 0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x37,0x20,0x3d, - 0x20,0x5f,0x32,0x38,0x2e,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x5f,0x32,0x38, - 0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x32,0x38,0x2e,0x78,0x79,0x7a,0x20,0x2a, - 0x20,0x5f,0x33,0x37,0x2c,0x20,0x5f,0x33,0x37,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x66,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sspine_vs_bytecode_hlsl4[844] = { - 0x44,0x58,0x42,0x43,0x2a,0xc9,0x57,0x52,0x4b,0x3d,0x3e,0x89,0x00,0xf4,0xfa,0x41, - 0xfd,0xd7,0x63,0xc3,0x01,0x00,0x00,0x00,0x4c,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xf4,0x00,0x00,0x00,0x58,0x01,0x00,0x00,0xc8,0x01,0x00,0x00, - 0xd0,0x02,0x00,0x00,0x52,0x44,0x45,0x46,0xb8,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x90,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f,0x6d,0x76,0x70,0x00,0x02,0x00,0x03,0x00, - 0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72, - 0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53, - 0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31, - 0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43, - 0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00, - 0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab,0x53,0x48,0x44,0x52,0x00,0x01,0x00,0x00, - 0x40,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00, - 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00,0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00, - 0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05, - 0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x01,0x00,0x00,0x00, - 0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00, - 0x02,0x00,0x00,0x00,0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x56,0x15,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x01, - 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_fs_bytecode_hlsl4[868] = { - 0x44,0x58,0x42,0x43,0xfb,0x9d,0xdb,0x19,0x85,0xbc,0x50,0x5d,0x6b,0x03,0xd4,0xc8, - 0x1b,0xea,0x59,0xf5,0x01,0x00,0x00,0x00,0x64,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x3c,0x01,0x00,0x00,0x88,0x01,0x00,0x00,0xbc,0x01,0x00,0x00, - 0xe8,0x02,0x00,0x00,0x52,0x44,0x45,0x46,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00, - 0x90,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0xd8,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x00,0xab,0xab,0x84,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x35,0x33,0x5f, - 0x70,0x6d,0x61,0x00,0x00,0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52, - 0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e, - 0x44,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43, - 0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x53,0x56,0x5f,0x54,0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52, - 0x24,0x01,0x00,0x00,0x40,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x59,0x00,0x00,0x04, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5a,0x00,0x00,0x03, - 0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00, - 0x00,0x00,0x00,0x00,0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x02,0x00,0x00,0x00,0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00, - 0x01,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0x72,0x00,0x10,0x00,0x01,0x00,0x00,0x00, - 0xf6,0x0f,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x02,0x10,0x00,0x00,0x00,0x00,0x00, - 0x36,0x00,0x00,0x05,0x82,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x3a,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x01,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x80,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x06,0x80,0x20,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x0e,0x10,0x00, - 0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00, - 0x07,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sspine_vs_bytecode_metal_macos[3084] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x1d,0x26,0xf7,0xce,0x5d,0x78,0x21, - 0x2f,0xa7,0x97,0xe1,0xbd,0x15,0x30,0xfb,0xa6,0x98,0xcc,0x1d,0xba,0x1d,0x0d,0x92, - 0xaa,0x4e,0x3d,0x75,0xee,0x73,0x36,0x7c,0x99,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xe0,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xb5,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x14,0x45,0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x81,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0x02,0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00, - 0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x1f,0x00,0x00,0x00, - 0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3, - 0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00, - 0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x42,0x24,0x81,0x98,0x89,0x9a,0x07, - 0x7a,0x90,0x87,0x7a,0x18,0x07,0x7a,0x70,0x83,0x76,0x28,0x07,0x7a,0x08,0x07,0x76, - 0xd0,0x03,0x3d,0x68,0x87,0x70,0xa0,0x07,0x79,0x48,0x07,0x7c,0x40,0x01,0x39,0x48, - 0x9a,0x22,0x4a,0x98,0xfc,0x4a,0xfa,0x1f,0x20,0x02,0x18,0x09,0x05,0x65,0x10,0xc1, - 0x10,0x4a,0x31,0x42,0x10,0x87,0xd0,0x40,0xc0,0x1c,0x01,0x18,0xa4,0xc0,0x9a,0x23, - 0x00,0x85,0x41,0x04,0x41,0x18,0x46,0x20,0x96,0x11,0x00,0x00,0x13,0xb2,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38, - 0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e, - 0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73, - 0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40, - 0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10, - 0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07, - 0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a, - 0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20, - 0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07, - 0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72, - 0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0, - 0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07, - 0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00, - 0x00,0x00,0x00,0xc8,0x02,0x01,0x00,0x00,0x0a,0x00,0x00,0x00,0x32,0x1e,0x98,0x10, - 0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50, - 0x04,0x05,0x18,0x50,0x08,0x05,0x51,0x06,0x05,0x42,0x6d,0x04,0x80,0xd8,0x58,0x42, - 0x13,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xeb,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10, - 0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28, - 0x00,0xa3,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c, - 0x81,0x22,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c, - 0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06, - 0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58, - 0x8c,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45, - 0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6, - 0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12, - 0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73, - 0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65, - 0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9, - 0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d, - 0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b, - 0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9, - 0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72, - 0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2, - 0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51, - 0xa8,0xb3,0x1b,0xc2,0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b, - 0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47, - 0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0xa3,0x3c,0x8a,0xa5,0x44,0xca,0xa5,0x4c, - 0x0a,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb, - 0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x45,0xd1,0x94,0x48, - 0xb9,0x94,0x49,0xd9,0x86,0x18,0x4a,0xa5,0x64,0x0a,0x47,0x28,0x2c,0x4d,0xce,0xc5, - 0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c, - 0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd, - 0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f, - 0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x45,0x50,0x3c,0xe5,0x5b,0x84,0x25, - 0x50,0xc0,0x40,0x89,0x14,0x49,0x99,0x94,0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6, - 0x26,0x47,0x06,0x33,0x84,0x5a,0x02,0xc5,0x53,0xbe,0x25,0x58,0x02,0x05,0x0c,0x94, - 0x48,0x91,0x94,0x49,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65, - 0x50,0x3c,0xe5,0x5b,0x86,0x25,0x50,0xc0,0x40,0x89,0x94,0x4b,0x99,0x94,0x32,0xa0, - 0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45, - 0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b, - 0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f, - 0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x22,0x66,0x6c,0x6f,0x61,0x74,0x34, - 0x78,0x34,0x1c,0xda,0xec,0xe0,0x86,0x28,0x8b,0xb0,0x10,0x8b,0xa0,0xac,0x81,0xc2, - 0x06,0x8c,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xe6, - 0xd2,0xf4,0xca,0x78,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95, - 0x7d,0x85,0xb1,0xa5,0x9d,0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0xb1,0x9b,0xfb,0x82, - 0x0b,0x93,0x0b,0x6b,0x9b,0xe3,0xf0,0x15,0x93,0x33,0x84,0x0c,0x96,0x43,0x39,0x03, - 0x05,0x0d,0x16,0x42,0xf9,0x16,0x61,0x09,0x94,0x34,0x50,0xd4,0x40,0x69,0x03,0xc5, - 0x0d,0x16,0x42,0x79,0x83,0x05,0x51,0x22,0x05,0x0e,0x94,0x49,0x89,0x83,0x21,0x88, - 0x22,0x06,0x0a,0x19,0x28,0x66,0xa0,0xc8,0xc1,0x10,0x23,0x01,0x94,0x4e,0x99,0x03, - 0x3e,0x6f,0x6d,0x6e,0x69,0x70,0x6f,0x74,0x65,0x6e,0x74,0x20,0x63,0x68,0x61,0x72, - 0x7c,0xa6,0xd2,0xda,0xe0,0xd8,0xca,0x40,0x86,0x56,0x56,0x40,0xa8,0x84,0x82,0x82, - 0x86,0x08,0x8a,0x1d,0x0c,0x31,0x94,0x3a,0x50,0xee,0xa0,0x49,0x86,0x18,0x0a,0x1e, - 0x28,0x78,0xd0,0x24,0x23,0x22,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x77, - 0x20,0x87,0x7a,0x60,0x87,0x72,0x70,0x03,0x73,0x60,0x87,0x70,0x38,0x87,0x79,0x98, - 0x22,0x04,0xc3,0x08,0x85,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xd2,0x81,0x1c,0xca, - 0xc1,0x1d,0xe8,0x61,0x4a,0x50,0x8c,0x58,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1, - 0x1c,0xe4,0x61,0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x4a,0x60,0x8c,0xa0,0xc2,0x21,0x1d, - 0xe4,0xc1,0x0d,0xd8,0x21,0x1c,0xdc,0xe1,0x1c,0xea,0x21,0x1c,0xce,0xa1,0x1c,0x7e, - 0xc1,0x1e,0xca,0x41,0x1e,0xe6,0x21,0x1d,0xde,0xc1,0x1d,0xa6,0x04,0xc8,0x88,0x29, - 0x1c,0xd2,0x41,0x1e,0xdc,0x60,0x1c,0xde,0xa1,0x1d,0xe0,0x21,0x1d,0xd8,0xa1,0x1c, - 0x7e,0xe1,0x1d,0xe0,0x81,0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x1e,0xa6,0x0c,0x0a,0xe3, - 0x8c,0x50,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x81,0x1e,0xca,0x01, - 0x1f,0xa6,0x04,0x74,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00, - 0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3, - 0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10, - 0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30, - 0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03, - 0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07, - 0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e, - 0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d, - 0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b, - 0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76, - 0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90, - 0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87, - 0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e, - 0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c, - 0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8, - 0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82, - 0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83, - 0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f, - 0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec, - 0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc, - 0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0, - 0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60, - 0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e, - 0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1, - 0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43, - 0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c, - 0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72, - 0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1, - 0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38, - 0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8, - 0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00, - 0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00, - 0x1e,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x05,0x00,0x00,0x00, - 0xf4,0xc6,0x22,0x82,0x20,0x08,0x46,0x00,0xa8,0x95,0x40,0x19,0xd0,0x98,0x01,0xa0, - 0x30,0x03,0x00,0x00,0xe3,0x15,0x07,0x33,0x4d,0x0c,0x05,0x65,0x90,0x81,0x19,0x0e, - 0x13,0x02,0xf9,0x8c,0x57,0x2c,0xd0,0x75,0x21,0x14,0x94,0x41,0x06,0xe8,0x60,0x4c, - 0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1,0x0a,0xa8,0xe2,0x38,0x86,0x82,0x62,0x43,0x00, - 0x9f,0xd9,0x06,0xa7,0x02,0x66,0x1b,0x82,0x2a,0x98,0x6d,0x08,0x06,0x21,0x83,0x80, - 0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x5b,0x86,0x20,0xc8,0x83,0x2d,0x43,0x11, - 0xe4,0xc1,0x96,0x41,0x09,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_fs_bytecode_metal_macos[3257] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xb9,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x47,0xc7,0x1e,0x49,0x53,0x1c,0xe5, - 0x90,0x01,0xa5,0x57,0x9a,0x30,0x01,0x5c,0x39,0x85,0x9f,0xb2,0x71,0x51,0xe1,0x73, - 0x0c,0xa4,0x4d,0xb1,0x81,0x33,0x8d,0x17,0x1e,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0xc4,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0xee,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x8e,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x60,0x10,0x05,0xb0,0x00,0xd5,0x06,0xa3,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x00, - 0x6a,0x03,0x62,0xfc,0xff,0xff,0xff,0xff,0x00,0x30,0x80,0x04,0x54,0x1b,0x8c,0x23, - 0x00,0x16,0xa0,0xda,0x60,0x20,0x02,0xb0,0x00,0x15,0x00,0x00,0x00,0x49,0x18,0x00, - 0x00,0x03,0x00,0x00,0x00,0x13,0x88,0x40,0x18,0x88,0x09,0x41,0x31,0x61,0x30,0x0e, - 0x04,0x89,0x20,0x00,0x00,0x27,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x6c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c, - 0x20,0x00,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x48,0xff,0x03,0x44,0x00,0x23,0xa1, - 0x00,0x0c,0x22,0x10,0xc2,0x51,0xd2,0x14,0x51,0xc2,0xe4,0xff,0x13,0x71,0x4d,0x54, - 0x44,0xfc,0xf6,0xf0,0x4f,0x63,0x04,0xc0,0x20,0x82,0x11,0x5c,0x24,0x4d,0x11,0x25, - 0x4c,0xfe,0x2f,0x01,0xcc,0xb3,0x10,0xd1,0x3f,0x8d,0x11,0x00,0x83,0x08,0x88,0x50, - 0x0c,0x31,0x42,0x39,0x89,0x54,0x21,0x42,0x08,0x81,0xd8,0x1c,0x41,0x30,0x47,0x00, - 0x06,0xc3,0x08,0xc2,0x53,0x90,0x70,0xd2,0x70,0xd0,0x01,0x8a,0x03,0x01,0x29,0xf0, - 0x86,0x11,0x86,0x67,0x18,0x61,0x00,0x86,0x11,0x88,0x67,0x8e,0x00,0x14,0x06,0x11, - 0x00,0x61,0x04,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83, - 0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79, - 0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5, - 0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07, - 0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0, - 0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07, - 0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d, - 0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60, - 0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f, - 0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79, - 0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07, - 0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50, - 0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07, - 0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71, - 0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00, - 0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07, - 0x72,0x30,0x84,0x59,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x18,0xc2,0x34,0x40, - 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x0c,0x61,0x24,0x20,0x00,0x06,0x00,0x00,0x00, - 0x00,0x00,0xb2,0x40,0x00,0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x7a,0x23,0x00,0x25,0x50,0x08,0x45,0x50, - 0x10,0x65,0x40,0x78,0x04,0x80,0xe8,0x58,0x42,0x13,0x00,0x00,0x00,0x79,0x18,0x00, - 0x00,0xf9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x63,0x4c,0x00,0xa5,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x3c,0xc4,0x24,0x3c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0x30,0x11,0x43,0x8c,0x87,0x78,0x8e,0x67,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x99,0x8e,0x87,0x78,0x88,0x67,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x98,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x69,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95, - 0x0d,0x11,0xa6,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17, - 0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba, - 0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64, - 0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85, - 0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0xa6,0xe7,0x19,0x26,0x68,0x8a,0x26, - 0x69,0x9a,0x86,0x08,0x13,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad, - 0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb, - 0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39, - 0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65, - 0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x9e,0x61,0xb2,0xa6, - 0x6b,0xc2,0xa6,0x6c,0x82,0x26,0x6d,0x92,0xa6,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a, - 0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x43,0x4c, - 0xd6,0xd4,0x4d,0xd8,0x94,0x4d,0xd0,0x14,0x4d,0xd2,0xe4,0x51,0x09,0x4b,0x93,0x73, - 0x11,0xab,0x33,0x33,0x2b,0x93,0xe3,0x13,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56, - 0x26,0xf7,0x35,0x97,0xa6,0x57,0x46,0x29,0x2c,0x4d,0xce,0x85,0xed,0x6d,0x2c,0x8c, - 0x2e,0xed,0xcd,0xed,0x2b,0xcd,0x8d,0xac,0x0c,0x8f,0x48,0x58,0x9a,0x9c,0x8b,0x5c, - 0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba, - 0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x16,0x66,0x6c,0x6f,0x61,0x74,0x1c,0xe0, - 0xda,0xc2,0x86,0x28,0xcf,0xf0,0x14,0xcf,0x30,0x95,0xc1,0x64,0x06,0x8c,0xc2,0xd2, - 0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xe6,0xd2,0xf4,0xca,0x78, - 0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0x85,0xb1,0xa5, - 0x9d,0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0x31,0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b, - 0x9b,0xe3,0xf0,0x55,0x33,0x33,0x84,0x0c,0x1e,0x63,0x02,0x83,0x29,0x0c,0x9e,0x62, - 0x12,0x83,0x67,0x78,0x88,0x69,0x0c,0x26,0x32,0x98,0xce,0x60,0x42,0x83,0xa7,0x98, - 0xd2,0xe0,0x29,0x26,0x68,0x52,0x83,0x49,0x9a,0xd6,0x80,0x4b,0x58,0x9a,0x9c,0x0b, - 0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x19,0x95,0xb0,0x34,0x39,0x97,0xb9,0xb0,0x36,0x38, - 0xb6,0x32,0x62,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f, - 0x61,0x74,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x3e,0x1c,0xe8,0xca,0xf0,0x86, - 0x50,0x0f,0x32,0xb5,0xc1,0x24,0x06,0xcf,0xf0,0x10,0x93,0x1b,0x4c,0xd0,0xf4,0x06, - 0x93,0x34,0xc1,0x01,0x97,0xb0,0x34,0x39,0x97,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39, - 0x1e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x1c,0xe6,0xda,0xe0,0x86,0x48,0x4f,0x31, - 0xc9,0xc1,0x24,0x06,0xcf,0xf0,0x10,0x13,0x34,0xcd,0xc1,0x24,0x4d,0x74,0x30,0x44, - 0x99,0xb8,0xe9,0x9b,0xd8,0x60,0x8a,0x83,0xa9,0x0e,0x86,0x18,0x0b,0x30,0x55,0x93, - 0x1d,0xd0,0xf9,0xd2,0xa2,0x9a,0xca,0x31,0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b, - 0xe3,0xf3,0xd6,0xe6,0x96,0x06,0xf7,0x46,0x57,0xe6,0x46,0x07,0x32,0x86,0x16,0x26, - 0xc7,0x67,0x2a,0xad,0x0d,0x8e,0xad,0x0c,0x64,0x68,0x65,0x05,0x84,0x4a,0x28,0x28, - 0x68,0x88,0x30,0xe9,0xc1,0x10,0x63,0xca,0x83,0x69,0x0f,0xb0,0x64,0x88,0x31,0x95, - 0xc1,0xc4,0x07,0x58,0x32,0xc4,0x98,0xf0,0x60,0xea,0x03,0x2c,0x19,0x62,0x4c,0x7e, - 0x30,0xf5,0x01,0x96,0x8c,0x88,0xd8,0x81,0x1d,0xec,0xa1,0x1d,0xdc,0xa0,0x1d,0xde, - 0x81,0x1c,0xea,0x81,0x1d,0xca,0xc1,0x0d,0xcc,0x81,0x1d,0xc2,0xe1,0x1c,0xe6,0x61, - 0x8a,0x10,0x0c,0x23,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x48,0x07,0x72,0x28, - 0x07,0x77,0xa0,0x87,0x29,0x41,0x31,0x62,0x09,0x87,0x74,0x90,0x07,0x37,0xb0,0x87, - 0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x81,0x31,0x82,0x0a,0x87,0x74, - 0x90,0x07,0x37,0x60,0x87,0x70,0x70,0x87,0x73,0xa8,0x87,0x70,0x38,0x87,0x72,0xf8, - 0x05,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x20,0x23,0xa6, - 0x70,0x48,0x07,0x79,0x70,0x83,0x71,0x78,0x87,0x76,0x80,0x87,0x74,0x60,0x87,0x72, - 0xf8,0x85,0x77,0x80,0x07,0x7a,0x48,0x87,0x77,0x70,0x87,0x79,0x98,0x32,0x28,0x8c, - 0x33,0x82,0x09,0x87,0x74,0x90,0x07,0x37,0x30,0x07,0x79,0x08,0x87,0x73,0x68,0x87, - 0x72,0x70,0x07,0x7a,0x98,0x12,0xdc,0x01,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x26,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x6d,0x01,0x0d,0x80,0x44,0x3e,0x83,0x5c,0x7e,0x85,0x17,0xb7,0x0d,0x00,0x00, - 0x00,0x61,0x20,0x00,0x00,0x25,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00, - 0x00,0x0c,0x00,0x00,0x00,0x74,0x47,0x00,0xc6,0x22,0x80,0x40,0x38,0xe6,0x20,0x06, - 0xc2,0xa8,0xc8,0xd5,0xc0,0x08,0x00,0xbd,0x19,0x00,0x82,0x23,0x00,0x54,0xc7,0x1a, - 0x80,0x40,0x18,0x6b,0x18,0x86,0x81,0xec,0x0c,0x00,0x89,0x19,0x00,0x0a,0x33,0x00, - 0x04,0x46,0x00,0x00,0x00,0x23,0x06,0xca,0x10,0x6c,0x8f,0x23,0x29,0x47,0x12,0x58, - 0x20,0xc9,0x67,0x90,0x21,0x20,0x90,0x41,0x06,0xa1,0x40,0x4c,0x08,0xe4,0x33,0xc8, - 0x10,0x24,0xd0,0x20,0x43,0x50,0x48,0x16,0x60,0xf2,0x19,0x6f,0xc0,0x38,0x31,0xa0, - 0x60,0xcc,0x31,0x30,0x01,0x19,0x0c,0x32,0x04,0x0d,0x36,0x62,0x60,0x08,0x01,0x1a, - 0x2c,0x45,0x30,0xdb,0x00,0x05,0x40,0x06,0x01,0x31,0x00,0x00,0x00,0x02,0x00,0x00, - 0x00,0x5b,0x86,0x24,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_vs_bytecode_metal_ios[3068] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xfc,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x93,0xd6,0x91,0x34,0xa6,0x5a,0xef, - 0xf4,0xa9,0x2b,0xc7,0x55,0x75,0x4a,0x7f,0xc5,0x46,0xc0,0x95,0x92,0x61,0x00,0x3e, - 0x6d,0x53,0x68,0xee,0xb6,0x8e,0xc8,0x26,0x6c,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xd8,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xb3,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x14,0x45,0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x20,0x02,0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00, - 0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00, - 0x1f,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84, - 0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c, - 0x10,0x44,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x42,0x24,0x81, - 0x98,0x89,0x9a,0x07,0x7a,0x90,0x87,0x7a,0x18,0x07,0x7a,0x70,0x83,0x76,0x28,0x07, - 0x7a,0x08,0x07,0x76,0xd0,0x03,0x3d,0x68,0x87,0x70,0xa0,0x07,0x79,0x48,0x07,0x7c, - 0x40,0x01,0x39,0x48,0x9a,0x22,0x4a,0x98,0xfc,0x4a,0xfa,0x1f,0x20,0x02,0x18,0x09, - 0x05,0x65,0x10,0xc1,0x10,0x4a,0x31,0x42,0x10,0x87,0xd0,0x40,0xc0,0x1c,0x01,0x18, - 0xa4,0xc0,0x9a,0x23,0x00,0x85,0x41,0x04,0x41,0x18,0x46,0x20,0x96,0x11,0x00,0x00, - 0x13,0xa8,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60, - 0x87,0x72,0x68,0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83, - 0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d, - 0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76, - 0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20, - 0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xf6,0x90,0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07, - 0x78,0xd0,0x06,0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a, - 0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50, - 0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07, - 0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75, - 0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0, - 0x06,0xf6,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07, - 0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76, - 0xa0,0x07,0x73,0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80, - 0x2c,0x10,0x00,0x00,0x0a,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18,0x50, - 0x08,0x05,0x51,0x06,0x05,0x42,0x6d,0x04,0x80,0xd8,0x58,0x02,0x24,0x00,0x00,0x00, - 0x79,0x18,0x00,0x00,0xea,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25, - 0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28,0x00,0xa3,0x50,0xb9, - 0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0x81,0x22,0x2c,0x05, - 0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c, - 0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04, - 0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6, - 0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58,0x8c,0x45,0x60,0xd1, - 0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45,0xe0,0x16,0x96,0x26, - 0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36, - 0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12,0x72,0x61,0x69,0x72, - 0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61, - 0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65,0x21,0x19,0x84,0xa5, - 0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89, - 0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89, - 0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19, - 0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7, - 0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70, - 0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5, - 0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x28, - 0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b, - 0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed, - 0x4d,0x6e,0x08,0xa3,0x3c,0x8a,0xa5,0x44,0xca,0xa5,0x4c,0x0a,0x46,0x26,0x2c,0x4d, - 0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb, - 0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x45,0xd1,0x94,0x48,0xb9,0x94,0x49,0xd9,0x86, - 0x18,0x4a,0xa5,0x64,0x0a,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c, - 0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18, - 0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9, - 0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32, - 0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x43,0xa8,0x45,0x50,0x3c,0xe5,0x5b,0x84,0x25,0x50,0xc0,0x40,0x89,0x14, - 0x49,0x99,0x94,0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84, - 0x5a,0x02,0xc5,0x53,0xbe,0x25,0x58,0x02,0x05,0x0c,0x94,0x48,0x91,0x94,0x49,0x19, - 0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65,0x50,0x3c,0xe5,0x5b,0x86, - 0x25,0x50,0xc0,0x40,0x89,0x94,0x4b,0x99,0x94,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22, - 0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c, - 0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9, - 0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf, - 0x34,0x37,0xb3,0x37,0x22,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x1c,0xda,0xec, - 0xe0,0x86,0x28,0x8b,0xb0,0x10,0x8b,0xa0,0xac,0x81,0xc2,0x06,0x8c,0xc2,0xd2,0xe4, - 0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xe6,0xd2,0xf4,0xca,0x78,0x85, - 0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0x85,0xb1,0xa5,0x9d, - 0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0xb1,0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b, - 0xe3,0xf0,0x15,0x93,0x33,0x84,0x0c,0x96,0x43,0x39,0x03,0x05,0x0d,0x16,0x42,0xf9, - 0x16,0x61,0x09,0x94,0x34,0x50,0xd4,0x40,0x69,0x03,0xc5,0x0d,0x16,0x42,0x79,0x83, - 0x05,0x51,0x22,0x05,0x0e,0x94,0x49,0x89,0x83,0x21,0x88,0x22,0x06,0x0a,0x19,0x28, - 0x66,0xa0,0xc8,0xc1,0x10,0x23,0x01,0x94,0x4e,0x99,0x03,0x3e,0x6f,0x6d,0x6e,0x69, - 0x70,0x6f,0x74,0x65,0x6e,0x74,0x20,0x63,0x68,0x61,0x72,0x7c,0xa6,0xd2,0xda,0xe0, - 0xd8,0xca,0x40,0x86,0x56,0x56,0x40,0xa8,0x84,0x82,0x82,0x86,0x08,0x8a,0x1d,0x0c, - 0x31,0x94,0x3a,0x50,0xee,0xa0,0x49,0x86,0x18,0x0a,0x1e,0x28,0x78,0xd0,0x24,0x23, - 0x22,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x77,0x20,0x87,0x7a,0x60,0x87, - 0x72,0x70,0x03,0x73,0x60,0x87,0x70,0x38,0x87,0x79,0x98,0x22,0x04,0xc3,0x08,0x85, - 0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xd2,0x81,0x1c,0xca,0xc1,0x1d,0xe8,0x61,0x4a, - 0x50,0x8c,0x58,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x61,0x1e,0xd2, - 0xe1,0x1d,0xdc,0x61,0x4a,0x60,0x8c,0xa0,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xd8,0x21, - 0x1c,0xdc,0xe1,0x1c,0xea,0x21,0x1c,0xce,0xa1,0x1c,0x7e,0xc1,0x1e,0xca,0x41,0x1e, - 0xe6,0x21,0x1d,0xde,0xc1,0x1d,0xa6,0x04,0xc8,0x88,0x29,0x1c,0xd2,0x41,0x1e,0xdc, - 0x60,0x1c,0xde,0xa1,0x1d,0xe0,0x21,0x1d,0xd8,0xa1,0x1c,0x7e,0xe1,0x1d,0xe0,0x81, - 0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x1e,0xa6,0x0c,0x0a,0xe3,0x8c,0x50,0xc2,0x21,0x1d, - 0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x81,0x1e,0xca,0x01,0x1f,0xa6,0x04,0x74,0x00, - 0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66, - 0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73, - 0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e, - 0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b, - 0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b, - 0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20, - 0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0, - 0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61, - 0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83, - 0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87, - 0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76, - 0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98, - 0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30, - 0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61, - 0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43, - 0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b, - 0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7, - 0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18, - 0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90, - 0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1, - 0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d, - 0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c, - 0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d, - 0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54, - 0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4, - 0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18, - 0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0, - 0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1, - 0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83, - 0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d, - 0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00, - 0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x1e,0x00,0x00,0x00,0x13,0x04,0x41,0x2c, - 0x10,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xf4,0xc6,0x22,0x82,0x20,0x08,0x46,0x00, - 0xa8,0x95,0x40,0x19,0xd0,0x98,0x01,0xa0,0x30,0x03,0x00,0x00,0xe3,0x15,0x07,0x33, - 0x4d,0x0c,0x05,0x65,0x90,0x81,0x19,0x0e,0x13,0x02,0xf9,0x8c,0x57,0x2c,0xd0,0x75, - 0x21,0x14,0x94,0x41,0x06,0xe8,0x60,0x4c,0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1,0x0a, - 0xa8,0xe2,0x38,0x86,0x82,0x62,0x43,0x00,0x9f,0xd9,0x06,0xa7,0x02,0x66,0x1b,0x82, - 0x2a,0x98,0x6d,0x08,0x06,0x21,0x83,0x80,0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x5b,0x86,0x20,0xc8,0x83,0x2d,0x43,0x11,0xe4,0xc1,0x96,0x41,0x09,0xf2,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_fs_bytecode_metal_ios[3241] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xa9,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xd0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf2,0xd8,0x54,0xd8,0x76,0x28,0x3c, - 0xc1,0x24,0xd6,0xe7,0xb5,0xc4,0xbc,0x0f,0x0f,0x5a,0x55,0xdc,0x0c,0x24,0xa5,0x96, - 0x04,0x74,0x34,0x10,0x4e,0xdf,0x2e,0x1d,0xee,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0xbc,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0xec,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x8e,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x03,0x22,0x0c,0x40,0x02,0x2c,0x40,0xb5,0xc1,0x18,0x08,0x60,0x01, - 0xaa,0x0d,0x06,0x51,0x00,0x0b,0x50,0x6d,0x30,0x8a,0xff,0xff,0xff,0xff,0x1f,0x00, - 0x09,0xa0,0x36,0x20,0xc6,0xff,0xff,0xff,0xff,0x0f,0x00,0x03,0x48,0x40,0xb5,0xc1, - 0x38,0x02,0x60,0x01,0xaa,0x0d,0x06,0x22,0x00,0x0b,0x50,0x01,0x00,0x49,0x18,0x00, - 0x00,0x03,0x00,0x00,0x00,0x13,0x88,0x40,0x18,0x88,0x09,0x41,0x31,0x61,0x30,0x0e, - 0x04,0x89,0x20,0x00,0x00,0x27,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x6c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c, - 0x20,0x00,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x48,0xff,0x03,0x44,0x00,0x23,0xa1, - 0x00,0x0c,0x22,0x10,0xc2,0x51,0xd2,0x14,0x51,0xc2,0xe4,0xff,0x13,0x71,0x4d,0x54, - 0x44,0xfc,0xf6,0xf0,0x4f,0x63,0x04,0xc0,0x20,0x82,0x11,0x5c,0x24,0x4d,0x11,0x25, - 0x4c,0xfe,0x2f,0x01,0xcc,0xb3,0x10,0xd1,0x3f,0x8d,0x11,0x00,0x83,0x08,0x88,0x50, - 0x0c,0x31,0x42,0x39,0x89,0x54,0x21,0x42,0x08,0x81,0xd8,0x1c,0x41,0x30,0x47,0x00, - 0x06,0xc3,0x08,0xc2,0x53,0x90,0x70,0xd2,0x70,0xd0,0x01,0x8a,0x03,0x01,0x29,0xf0, - 0x86,0x11,0x86,0x67,0x18,0x61,0x00,0x86,0x11,0x88,0x67,0x8e,0x00,0x14,0x06,0x11, - 0x00,0x61,0x04,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83, - 0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37, - 0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80, - 0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06, - 0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40, - 0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78, - 0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10, - 0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07, - 0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6, - 0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60, - 0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07, - 0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71, - 0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80, - 0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98,0x05,0x00,0x80,0x00, - 0x00,0x00,0x00,0x00,0x80,0x21,0x4c,0x03,0x04,0x80,0x00,0x00,0x00,0x00,0x00,0xc0, - 0x10,0x46,0x02,0x02,0x60,0x00,0x00,0x00,0x00,0x00,0x20,0x0b,0x04,0x09,0x00,0x00, - 0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43, - 0x7a,0x23,0x00,0x25,0x50,0x08,0x45,0x50,0x10,0x65,0x40,0x78,0x04,0x80,0xe8,0x58, - 0x02,0x24,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xf9,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x63, - 0x4c,0x00,0xa5,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x3c,0xc4,0x24,0x3c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x30,0x11,0x43,0x8c,0x87, - 0x78,0x8e,0x67,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x99,0x8e,0x87,0x78,0x88, - 0x67,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x98, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x69,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d,0x11,0xa6,0x86,0x51,0x58,0x9a,0x9c,0x8b, - 0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34, - 0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a, - 0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc, - 0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61, - 0xa6,0xe7,0x19,0x26,0x68,0x8a,0x26,0x69,0x9a,0x86,0x08,0x13,0x45,0x29,0x2c,0x4d, - 0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e, - 0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39, - 0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73, - 0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4, - 0xd9,0x0d,0x91,0x9e,0x61,0xb2,0xa6,0x6b,0xc2,0xa6,0x6c,0x82,0x26,0x6d,0x92,0xa6, - 0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37, - 0xb6,0x37,0xb9,0x21,0xd2,0x43,0x4c,0xd6,0xd4,0x4d,0xd8,0x94,0x4d,0xd0,0x14,0x4d, - 0xd2,0xe4,0x51,0x09,0x4b,0x93,0x73,0x11,0xab,0x33,0x33,0x2b,0x93,0xe3,0x13,0x96, - 0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xf7,0x35,0x97,0xa6,0x57,0x46,0x29,0x2c, - 0x4d,0xce,0x85,0xed,0x6d,0x2c,0x8c,0x2e,0xed,0xcd,0xed,0x2b,0xcd,0x8d,0xac,0x0c, - 0x8f,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39, - 0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x16, - 0x66,0x6c,0x6f,0x61,0x74,0x1c,0xe0,0xda,0xc2,0x86,0x28,0xcf,0xf0,0x14,0xcf,0x30, - 0x95,0xc1,0x64,0x06,0x8c,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0, - 0xca,0xbe,0xe6,0xd2,0xf4,0xca,0x78,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1, - 0xe5,0xc1,0x95,0x7d,0x85,0xb1,0xa5,0x9d,0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0x31, - 0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b,0xe3,0xf0,0x55,0x33,0x33,0x84,0x0c,0x1e, - 0x63,0x02,0x83,0x29,0x0c,0x9e,0x62,0x12,0x83,0x67,0x78,0x88,0x69,0x0c,0x26,0x32, - 0x98,0xce,0x60,0x42,0x83,0xa7,0x98,0xd2,0xe0,0x29,0x26,0x68,0x52,0x83,0x49,0x9a, - 0xd6,0x80,0x4b,0x58,0x9a,0x9c,0x0b,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x19,0x95,0xb0, - 0x34,0x39,0x97,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x62,0x74,0x65,0x78,0x74,0x75,0x72, - 0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c, - 0x65,0x3e,0x1c,0xe8,0xca,0xf0,0x86,0x50,0x0f,0x32,0xb5,0xc1,0x24,0x06,0xcf,0xf0, - 0x10,0x93,0x1b,0x4c,0xd0,0xf4,0x06,0x93,0x34,0xc1,0x01,0x97,0xb0,0x34,0x39,0x97, - 0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39,0x1e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x1c, - 0xe6,0xda,0xe0,0x86,0x48,0x4f,0x31,0xc9,0xc1,0x24,0x06,0xcf,0xf0,0x10,0x13,0x34, - 0xcd,0xc1,0x24,0x4d,0x74,0x30,0x44,0x99,0xb8,0xe9,0x9b,0xd8,0x60,0x8a,0x83,0xa9, - 0x0e,0x86,0x18,0x0b,0x30,0x55,0x93,0x1d,0xd0,0xf9,0xd2,0xa2,0x9a,0xca,0x31,0x9b, - 0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b,0xe3,0xf3,0xd6,0xe6,0x96,0x06,0xf7,0x46,0x57, - 0xe6,0x46,0x07,0x32,0x86,0x16,0x26,0xc7,0x67,0x2a,0xad,0x0d,0x8e,0xad,0x0c,0x64, - 0x68,0x65,0x05,0x84,0x4a,0x28,0x28,0x68,0x88,0x30,0xe9,0xc1,0x10,0x63,0xca,0x83, - 0x69,0x0f,0xb0,0x64,0x88,0x31,0x95,0xc1,0xc4,0x07,0x58,0x32,0xc4,0x98,0xf0,0x60, - 0xea,0x03,0x2c,0x19,0x62,0x4c,0x7e,0x30,0xf5,0x01,0x96,0x8c,0x88,0xd8,0x81,0x1d, - 0xec,0xa1,0x1d,0xdc,0xa0,0x1d,0xde,0x81,0x1c,0xea,0x81,0x1d,0xca,0xc1,0x0d,0xcc, - 0x81,0x1d,0xc2,0xe1,0x1c,0xe6,0x61,0x8a,0x10,0x0c,0x23,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x48,0x07,0x72,0x28,0x07,0x77,0xa0,0x87,0x29,0x41,0x31,0x62,0x09, - 0x87,0x74,0x90,0x07,0x37,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87, - 0x29,0x81,0x31,0x82,0x0a,0x87,0x74,0x90,0x07,0x37,0x60,0x87,0x70,0x70,0x87,0x73, - 0xa8,0x87,0x70,0x38,0x87,0x72,0xf8,0x05,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78, - 0x07,0x77,0x98,0x12,0x20,0x23,0xa6,0x70,0x48,0x07,0x79,0x70,0x83,0x71,0x78,0x87, - 0x76,0x80,0x87,0x74,0x60,0x87,0x72,0xf8,0x85,0x77,0x80,0x07,0x7a,0x48,0x87,0x77, - 0x70,0x87,0x79,0x98,0x32,0x28,0x8c,0x33,0x82,0x09,0x87,0x74,0x90,0x07,0x37,0x30, - 0x07,0x79,0x08,0x87,0x73,0x68,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0xdc,0x01,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x0b,0x00,0x00,0x00,0x26,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x6d,0x01,0x0d,0x80,0x44,0x3e,0x83, - 0x5c,0x7e,0x85,0x17,0xb7,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x25,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x74,0x47,0x00, - 0xc6,0x22,0x80,0x40,0x38,0xe6,0x20,0x06,0xc2,0xa8,0xc8,0xd5,0xc0,0x08,0x00,0xbd, - 0x19,0x00,0x82,0x23,0x00,0x54,0xc7,0x1a,0x80,0x40,0x18,0x6b,0x18,0x86,0x81,0xec, - 0x0c,0x00,0x89,0x19,0x00,0x0a,0x33,0x00,0x04,0x46,0x00,0x00,0x00,0x23,0x06,0xca, - 0x10,0x6c,0x8f,0x23,0x29,0x47,0x12,0x58,0x20,0xc9,0x67,0x90,0x21,0x20,0x90,0x41, - 0x06,0xa1,0x40,0x4c,0x08,0xe4,0x33,0xc8,0x10,0x24,0xd0,0x20,0x43,0x50,0x48,0x16, - 0x60,0xf2,0x19,0x6f,0xc0,0x38,0x31,0xa0,0x60,0xcc,0x31,0x30,0x01,0x19,0x0c,0x32, - 0x04,0x0d,0x36,0x62,0x60,0x08,0x01,0x1a,0x2c,0x45,0x30,0xdb,0x00,0x05,0x40,0x06, - 0x01,0x31,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5b,0x86,0x24,0xf8,0x03,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const char _sspine_vs_source_metal_sim[624] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x7d,0x3b,0x0a, - 0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75, - 0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x75, - 0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d, - 0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74, - 0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28, - 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32, - 0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74, - 0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b, - 0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f, - 0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b, - 0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, - 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, - 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39, - 0x2e,0x6d,0x76,0x70,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e, - 0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76, - 0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -static const char _sspine_fs_source_metal_sim[619] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x66, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x20,0x70,0x6d,0x61,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74, - 0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30, - 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28, - 0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65, - 0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, - 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, - 0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d, - 0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x66,0x73,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x35,0x33,0x20,0x5b,0x5b,0x62,0x75,0x66, - 0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72, - 0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65,0x78,0x20,0x5b, - 0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d, - 0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x5f,0x32,0x38,0x20,0x3d,0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65, - 0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e,0x75,0x76,0x29,0x20,0x2a,0x20,0x69, - 0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x20,0x5f,0x33,0x37,0x20,0x3d,0x20,0x5f,0x32,0x38,0x2e,0x77,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x5f,0x32,0x38,0x2c,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x28,0x5f,0x32,0x38,0x2e,0x78,0x79,0x7a,0x20,0x2a,0x20,0x5f, - 0x33,0x37,0x2c,0x20,0x5f,0x33,0x37,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f, - 0x6c,0x6f,0x72,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x5f,0x35,0x33,0x2e, - 0x70,0x6d,0x61,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72, - 0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_WGPU) -static const char _sspine_vs_source_wgsl[1003] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x6d,0x76,0x70,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78,0x34,0x66,0x2c,0x0a, - 0x7d,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29,0x20,0x40,0x62,0x69, - 0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76,0x61,0x72,0x3c,0x75,0x6e,0x69, - 0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70, - 0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74, - 0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a, - 0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20, - 0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x32,0x20,0x3a,0x20,0x6d, - 0x61,0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x6d,0x76, - 0x70,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x36,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x5f,0x31,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x32,0x20,0x2a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x28,0x78,0x5f,0x32,0x36,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x36,0x2e,0x79, - 0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a, - 0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x38,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x33,0x38,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x34,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x32,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75, - 0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61, - 0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c, - 0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78, - 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65, - 0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const char _sspine_fs_source_wgsl[1125] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x70,0x6d,0x61,0x20,0x3a,0x20,0x66,0x33,0x32,0x2c,0x0a,0x7d,0x0a,0x0a,0x40, - 0x67,0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e, - 0x67,0x28,0x33,0x32,0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20, - 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b, - 0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e, - 0x64,0x69,0x6e,0x67,0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70, - 0x20,0x3a,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e, - 0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29,0x20, - 0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x29,0x20,0x76,0x61,0x72,0x3c, - 0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x35,0x33,0x20,0x3a,0x20, - 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d, - 0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20,0x76,0x61,0x72,0x20, - 0x63,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x20,0x20,0x76,0x61, - 0x72,0x20,0x63,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x63,0x30,0x20,0x3d,0x20,0x28,0x78, - 0x5f,0x32,0x34,0x20,0x2a,0x20,0x78,0x5f,0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x33,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x30,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x37, - 0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x63,0x30,0x2e,0x77,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x38,0x20,0x3a,0x20,0x76,0x65,0x63,0x33, - 0x66,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x33,0x66,0x28,0x78,0x5f,0x33,0x31,0x2e, - 0x78,0x2c,0x20,0x78,0x5f,0x33,0x31,0x2e,0x79,0x2c,0x20,0x78,0x5f,0x33,0x31,0x2e, - 0x7a,0x29,0x20,0x2a,0x20,0x78,0x5f,0x33,0x37,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x34,0x30,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x63, - 0x30,0x2e,0x77,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x35,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x20,0x20,0x63,0x31,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x34,0x66,0x28,0x78, - 0x5f,0x33,0x38,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x33,0x38,0x2e,0x79,0x2c,0x20,0x78, - 0x5f,0x33,0x38,0x2e,0x7a,0x2c,0x20,0x78,0x5f,0x34,0x30,0x29,0x20,0x2a,0x20,0x78, - 0x5f,0x34,0x35,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x39, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x30,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x35,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x20,0x3d,0x20,0x63,0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f, - 0x35,0x38,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x78,0x5f,0x35,0x33,0x2e, - 0x70,0x6d,0x61,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x78,0x5f,0x34,0x39,0x2c,0x20,0x78,0x5f, - 0x35,0x30,0x2c,0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x35,0x38,0x2c,0x20, - 0x78,0x5f,0x35,0x38,0x2c,0x20,0x78,0x5f,0x35,0x38,0x2c,0x20,0x78,0x5f,0x35,0x38, - 0x29,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a, - 0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74, - 0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30, - 0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66,0x72, - 0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20, - 0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20, - 0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29, - 0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29,0x3b, - 0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sspine_vs_source_dummy = ""; -static const char* _sspine_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs - -#define _sspine_def(val, def) (((val) == 0) ? (def) : (val)) -#define _SSPINE_INIT_COOKIE (0xABBAABBA) -#define _SSPINE_INVALID_SLOT_INDEX (0) -#define _SSPINE_DEFAULT_CONTEXT_POOL_SIZE (4) -#define _SSPINE_DEFAULT_ATLAS_POOL_SIZE (64) -#define _SSPINE_DEFAULT_SKELETON_POOL_SIZE (64) -#define _SSPINE_DEFAULT_SKINSET_POOL_SIZE (64) -#define _SSPINE_DEFAULT_INSTANCE_POOL_SIZE (1024) -#define _SSPINE_DEFAULT_MAX_VERTICES (1<<16) -#define _SSPINE_DEFAULT_MAX_COMMANDS (1<<14) -#define _SSPINE_MAX_TRIGGERED_EVENTS (16) -#define _SSPINE_SLOT_SHIFT (16) -#define _SSPINE_MAX_POOL_SIZE (1<<_SSPINE_SLOT_SHIFT) -#define _SSPINE_SLOT_MASK (_SSPINE_MAX_POOL_SIZE-1) - -typedef struct { - float mvp[16]; -} _sspine_vsparams_t; - -typedef struct { - float pma; - uint8_t _pad[12]; -} _sspine_fsparams_t; - -typedef struct { - uint32_t id; - sspine_resource_state state; -} _sspine_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sspine_pool_t; - -typedef struct { - _sspine_slot_t slot; - sspine_atlas_overrides overrides; - spAtlas* sp_atlas; - int num_pages; -} _sspine_atlas_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_atlas_t* items; -} _sspine_atlas_pool_t; - -typedef struct { - uint32_t id; - _sspine_atlas_t* ptr; -} _sspine_atlas_ref_t; - -typedef struct { - sg_image img; - sg_sampler smp; -} _sspine_image_sampler_pair_t; - -typedef struct { - _sspine_slot_t slot; - _sspine_atlas_ref_t atlas; - spSkeletonData* sp_skel_data; - spAnimationStateData* sp_anim_data; - struct { - int cap; - sspine_vec2* ptr; - } tform_buf; -} _sspine_skeleton_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_skeleton_t* items; -} _sspine_skeleton_pool_t; - -typedef struct { - uint32_t id; - _sspine_skeleton_t* ptr; -} _sspine_skeleton_ref_t; - -typedef struct { - _sspine_slot_t slot; - _sspine_skeleton_ref_t skel; - spSkin* sp_skin; -} _sspine_skinset_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_skinset_t* items; -} _sspine_skinset_pool_t; - -typedef struct { - uint32_t id; - _sspine_skinset_t* ptr; -} _sspine_skinset_ref_t; - -typedef struct { - _sspine_slot_t slot; - _sspine_atlas_ref_t atlas; - _sspine_skeleton_ref_t skel; - _sspine_skinset_ref_t skinset; - spSkeleton* sp_skel; - spAnimationState* sp_anim_state; - spSkeletonClipping* sp_clip; - int cur_triggered_event_index; - sspine_triggered_event_info triggered_events[_SSPINE_MAX_TRIGGERED_EVENTS]; -} _sspine_instance_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_instance_t* items; -} _sspine_instance_pool_t; - -typedef struct { - sspine_vec2 pos; - sspine_vec2 uv; - uint32_t color; -} _sspine_vertex_t; - -typedef struct { - _sspine_vertex_t* ptr; - int index; -} _sspine_alloc_vertices_result_t; - -typedef struct { - uint32_t* ptr; - int index; -} _sspine_alloc_indices_result_t; - -typedef struct { - int layer; - sg_pipeline pip; - sg_image img; - sg_sampler smp; - float pma; // pma = 0.0: use texture color as is, pma = 1.0: multiply texture rgb by texture alpha in fragment shader - int base_element; - int num_elements; -} _sspine_command_t; - -typedef struct { - _sspine_slot_t slot; - float transform[16]; - struct { - int cap; - int next; - uint32_t rewind_frame_id; - _sspine_vertex_t* ptr; - } vertices; - struct { - int cap; - int next; - uint32_t rewind_frame_id; - uint32_t* ptr; - } indices; - struct { - int cap; - int next; - uint32_t rewind_frame_id; - _sspine_command_t* ptr; - } commands; - uint32_t update_frame_id; - sg_buffer vbuf; - sg_buffer ibuf; - struct { - sg_pipeline normal_additive; - sg_pipeline multiply; - } pip; - sg_bindings bind; -} _sspine_context_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_context_t* items; -} _sspine_context_pool_t; - -typedef struct { - uint32_t init_cookie; - uint32_t frame_id; - sspine_desc desc; - sspine_context def_ctx_id; - sspine_context cur_ctx_id; - _sspine_context_t* cur_ctx; // may be 0! - sg_shader shd; - _sspine_context_pool_t context_pool; - _sspine_atlas_pool_t atlas_pool; - _sspine_skeleton_pool_t skeleton_pool; - _sspine_skinset_pool_t skinset_pool; - _sspine_instance_pool_t instance_pool; -} _sspine_t; -static _sspine_t _sspine; - -// dummy spine-c platform implementation functions -#if defined(__cplusplus) -extern "C" { -#endif -void _spAtlasPage_createTexture(spAtlasPage* self, const char* path) { - // nothing to do here - (void)self; (void)path; -} - -static void _sspine_delete_image_sampler_pair(const _sspine_image_sampler_pair_t* isp); -void _spAtlasPage_disposeTexture(spAtlasPage* self) { - _sspine_delete_image_sampler_pair((const _sspine_image_sampler_pair_t*) self->rendererObject); -} - -char* _spUtil_readFile(const char* path, int* length) { - (void)path; - *length = 0; - return 0; -} -#if defined(__cplusplus) -} // extern "C" -#endif - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SSPINE_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sspine_log_messages[] = { - _SSPINE_LOG_ITEMS -}; -#undef _SSPINE_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SSPINE_PANIC(code) _sspine_log(SSPINE_LOGITEM_ ##code, 0, __LINE__) -#define _SSPINE_ERROR(code) _sspine_log(SSPINE_LOGITEM_ ##code, 1, __LINE__) -#define _SSPINE_WARN(code) _sspine_log(SSPINE_LOGITEM_ ##code, 2, __LINE__) -#define _SSPINE_INFO(code) _sspine_log(SSPINE_LOGITEM_ ##code, 3, __LINE__) - -static void _sspine_log(sspine_log_item log_item, uint32_t log_level, uint32_t line_nr) { - if (_sspine.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sspine_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sspine.desc.logger.func("sspine", log_level, log_item, message, line_nr, filename, _sspine.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _sspine_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -/* Copy a string into a fixed size buffer with guaranteed zero- - termination. - - Return false if the string didn't fit into the buffer and had to be clamped. - - FIXME: Currently UTF-8 strings might become invalid if the string - is clamped, because the last zero-byte might be written into - the middle of a multi-byte sequence. -*/ -static bool _sspine_strcpy(const char* src, char* dst, int max_len) { - SOKOL_ASSERT(src && dst && (max_len > 0)); - char* const end = &(dst[max_len-1]); - char c = 0; - for (int i = 0; i < max_len; i++) { - c = *src; - if (c != 0) { - src++; - } - *dst++ = c; - } - // truncated? - if (c != 0) { - *end = 0; - return false; - } else { - return true; - } -} - -static sspine_string _sspine_string(const char* cstr) { - sspine_string res; - _sspine_clear(&res, sizeof(res)); - if (cstr) { - res.valid = true; - res.truncated = !_sspine_strcpy(cstr, res.cstr, sizeof(res.cstr)); - res.len = (uint8_t)strlen(res.cstr); - } - return res; -} - -static void* _sspine_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sspine.desc.allocator.alloc_fn) { - ptr = _sspine.desc.allocator.alloc_fn(size, _sspine.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SSPINE_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _sspine_malloc_clear(size_t size) { - void* ptr = _sspine_malloc(size); - _sspine_clear(ptr, size); - return ptr; -} - -static void _sspine_free(void* ptr) { - if (_sspine.desc.allocator.free_fn) { - _sspine.desc.allocator.free_fn(ptr, _sspine.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ███████ ███████ ███████ -// ██ ██ ██ ██ ██ -// ██████ █████ █████ ███████ -// ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ███████ -// -// >>refs -static bool _sspine_atlas_ref_valid(const _sspine_atlas_ref_t* ref) { - return ref->ptr && (ref->ptr->slot.id == ref->id); -} - -static bool _sspine_skeleton_ref_valid(const _sspine_skeleton_ref_t* ref) { - return ref->ptr && (ref->ptr->slot.id == ref->id); -} - -static bool _sspine_skinset_ref_valid(const _sspine_skinset_ref_t* ref) { - return ref->ptr && (ref->ptr->slot.id == ref->id); -} - -static bool _sspine_skeleton_and_deps_valid(_sspine_skeleton_t* skeleton) { - return skeleton && _sspine_atlas_ref_valid(&skeleton->atlas); -} - -static bool _sspine_skinset_and_deps_valid(_sspine_skinset_t* skinset) { - return skinset && _sspine_skeleton_ref_valid(&skinset->skel); -} - -static bool _sspine_instance_and_deps_valid(_sspine_instance_t* instance) { - return instance && - _sspine_atlas_ref_valid(&instance->atlas) && - _sspine_skeleton_ref_valid(&instance->skel) && - ((instance->skinset.id == SSPINE_INVALID_ID) || _sspine_skinset_ref_valid(&instance->skinset)); -} - -static sspine_image _sspine_image(uint32_t atlas_id, int index) { - sspine_image img = { atlas_id, index }; - return img; -} - -static sspine_atlas_page _sspine_atlas_page(uint32_t atlas_id, int index) { - sspine_atlas_page page = { atlas_id, index }; - return page; -} - -static sspine_anim _sspine_anim(uint32_t skeleton_id, int index) { - sspine_anim anim = { skeleton_id, index }; - return anim; -} - -static sspine_bone _sspine_bone(uint32_t skeleton_id, int index) { - sspine_bone bone = { skeleton_id, index }; - return bone; -} - -static sspine_slot _sspine_slot(uint32_t skeleton_id, int index) { - sspine_slot slot = { skeleton_id, index }; - return slot; -} - -static sspine_event _sspine_event(uint32_t skeleton_id, int index) { - sspine_event event = { skeleton_id, index }; - return event; -} - -static sspine_iktarget _sspine_iktarget(uint32_t skeleton_id, int index) { - sspine_iktarget iktarget = { skeleton_id, index }; - return iktarget; -} - -static sspine_skin _sspine_skin(uint32_t skeleton_id, int index) { - sspine_skin skin = { skeleton_id, index }; - return skin; -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _sspine_init_pool(_sspine_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _sspine_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _sspine_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _sspine_discard_pool(_sspine_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sspine_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sspine_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _sspine_pool_alloc_index(_sspine_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SSPINE_INVALID_SLOT_INDEX; - } -} - -static void _sspine_pool_free_index(_sspine_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* initialize a pool slot: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the handle id -*/ -static uint32_t _sspine_slot_init(_sspine_pool_t* pool, _sspine_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == SSPINE_RESOURCESTATE_INITIAL) && (slot->id == SSPINE_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SSPINE_SLOT_SHIFT)|(slot_index & _SSPINE_SLOT_MASK); - slot->state = SSPINE_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _sspine_slot_index(uint32_t id) { - int slot_index = (int) (id & _SSPINE_SLOT_MASK); - SOKOL_ASSERT(_SSPINE_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -static void _sspine_init_item_pool(_sspine_pool_t* pool, int pool_size, void** items_ptr, size_t item_size_bytes) { - // NOTE: the pools will have an additional item, since slot 0 is reserved - SOKOL_ASSERT(pool && (pool->size == 0)); - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SSPINE_MAX_POOL_SIZE)); - SOKOL_ASSERT(items_ptr && (*items_ptr == 0)); - SOKOL_ASSERT(item_size_bytes > 0); - _sspine_init_pool(pool, pool_size); - const size_t pool_size_bytes = item_size_bytes * (size_t)pool->size; - *items_ptr = _sspine_malloc_clear(pool_size_bytes); -} - -static void _sspine_discard_item_pool(_sspine_pool_t* pool, void** items_ptr) { - SOKOL_ASSERT(pool && (pool->size != 0)); - SOKOL_ASSERT(items_ptr && (*items_ptr != 0)); - _sspine_free(*items_ptr); *items_ptr = 0; - _sspine_discard_pool(pool); -} - -// ██████ ██████ ███ ██ ████████ ███████ ██ ██ ████████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ████ ██ ███████ ██ ██ ██ -// -// >>context -static void _sspine_setup_context_pool(int pool_size) { - _sspine_context_pool_t* p = &_sspine.context_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_context_t)); -} - -static void _sspine_discard_context_pool(void) { - _sspine_context_pool_t* p = &_sspine.context_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_context _sspine_make_context_handle(uint32_t id) { - sspine_context handle = { id }; - return handle; -} - -static _sspine_context_t* _sspine_context_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_context_pool_t* p = &_sspine.context_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_context_t* _sspine_lookup_context(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_context_t* ctx = _sspine_context_at(id); - if (ctx->slot.id == id) { - return ctx; - } - } - return 0; -} - -static sspine_context _sspine_alloc_context(void) { - _sspine_context_pool_t* p = &_sspine.context_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_context_handle(id); - } else { - // pool exhausted - return _sspine_make_context_handle(SSPINE_INVALID_ID); - } -} - -static sspine_resource_state _sspine_init_context(_sspine_context_t* ctx, const sspine_context_desc* desc) { - SOKOL_ASSERT(ctx && (ctx->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - // setup vertex, index and command storage - ctx->vertices.cap = desc->max_vertices; - ctx->indices.cap = ctx->vertices.cap * 3; - ctx->commands.cap = desc->max_commands; - - const size_t vbuf_size = (size_t)ctx->vertices.cap * sizeof(_sspine_vertex_t); - const size_t ibuf_size = (size_t)ctx->indices.cap * sizeof(uint32_t); - const size_t cbuf_size = (size_t)ctx->commands.cap * sizeof(_sspine_command_t); - - ctx->vertices.ptr = (_sspine_vertex_t*) _sspine_malloc(vbuf_size); - ctx->indices.ptr = (uint32_t*) _sspine_malloc(ibuf_size); - ctx->commands.ptr = (_sspine_command_t*) _sspine_malloc(cbuf_size); - - sg_buffer_desc vbuf_desc; - _sspine_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.size = vbuf_size; - vbuf_desc.label = "sspine-vbuf"; - ctx->vbuf = sg_make_buffer(&vbuf_desc); - ctx->bind.vertex_buffers[0] = ctx->vbuf; - - sg_buffer_desc ibuf_desc; - _sspine_clear(&ibuf_desc, sizeof(ibuf_desc)); - ibuf_desc.type = SG_BUFFERTYPE_INDEXBUFFER; - ibuf_desc.usage = SG_USAGE_STREAM; - ibuf_desc.size = ibuf_size; - ibuf_desc.label = "sspine-ibuf"; - ctx->ibuf = sg_make_buffer(&ibuf_desc); - ctx->bind.index_buffer = ctx->ibuf; - - // for blend modes, see: https://wiki.libsdl.org/SDL_BlendMode - // - // NOTE: we're configuring the blend mode for premultiplied alpha, - // and then do the premultiplication in the fragment shader - // if needed - sg_pipeline_desc pip_desc; - _sspine_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.shader = _sspine.shd; - pip_desc.layout.buffers[0].stride = sizeof(_sspine_vertex_t); - pip_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT2; - pip_desc.layout.attrs[1].format = SG_VERTEXFORMAT_FLOAT2; - pip_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; - pip_desc.index_type = SG_INDEXTYPE_UINT32; - pip_desc.sample_count = desc->sample_count; - pip_desc.depth.pixel_format = desc->depth_format; - pip_desc.colors[0].pixel_format = desc->color_format; - pip_desc.colors[0].write_mask = desc->color_write_mask; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.label = "sspine-pip-normal/additive"; - ctx->pip.normal_additive = sg_make_pipeline(&pip_desc); - - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_SRC_COLOR; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.label = "sspine-pip-multiply"; - ctx->pip.multiply = sg_make_pipeline(&pip_desc); - - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_context(_sspine_context_t* ctx) { - // NOTE: it's ok to call sg_destroy functions with invalid handles - sg_destroy_pipeline(ctx->pip.normal_additive); - sg_destroy_pipeline(ctx->pip.multiply); - sg_destroy_buffer(ctx->ibuf); - sg_destroy_buffer(ctx->vbuf); - if (ctx->commands.ptr) { - _sspine_free(ctx->commands.ptr); - ctx->commands.ptr = 0; - } - if (ctx->indices.ptr) { - _sspine_free(ctx->indices.ptr); - ctx->indices.ptr = 0; - } - if (ctx->vertices.ptr) { - _sspine_free(ctx->vertices.ptr); - ctx->vertices.ptr = 0; - } -} - -static void _sspine_destroy_context(sspine_context ctx_id) { - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - _sspine_deinit_context(ctx); - _sspine_context_pool_t* p = &_sspine.context_pool; - _sspine_clear(ctx, sizeof(_sspine_context_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(ctx_id.id)); - } -} - -static void _sspine_destroy_all_contexts(void) { - _sspine_context_pool_t* p = &_sspine.context_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_context_t* ctx = &p->items[i]; - _sspine_destroy_context(_sspine_make_context_handle(ctx->slot.id)); - } -} - -static sspine_context_desc _sspine_context_desc_defaults(const sspine_context_desc* desc) { - sspine_context_desc res = *desc; - res.max_vertices = _sspine_def(desc->max_vertices, _SSPINE_DEFAULT_MAX_VERTICES); - res.max_commands = _sspine_def(desc->max_commands, _SSPINE_DEFAULT_MAX_COMMANDS); - return res; -} - -static bool _sspine_is_default_context(sspine_context ctx_id) { - return ctx_id.id == 0x00010001; -} - -// █████ ████████ ██ █████ ███████ -// ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██ ██ ███████ -// -// >>atlas -static void _sspine_setup_atlas_pool(int pool_size) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_atlas_t)); -} - -static void _sspine_discard_atlas_pool(void) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_atlas _sspine_make_atlas_handle(uint32_t id) { - sspine_atlas handle = { id }; - return handle; -} - -static _sspine_atlas_t* _sspine_atlas_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_atlas_t* _sspine_lookup_atlas(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_atlas_t* atlas = _sspine_atlas_at(id); - if (atlas->slot.id == id) { - return atlas; - } - } - return 0; -} - -static sspine_atlas _sspine_alloc_atlas(void) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_atlas_handle(id); - } else { - // pool exhausted - return _sspine_make_atlas_handle(SSPINE_INVALID_ID); - } -} - -static const _sspine_image_sampler_pair_t* _sspine_new_image_sampler_pair(sg_image img, sg_sampler smp) { - _sspine_image_sampler_pair_t* isp = (_sspine_image_sampler_pair_t*) _sspine_malloc_clear(sizeof(_sspine_image_sampler_pair_t)); - SOKOL_ASSERT(isp); - isp->img = img; - isp->smp = smp; - return isp; -} - -static void _sspine_delete_image_sampler_pair(const _sspine_image_sampler_pair_t* isp) { - if (isp) { - sg_destroy_sampler(isp->smp); - sg_destroy_image(isp->img); - _sspine_free((void*)isp); - } -} - -static sg_image _sspine_image_from_renderer_object(void* renderer_object) { - SOKOL_ASSERT(renderer_object); - const _sspine_image_sampler_pair_t* isp = (const _sspine_image_sampler_pair_t*)renderer_object; - return isp->img; -} - -static sg_sampler _sspine_sampler_from_renderer_object(void* renderer_object) { - SOKOL_ASSERT(renderer_object); - const _sspine_image_sampler_pair_t* isp = (const _sspine_image_sampler_pair_t*)renderer_object; - return isp->smp; -} - -static sspine_resource_state _sspine_init_atlas(_sspine_atlas_t* atlas, const sspine_atlas_desc* desc) { - SOKOL_ASSERT(atlas && (atlas->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - SOKOL_ASSERT(atlas->sp_atlas == 0); - - if ((0 == desc->data.ptr) || (0 == desc->data.size)) { - _SSPINE_ERROR(ATLAS_DESC_NO_DATA); - return SSPINE_RESOURCESTATE_FAILED; - } - atlas->overrides = desc->override; - - // NOTE: Spine doesn't detect when invalid or corrupt data is passed here, - // not much we can do about this... - atlas->sp_atlas = spAtlas_create((const char*)desc->data.ptr, (int)desc->data.size, "", 0); - if (0 == atlas->sp_atlas) { - _SSPINE_ERROR(SPINE_ATLAS_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - - // allocate a sokol-gfx image and sampler object for each page, but the actual - // initialization needs to be delegated to the application - for (spAtlasPage* page = atlas->sp_atlas->pages; page != 0; page = page->next) { - atlas->num_pages++; - const sg_image img = sg_alloc_image(); - if (sg_query_image_state(img) != SG_RESOURCESTATE_ALLOC) { - _SSPINE_ERROR(SG_ALLOC_IMAGE_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - const sg_sampler smp = sg_alloc_sampler(); - if (sg_query_sampler_state(smp) != SG_RESOURCESTATE_ALLOC) { - _SSPINE_ERROR(SG_ALLOC_SAMPLER_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - - // need to put the image and sampler handle into a heap-alloc unfortunately, - // because a void* isn't big enough to stash two 32-bit handles into - // it directly on platforms with 32-bit pointers (like wasm) - page->rendererObject = (void*) _sspine_new_image_sampler_pair(img, smp); - - if (desc->override.premul_alpha_enabled) { - // NOTE: -1 is spine-c convention for 'true' - page->pma = -1; - } else if (desc->override.premul_alpha_disabled) { - page->pma = 0; - } - } - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_atlas(_sspine_atlas_t* atlas) { - if (atlas->sp_atlas) { - spAtlas_dispose(atlas->sp_atlas); - atlas->sp_atlas = 0; - } -} - -static void _sspine_destroy_atlas(sspine_atlas atlas_id) { - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - _sspine_deinit_atlas(atlas); - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - _sspine_clear(atlas, sizeof(_sspine_atlas_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(atlas_id.id)); - } -} - -static void _sspine_destroy_all_atlases(void) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_atlas_t* atlas = &p->items[i]; - _sspine_destroy_atlas(_sspine_make_atlas_handle(atlas->slot.id)); - } -} - -static sspine_atlas_desc _sspine_atlas_desc_defaults(const sspine_atlas_desc* desc) { - sspine_atlas_desc res = *desc; - return res; -} - -static spAtlasPage* _sspine_lookup_atlas_page(uint32_t atlas_id, int page_index) { - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id); - if (atlas) { - if ((page_index >= 0) && (page_index < atlas->num_pages)) { - int i = 0; - for (spAtlasPage* page = atlas->sp_atlas->pages; page != 0; page = page->next, i++) { - if (i == page_index) { - return page; - } - } - } - } - return 0; -} - -// ███████ ██ ██ ███████ ██ ███████ ████████ ██████ ███ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ███████ █████ █████ ██ █████ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ███████ ███████ ███████ ██ ██████ ██ ████ -// -// >>skeleton -static void _sspine_setup_skeleton_pool(int pool_size) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_skeleton_t)); -} - -static void _sspine_discard_skeleton_pool(void) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_skeleton _sspine_make_skeleton_handle(uint32_t id) { - sspine_skeleton handle = { id }; - return handle; -} - -static _sspine_skeleton_t* _sspine_skeleton_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_skeleton_t* _sspine_lookup_skeleton(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_skeleton_t* skeleton = _sspine_skeleton_at(id); - if (skeleton->slot.id == id) { - return skeleton; - } - } - return 0; -} - -static sspine_skeleton _sspine_alloc_skeleton(void) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_skeleton_handle(id); - } else { - // pool exhausted - return _sspine_make_skeleton_handle(SSPINE_INVALID_ID); - } -} - -static sspine_resource_state _sspine_init_skeleton(_sspine_skeleton_t* skeleton, const sspine_skeleton_desc* desc) { - SOKOL_ASSERT(skeleton && (skeleton->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - if ((0 == desc->json_data) && ((0 == desc->binary_data.ptr) || (0 == desc->binary_data.size))) { - _SSPINE_ERROR(SKELETON_DESC_NO_DATA); - return SSPINE_RESOURCESTATE_FAILED; - } - if (desc->atlas.id == SSPINE_INVALID_ID) { - _SSPINE_ERROR(SKELETON_DESC_NO_ATLAS); - return SSPINE_RESOURCESTATE_FAILED; - } - - skeleton->atlas.id = desc->atlas.id; - skeleton->atlas.ptr = _sspine_lookup_atlas(skeleton->atlas.id); - if (!_sspine_atlas_ref_valid(&skeleton->atlas)) { - _SSPINE_ERROR(SKELETON_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - _sspine_atlas_t* atlas = skeleton->atlas.ptr; - if (SSPINE_RESOURCESTATE_VALID != atlas->slot.state) { - _SSPINE_ERROR(SKELETON_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(atlas->sp_atlas); - - if (desc->json_data) { - spSkeletonJson* skel_json = spSkeletonJson_create(atlas->sp_atlas); - SOKOL_ASSERT(skel_json); - skel_json->scale = desc->prescale; - skeleton->sp_skel_data = spSkeletonJson_readSkeletonData(skel_json, desc->json_data); - spSkeletonJson_dispose(skel_json); skel_json = 0; - if (0 == skeleton->sp_skel_data) { - _SSPINE_ERROR(CREATE_SKELETON_DATA_FROM_JSON_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - } else { - spSkeletonBinary* skel_bin = spSkeletonBinary_create(atlas->sp_atlas); - SOKOL_ASSERT(skel_bin); - skel_bin->scale = desc->prescale; - skeleton->sp_skel_data = spSkeletonBinary_readSkeletonData(skel_bin, (const unsigned char*)desc->binary_data.ptr, (int)desc->binary_data.size); - spSkeletonBinary_dispose(skel_bin); skel_bin = 0; - if (0 == skeleton->sp_skel_data) { - _SSPINE_ERROR(CREATE_SKELETON_DATA_FROM_BINARY_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - } - SOKOL_ASSERT(skeleton->sp_skel_data); - - skeleton->sp_anim_data = spAnimationStateData_create(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_anim_data); - skeleton->sp_anim_data->defaultMix = desc->anim_default_mix; - - // get the max number of vertices in any mesh attachment - int max_vertex_count = 4; // number of vertices in a 'region attachment' (a 2-triangle quad) - const spSkeletonData* sp_skel_data = skeleton->sp_skel_data; - for (int skinIndex = 0; skinIndex < sp_skel_data->skinsCount; skinIndex++) { - const spSkin* sp_skin = sp_skel_data->skins[skinIndex]; - const spSkinEntry* skin_entry = spSkin_getAttachments(sp_skin); - if (skin_entry) do { - if (skin_entry->attachment) { - if (skin_entry->attachment->type == SP_ATTACHMENT_MESH) { - const spMeshAttachment* mesh_attachment = (spMeshAttachment*)skin_entry->attachment; - // worldVerticesLength is number of floats - SOKOL_ASSERT((mesh_attachment->super.worldVerticesLength & 1) == 0); - const int num_vertices = mesh_attachment->super.worldVerticesLength / 2; - if (num_vertices > max_vertex_count) { - max_vertex_count = num_vertices; - } - } - } - } while ((skin_entry = skin_entry->next) != 0); - } - - // allocate a shared vertex transform buffer (big enough to hold vertices for biggest mesh attachment) - skeleton->tform_buf.cap = max_vertex_count; - skeleton->tform_buf.ptr = (sspine_vec2*) _sspine_malloc((size_t)skeleton->tform_buf.cap * sizeof(sspine_vec2)); - - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_skeleton(_sspine_skeleton_t* skeleton) { - if (skeleton->tform_buf.ptr) { - _sspine_free(skeleton->tform_buf.ptr); - skeleton->tform_buf.ptr = 0; - } - if (skeleton->sp_anim_data) { - spAnimationStateData_dispose(skeleton->sp_anim_data); - skeleton->sp_anim_data = 0; - } - if (skeleton->sp_skel_data) { - spSkeletonData_dispose(skeleton->sp_skel_data); - skeleton->sp_skel_data = 0; - } -} - -static void _sspine_destroy_skeleton(sspine_skeleton skeleton_id) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (skeleton) { - _sspine_deinit_skeleton(skeleton); - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - _sspine_clear(skeleton, sizeof(_sspine_skeleton_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(skeleton_id.id)); - } -} - -static void _sspine_destroy_all_skeletons(void) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_skeleton_t* skeleton = &p->items[i]; - _sspine_destroy_skeleton(_sspine_make_skeleton_handle(skeleton->slot.id)); - } -} - -static sspine_skeleton_desc _sspine_skeleton_desc_defaults(const sspine_skeleton_desc* desc) { - sspine_skeleton_desc res = *desc; - res.prescale = _sspine_def(desc->prescale, 1.0f); - res.anim_default_mix = _sspine_def(desc->anim_default_mix, 0.2f); - return res; -} - -static spBoneData* _sspine_lookup_bone_data(uint32_t skeleton_id, int bone_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->bones); - if ((bone_index >= 0) && (bone_index <= skeleton->sp_skel_data->bonesCount)) { - return skeleton->sp_skel_data->bones[bone_index]; - } - } - return 0; -} - -static spSlotData* _sspine_lookup_slot_data(uint32_t skeleton_id, int slot_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->slots); - if ((slot_index >= 0) && (slot_index <= skeleton->sp_skel_data->slotsCount)) { - return skeleton->sp_skel_data->slots[slot_index]; - } - } - return 0; -} - -static spEventData* _sspine_lookup_event_data(uint32_t skeleton_id, int event_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->events); - if ((event_index >= 0) && (event_index < skeleton->sp_skel_data->eventsCount)) { - return skeleton->sp_skel_data->events[event_index]; - } - } - return 0; -} - -static spIkConstraintData* _sspine_lookup_ikconstraint_data(uint32_t skeleton_id, int iktarget_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->ikConstraints); - if ((iktarget_index >= 0) && (iktarget_index < skeleton->sp_skel_data->ikConstraintsCount)) { - return skeleton->sp_skel_data->ikConstraints[iktarget_index]; - } - } - return 0; -} - -static spSkin* _sspine_lookup_skin(uint32_t skeleton_id, int skin_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->skins); - if ((skin_index >= 0) && (skin_index < skeleton->sp_skel_data->skinsCount)) { - return skeleton->sp_skel_data->skins[skin_index]; - } - } - return 0; -} - -// ███████ ██ ██ ██ ███ ██ ███████ ███████ ████████ -// ██ ██ ██ ██ ████ ██ ██ ██ ██ -// ███████ █████ ██ ██ ██ ██ ███████ █████ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██ ████ ███████ ███████ ██ -// -// >>skinset -static void _sspine_setup_skinset_pool(int pool_size) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_skinset_t)); -} - -static void _sspine_discard_skinset_pool(void) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_skinset _sspine_make_skinset_handle(uint32_t id) { - sspine_skinset handle = { id }; - return handle; -} - -static _sspine_skinset_t* _sspine_skinset_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_skinset_t* _sspine_lookup_skinset(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_skinset_t* skinset = _sspine_skinset_at(id); - if (skinset->slot.id == id) { - return skinset; - } - } - return 0; -} - -static sspine_skinset _sspine_alloc_skinset(void) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_skinset_handle(id); - } else { - // pool exhausted - return _sspine_make_skinset_handle(SSPINE_INVALID_ID); - } -} - -static sspine_resource_state _sspine_init_skinset(_sspine_skinset_t* skinset, const sspine_skinset_desc* desc) { - SOKOL_ASSERT(skinset && (skinset->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - if (desc->skeleton.id == SSPINE_INVALID_ID) { - _SSPINE_ERROR(SKINSET_DESC_NO_SKELETON); - return SSPINE_RESOURCESTATE_FAILED; - } - skinset->skel.id = desc->skeleton.id; - skinset->skel.ptr = _sspine_lookup_skeleton(desc->skeleton.id); - if (!_sspine_skeleton_ref_valid(&skinset->skel)) { - _SSPINE_ERROR(SKINSET_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - _sspine_skeleton_t* skel = skinset->skel.ptr; - if (SSPINE_RESOURCESTATE_VALID != skel->slot.state) { - _SSPINE_ERROR(SKINSET_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(skel->sp_skel_data); - skinset->sp_skin = spSkin_create("skinset"); - for (int i = 0; i < SSPINE_MAX_SKINSET_SKINS; i++) { - if (desc->skins[i].skeleton_id != SSPINE_INVALID_ID) { - spSkin* skin = _sspine_lookup_skin(desc->skins[i].skeleton_id, desc->skins[i].index); - if (0 == skin) { - _SSPINE_ERROR(SKINSET_INVALID_SKIN_HANDLE); - return SSPINE_RESOURCESTATE_FAILED; - } - spSkin_addSkin(skinset->sp_skin, skin); - } - } - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_skinset(_sspine_skinset_t* skinset) { - if (skinset->sp_skin) { - spSkin_clear(skinset->sp_skin); - spSkin_dispose(skinset->sp_skin); - skinset->sp_skin = 0; - } -} - -static void _sspine_destroy_skinset(sspine_skinset skinset_id) { - _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (skinset) { - _sspine_deinit_skinset(skinset); - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - _sspine_clear(skinset, sizeof(_sspine_skinset_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(skinset_id.id)); - } -} - -static void _sspine_destroy_all_skinsets(void) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_skinset_t* skinset = &p->items[i]; - _sspine_destroy_skinset(_sspine_make_skinset_handle(skinset->slot.id)); - } -} - -static sspine_skinset_desc _sspine_skinset_desc_defaults(const sspine_skinset_desc* desc) { - sspine_skinset_desc res = *desc; - return res; -} - -// ██ ███ ██ ███████ ████████ █████ ███ ██ ██████ ███████ -// ██ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ██ ██ ██ ███████ ██ ███████ ██ ██ ██ ██ █████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ████ ███████ ██ ██ ██ ██ ████ ██████ ███████ -// -// >>instance -static void _sspine_setup_instance_pool(int pool_size) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_instance_t)); -} - -static void _sspine_discard_instance_pool(void) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_instance _sspine_make_instance_handle(uint32_t id) { - sspine_instance handle = { id }; - return handle; -} - -static _sspine_instance_t* _sspine_instance_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_instance_pool_t* p = &_sspine.instance_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_instance_t* _sspine_lookup_instance(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_instance_t* instance = _sspine_instance_at(id); - if (instance->slot.id == id) { - return instance; - } - } - return 0; -} - -static sspine_instance _sspine_alloc_instance(void) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - sspine_instance res; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - res = _sspine_make_instance_handle(id); - } else { - // pool exhausted - res = _sspine_make_instance_handle(SSPINE_INVALID_ID); - } - return res; -} - -static void _sspine_rewind_triggered_events(_sspine_instance_t* instance) { - instance->cur_triggered_event_index = 0; - _sspine_clear(instance->triggered_events, sizeof(instance->triggered_events)); -} - -static sspine_triggered_event_info* _sspine_next_triggered_event_info(_sspine_instance_t* instance) { - if (instance->cur_triggered_event_index < _SSPINE_MAX_TRIGGERED_EVENTS) { - return &instance->triggered_events[instance->cur_triggered_event_index++]; - } else { - return 0; - } -} - -static void _sspine_event_listener(spAnimationState* sp_anim_state, spEventType sp_event_type, spTrackEntry* sp_track_entry, spEvent* sp_event) { - if (sp_event_type == SP_ANIMATION_EVENT) { - SOKOL_ASSERT(sp_anim_state && sp_track_entry && sp_event); (void)sp_track_entry; - SOKOL_ASSERT(sp_event->data && sp_event->data->name); - _sspine_instance_t* instance = _sspine_lookup_instance((uint32_t)(uintptr_t)sp_anim_state->userData); - if (_sspine_instance_and_deps_valid(instance)) { - sspine_triggered_event_info* info = _sspine_next_triggered_event_info(instance); - if (info) { - // FIXME: this sucks, but we really need the event index - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(instance->skel.id); - SOKOL_ASSERT(skeleton && skeleton->sp_skel_data->events); - const spEventData* sp_event_data = sp_event->data; - for (int i = 0; i < skeleton->sp_skel_data->eventsCount; i++) { - if (sp_event_data == skeleton->sp_skel_data->events[i]) { - info->event = _sspine_event(skeleton->slot.id, i); - break; - } - } - SOKOL_ASSERT(info->event.skeleton_id != SSPINE_INVALID_ID); - info->valid = true; - info->time = sp_event->time; - info->int_value = sp_event->intValue; - info->float_value = sp_event->floatValue; - info->volume = sp_event->volume; - info->balance = sp_event->balance; - info->string_value = _sspine_string(sp_event->stringValue); - if (info->string_value.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - } - } -} - -static sspine_resource_state _sspine_init_instance(_sspine_instance_t* instance, const sspine_instance_desc* desc) { - SOKOL_ASSERT(instance && (instance->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - if (desc->skeleton.id == SSPINE_INVALID_ID) { - _SSPINE_ERROR(INSTANCE_DESC_NO_SKELETON); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->skel.id = desc->skeleton.id; - instance->skel.ptr = _sspine_lookup_skeleton(instance->skel.id); - if (!_sspine_skeleton_ref_valid(&instance->skel)) { - _SSPINE_ERROR(INSTANCE_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - _sspine_skeleton_t* skel = instance->skel.ptr; - if (SSPINE_RESOURCESTATE_VALID != skel->slot.state) { - _SSPINE_ERROR(INSTANCE_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->atlas = skel->atlas; - if (!_sspine_atlas_ref_valid(&instance->atlas)) { - _SSPINE_ERROR(INSTANCE_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - if (SSPINE_RESOURCESTATE_VALID != instance->atlas.ptr->slot.state) { - _SSPINE_ERROR(INSTANCE_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(skel->sp_skel_data); - SOKOL_ASSERT(skel->sp_anim_data); - - instance->sp_skel = spSkeleton_create(skel->sp_skel_data); - if (0 == instance->sp_skel) { - _SSPINE_ERROR(SPINE_SKELETON_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->sp_anim_state = spAnimationState_create(skel->sp_anim_data); - if (0 == instance->sp_anim_state) { - _SSPINE_ERROR(SPINE_ANIMATIONSTATE_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->sp_clip = spSkeletonClipping_create(); - if (0 == instance->sp_clip) { - _SSPINE_ERROR(SPINE_SKELETONCLIPPING_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - - instance->sp_anim_state->userData = (void*)(uintptr_t)instance->slot.id; - instance->sp_anim_state->listener = _sspine_event_listener; - - spSkeleton_setToSetupPose(instance->sp_skel); - spAnimationState_update(instance->sp_anim_state, 0.0f); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - spSkeleton_updateWorldTransform(instance->sp_skel); - - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_instance(_sspine_instance_t* instance) { - if (instance->sp_clip) { - spSkeletonClipping_dispose(instance->sp_clip); - instance->sp_clip = 0; - } - if (instance->sp_anim_state) { - spAnimationState_dispose(instance->sp_anim_state); - instance->sp_anim_state = 0; - } - if (instance->sp_skel) { - spSkeleton_dispose(instance->sp_skel); - instance->sp_skel = 0; - } -} - -static void _sspine_destroy_instance(sspine_instance instance_id) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - _sspine_deinit_instance(instance); - _sspine_instance_pool_t* p = &_sspine.instance_pool; - _sspine_clear(instance, sizeof(_sspine_instance_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(instance_id.id)); - } -} - -static void _sspine_destroy_all_instances(void) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_instance_t* instance = &p->items[i]; - _sspine_destroy_instance(_sspine_make_instance_handle(instance->slot.id)); - } -} - -static spAnimation* _sspine_lookup_skeleton_anim(uint32_t skeleton_id, int anim_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - if ((anim_index >= 0) && (anim_index < skeleton->sp_skel_data->animationsCount)) { - return skeleton->sp_skel_data->animations[anim_index]; - } - } - return 0; -} - -static spAnimation* _sspine_lookup_instance_anim(uint32_t instance_id, uint32_t skeleton_id, int anim_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->data); - if ((anim_index >= 0) && (anim_index < instance->sp_skel->data->animationsCount)) { - return instance->sp_skel->data->animations[anim_index]; - } - } - return 0; -} - -static spBone* _sspine_lookup_bone(uint32_t instance_id, uint32_t skeleton_id, int bone_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->bones); - if ((bone_index >= 0) && (bone_index <= instance->sp_skel->bonesCount)) { - return instance->sp_skel->bones[bone_index]; - } - } - return 0; -} - -static spSlot* _sspine_lookup_slot(uint32_t instance_id, uint32_t skeleton_id, int slot_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->slots); - if ((slot_index >= 0) && (slot_index <= instance->sp_skel->slotsCount)) { - return instance->sp_skel->slots[slot_index]; - } - } - return 0; -} - -static spIkConstraint* _sspine_lookup_ikconstraint(uint32_t instance_id, uint32_t skeleton_id, int iktarget_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->ikConstraints); - if ((iktarget_index >= 0) && (iktarget_index < instance->sp_skel->ikConstraintsCount)) { - return instance->sp_skel->ikConstraints[iktarget_index]; - } - } - return 0; -} - -static sspine_instance_desc _sspine_instance_desc_defaults(const sspine_instance_desc* desc) { - sspine_instance_desc res = *desc; - return res; -} - -// ██████ ██████ █████ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██████ ███████ ██ █ ██ -// ██ ██ ██ ██ ██ ██ ██ ███ ██ -// ██████ ██ ██ ██ ██ ███ ███ -// -// >>draw -static void _sspine_check_rewind_commands(_sspine_context_t* ctx) { - if (_sspine.frame_id != ctx->commands.rewind_frame_id) { - ctx->commands.next = 0; - ctx->commands.rewind_frame_id = _sspine.frame_id; - } -} - -static _sspine_command_t* _sspine_next_command(_sspine_context_t* ctx) { - _sspine_check_rewind_commands(ctx); - if (ctx->commands.next < ctx->commands.cap) { - return &(ctx->commands.ptr[ctx->commands.next++]); - } else { - _SSPINE_ERROR(COMMAND_BUFFER_FULL); - return 0; - } -} - -static _sspine_command_t* _sspine_cur_command(_sspine_context_t* ctx) { - _sspine_check_rewind_commands(ctx); - if (ctx->commands.next > 0) { - return &ctx->commands.ptr[ctx->commands.next - 1]; - } else { - return 0; - } -} - -static void _sspine_check_rewind_vertices(_sspine_context_t* ctx) { - if (_sspine.frame_id != ctx->vertices.rewind_frame_id) { - ctx->vertices.next = 0; - ctx->vertices.rewind_frame_id = _sspine.frame_id; - } -} - -static _sspine_alloc_vertices_result_t _sspine_alloc_vertices(_sspine_context_t* ctx, int num) { - _sspine_check_rewind_vertices(ctx); - _sspine_alloc_vertices_result_t res; - _sspine_clear(&res, sizeof(res)); - if ((ctx->vertices.next + num) <= ctx->vertices.cap) { - res.ptr = &(ctx->vertices.ptr[ctx->vertices.next]); - res.index = ctx->vertices.next; - ctx->vertices.next += num; - } else { - _SSPINE_ERROR(VERTEX_BUFFER_FULL); - } - return res; -} - -static void _sspine_check_rewind_indices(_sspine_context_t* ctx) { - if (_sspine.frame_id != ctx->indices.rewind_frame_id) { - ctx->indices.next = 0; - ctx->indices.rewind_frame_id = _sspine.frame_id; - } -} - -static _sspine_alloc_indices_result_t _sspine_alloc_indices(_sspine_context_t* ctx, int num) { - _sspine_check_rewind_indices(ctx); - _sspine_alloc_indices_result_t res; - _sspine_clear(&res, sizeof(res)); - if ((ctx->indices.next + num) <= ctx->indices.cap) { - res.ptr = &(ctx->indices.ptr[ctx->indices.next]); - res.index = ctx->indices.next; - ctx->indices.next += num; - } else { - _SSPINE_ERROR(INDEX_BUFFER_FULL); - } - return res; -} - -static void _sspine_draw_instance(_sspine_context_t* ctx, _sspine_instance_t* instance, int layer) { - SOKOL_ASSERT(_sspine_instance_and_deps_valid(instance)); - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - SOKOL_ASSERT(instance->sp_clip); - - // see: https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-sdl/src/spine-sdl-c.c - const spSkeleton* sp_skel = instance->sp_skel; - float* tform_buf = (float*)instance->skel.ptr->tform_buf.ptr; - const int max_tform_buf_verts = instance->skel.ptr->tform_buf.cap; - SOKOL_UNUSED(max_tform_buf_verts); // only used in asserts - const int tform_buf_stride = 2; // each element is 2 floats - spSkeletonClipping* sp_clip = instance->sp_clip; - for (int slot_index = 0; slot_index < sp_skel->slotsCount; slot_index++) { - spSlot* sp_slot = sp_skel->drawOrder[slot_index]; - if (!sp_slot->attachment) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - // early out if the slot alpha is 0 or the bone is not active - // FIXME: does alpha 0 actually mean 'invisible' for all blend modes? - if ((sp_slot->color.a == 0) || (!sp_slot->bone->active)) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - int num_vertices = 0; - float* uvs = 0; - float* vertices = 0; - int num_indices = 0; - const uint16_t* indices = 0; - const spColor* att_color = 0; - sg_image img = { SG_INVALID_ID }; - sg_sampler smp = { SG_INVALID_ID }; - bool premul_alpha = false; - if (sp_slot->attachment->type == SP_ATTACHMENT_REGION) { - static const uint16_t quad_indices[] = { 0, 1, 2, 2, 3, 0 }; - spRegionAttachment* region = (spRegionAttachment*)sp_slot->attachment; - att_color = ®ion->color; - // FIXME(?) early out if the slot alpha is 0 - if (att_color->a == 0) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - spRegionAttachment_computeWorldVertices(region, sp_slot, tform_buf, 0, tform_buf_stride); - vertices = tform_buf; - num_vertices = 4; - indices = &quad_indices[0]; - num_indices = 6; - uvs = region->uvs; - const spAtlasPage* sp_page = ((spAtlasRegion*)region->rendererObject)->page; - img = _sspine_image_from_renderer_object(sp_page->rendererObject); - smp = _sspine_sampler_from_renderer_object(sp_page->rendererObject); - premul_alpha = sp_page->pma != 0; - } else if (sp_slot->attachment->type == SP_ATTACHMENT_MESH) { - spMeshAttachment* mesh = (spMeshAttachment*)sp_slot->attachment; - att_color = &mesh->color; - // FIXME(?) early out if the slot alpha is 0 - if (att_color->a == 0) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - const int num_floats = mesh->super.worldVerticesLength; - num_vertices = num_floats / 2; - SOKOL_ASSERT(num_vertices <= max_tform_buf_verts); - spVertexAttachment_computeWorldVertices(&mesh->super, sp_slot, 0, num_floats, tform_buf, 0, tform_buf_stride); - vertices = tform_buf; - indices = mesh->triangles; - num_indices = mesh->trianglesCount; // actually indicesCount??? - uvs = mesh->uvs; - const spAtlasPage* sp_page = ((spAtlasRegion*)mesh->rendererObject)->page; - img = _sspine_image_from_renderer_object(sp_page->rendererObject); - smp = _sspine_sampler_from_renderer_object(sp_page->rendererObject); - premul_alpha = sp_page->pma != 0; - } else if (sp_slot->attachment->type == SP_ATTACHMENT_CLIPPING) { - spClippingAttachment* clip_attachment = (spClippingAttachment*) sp_slot->attachment; - spSkeletonClipping_clipStart(sp_clip, sp_slot, clip_attachment); - continue; - } else { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - SOKOL_ASSERT(vertices && (num_vertices > 0)); - SOKOL_ASSERT(indices && (num_indices > 0)); - SOKOL_ASSERT(uvs); - SOKOL_ASSERT(img.id != SG_INVALID_ID); - SOKOL_ASSERT(smp.id != SG_INVALID_ID); - - if (spSkeletonClipping_isClipping(sp_clip)) { - spSkeletonClipping_clipTriangles(sp_clip, tform_buf, num_vertices * 2, (uint16_t*)indices, num_indices, uvs, tform_buf_stride); - vertices = sp_clip->clippedVertices->items; - num_vertices = sp_clip->clippedVertices->size / 2; - uvs = sp_clip->clippedUVs->items; - indices = sp_clip->clippedTriangles->items; - num_indices = sp_clip->clippedTriangles->size; - } - SOKOL_ASSERT(vertices); - SOKOL_ASSERT(indices); - SOKOL_ASSERT(uvs); - - // there might be no geometry to render after clipping - if ((0 == num_vertices) || (0 == num_indices)) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - const _sspine_alloc_vertices_result_t dst_vertices = _sspine_alloc_vertices(ctx, num_vertices); - const _sspine_alloc_indices_result_t dst_indices = _sspine_alloc_indices(ctx, num_indices); - if ((0 == dst_vertices.ptr) || (0 == dst_indices.ptr)) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - // write transformed and potentially clipped vertices and indices - const uint8_t r = (uint8_t)(sp_skel->color.r * sp_slot->color.r * att_color->r * 255.0f); - const uint8_t g = (uint8_t)(sp_skel->color.g * sp_slot->color.g * att_color->g * 255.0f); - const uint8_t b = (uint8_t)(sp_skel->color.b * sp_slot->color.b * att_color->b * 255.0f); - const uint8_t a = (uint8_t)(sp_skel->color.a * sp_slot->color.a * att_color->a * 255.0f); - const uint32_t color = (((uint32_t)a<<24) | ((uint32_t)b<<16) | ((uint32_t)g<<8) | (uint32_t)r); - for (int vi = 0; vi < num_vertices; vi++) { - dst_vertices.ptr[vi].pos.x = vertices[vi*2]; - dst_vertices.ptr[vi].pos.y = vertices[vi*2 + 1]; - dst_vertices.ptr[vi].color = color; - dst_vertices.ptr[vi].uv.x = uvs[vi*2]; - dst_vertices.ptr[vi].uv.y = uvs[vi*2 + 1]; - } - for (int ii = 0; ii < num_indices; ii++) { - dst_indices.ptr[ii] = (uint32_t)indices[ii] + (uint32_t)dst_vertices.index; - } - - sg_pipeline pip = { SG_INVALID_ID }; - // NOTE: pma == 0.0: use color from texture as is - // pma == 1.0: multiply texture rgb by texture alpha in fragment shader - float pma = 0.0f; - switch (sp_slot->data->blendMode) { - case SP_BLEND_MODE_NORMAL: - case SP_BLEND_MODE_ADDITIVE: - case SP_BLEND_MODE_SCREEN: - pip = ctx->pip.normal_additive; - pma = premul_alpha ? 0.0f : 1.0f; // NOT A BUG - break; - case SP_BLEND_MODE_MULTIPLY: - pip = ctx->pip.multiply; - pma = 0.0f; // always use texture color as is - break; - } - - // write new draw command, or merge with current draw command - _sspine_command_t* cur_cmd = _sspine_cur_command(ctx); - if (cur_cmd - && (cur_cmd->layer == layer) - && (cur_cmd->pip.id == pip.id) - && (cur_cmd->img.id == img.id) - && (cur_cmd->smp.id == smp.id) - && (cur_cmd->pma == pma)) - { - // merge with current command - cur_cmd->num_elements += num_indices; - } else { - // record a new command - _sspine_command_t* cmd_ptr = _sspine_next_command(ctx); - if (cmd_ptr) { - cmd_ptr->layer = layer; - cmd_ptr->pip = pip; - cmd_ptr->img = img; - cmd_ptr->smp = smp; - cmd_ptr->pma = pma; - cmd_ptr->base_element = dst_indices.index; - cmd_ptr->num_elements = num_indices; - } - } - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - } - spSkeletonClipping_clipEnd2(sp_clip); -} - -// compute orthographic projection matrix -static void _sspine_layer_transform_to_proj(const sspine_layer_transform* tform, float* res) { - const float left = -tform->origin.x; - const float right = tform->size.x - tform->origin.x; - const float top = -tform->origin.y; - const float bottom = tform->size.y - tform->origin.y; - const float znear = -1.0f; - const float zfar = 1.0f; - res[0] = 2.0f / (right - left); - res[1] = 0.0f; - res[2] = 0.0f; - res[3] = 0.0f; - res[4] = 0.0f; - res[5] = 2.0f / (top - bottom); - res[6] = 0.0f; - res[7] = 0.0f; - res[8] = 0.0f; - res[9] = 0.0f; - res[10] = -2.0f / (zfar - znear); - res[11] = 0.0f; - res[12] = -(right + left) / (right - left); - res[13] = -(top + bottom) / (top - bottom); - res[14] = -(zfar + znear) / (zfar - znear); - res[15] = 1.0f; -} - -static _sspine_vsparams_t _sspine_compute_vsparams(const sspine_layer_transform* tform) { - _sspine_vsparams_t p; - _sspine_clear(&p, sizeof(p)); - _sspine_layer_transform_to_proj(tform, p.mvp); - return p; -} - -static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_layer_transform* tform) { - if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { - sg_push_debug_group("sokol-spine"); - - if (ctx->update_frame_id != _sspine.frame_id) { - ctx->update_frame_id = _sspine.frame_id; - const sg_range vtx_range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sspine_vertex_t) }; - sg_update_buffer(ctx->vbuf, &vtx_range); - const sg_range idx_range = { ctx->indices.ptr, (size_t)ctx->indices.next * sizeof(uint32_t) }; - sg_update_buffer(ctx->ibuf, &idx_range); - } - - _sspine_vsparams_t vsparams = _sspine_compute_vsparams(tform); - const sg_range vsparams_range = { &vsparams, sizeof(vsparams) }; - _sspine_fsparams_t fsparams; - _sspine_clear(&fsparams, sizeof(fsparams)); - const sg_range fsparams_range = { &fsparams, sizeof(fsparams) }; - - uint32_t cur_pip_id = SG_INVALID_ID; - uint32_t cur_img_id = SG_INVALID_ID; - uint32_t cur_smp_id = SG_INVALID_ID; - float cur_pma = -1.0f; - for (int i = 0; i < ctx->commands.next; i++) { - const _sspine_command_t* cmd = &ctx->commands.ptr[i]; - const bool img_valid = sg_query_image_state(cmd->img) == SG_RESOURCESTATE_VALID; - const bool smp_valid = sg_query_sampler_state(cmd->smp) == SG_RESOURCESTATE_VALID; - if ((layer == cmd->layer) && img_valid && smp_valid) { - if (cur_pip_id != cmd->pip.id) { - sg_apply_pipeline(cmd->pip); - cur_pip_id = cmd->pip.id; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &vsparams_range); - cur_img_id = SG_INVALID_ID; - } - if ((cur_img_id != cmd->img.id) || (cur_smp_id != cmd->smp.id)) { - ctx->bind.fs.images[0] = cmd->img; - ctx->bind.fs.samplers[0] = cmd->smp; - sg_apply_bindings(&ctx->bind); - cur_img_id = cmd->img.id; - cur_smp_id = cmd->smp.id; - } - if (cur_pma != cmd->pma) { - fsparams.pma = cmd->pma; - sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, &fsparams_range); - cur_pma = cmd->pma; - } - if (cmd->num_elements > 0) { - sg_draw(cmd->base_element, cmd->num_elements, 1); - } - } - } - sg_pop_debug_group(); - } -} - -// ███ ███ ██ ███████ ██████ -// ████ ████ ██ ██ ██ -// ██ ████ ██ ██ ███████ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██████ -// -// >>misc - -// return sspine_desc with patched defaults -static sspine_desc _sspine_desc_defaults(const sspine_desc* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sspine_desc res = *desc; - res.max_vertices = _sspine_def(desc->max_vertices, _SSPINE_DEFAULT_MAX_VERTICES); - res.max_commands = _sspine_def(desc->max_commands, _SSPINE_DEFAULT_MAX_COMMANDS); - res.context_pool_size = _sspine_def(desc->context_pool_size, _SSPINE_DEFAULT_CONTEXT_POOL_SIZE); - res.atlas_pool_size = _sspine_def(desc->atlas_pool_size, _SSPINE_DEFAULT_ATLAS_POOL_SIZE); - res.skeleton_pool_size = _sspine_def(desc->skeleton_pool_size, _SSPINE_DEFAULT_SKELETON_POOL_SIZE); - res.skinset_pool_size = _sspine_def(desc->skinset_pool_size, _SSPINE_DEFAULT_SKINSET_POOL_SIZE); - res.instance_pool_size = _sspine_def(desc->instance_pool_size, _SSPINE_DEFAULT_INSTANCE_POOL_SIZE); - return res; -} - -static sspine_context_desc _sspine_as_context_desc(const sspine_desc* desc) { - sspine_context_desc ctx_desc; - _sspine_clear(&ctx_desc, sizeof(ctx_desc)); - ctx_desc.max_vertices = desc->max_vertices; - ctx_desc.max_commands = desc->max_commands; - ctx_desc.color_format = desc->color_format; - ctx_desc.depth_format = desc->depth_format; - ctx_desc.sample_count = desc->sample_count; - ctx_desc.color_write_mask = desc->color_write_mask; - return ctx_desc; -} - -static sg_filter _sspine_as_sampler_filter(spAtlasFilter filter) { - switch (filter) { - case SP_ATLAS_UNKNOWN_FILTER: return _SG_FILTER_DEFAULT; - case SP_ATLAS_NEAREST: return SG_FILTER_NEAREST; - case SP_ATLAS_LINEAR: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP_NEAREST_NEAREST: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_LINEAR_NEAREST: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP_NEAREST_LINEAR: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_LINEAR_LINEAR: return SG_FILTER_LINEAR; - default: return SG_FILTER_LINEAR; - } -} - -static sg_filter _sspine_as_sampler_mipmap_filter(spAtlasFilter filter) { - switch (filter) { - case SP_ATLAS_UNKNOWN_FILTER: return _SG_FILTER_DEFAULT; - case SP_ATLAS_NEAREST: return SG_FILTER_NONE; - case SP_ATLAS_LINEAR: return SG_FILTER_NONE; - case SP_ATLAS_MIPMAP: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_NEAREST_NEAREST: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_LINEAR_NEAREST: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_NEAREST_LINEAR: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP_LINEAR_LINEAR: return SG_FILTER_LINEAR; - default: return SG_FILTER_NEAREST; - } -} - -static sg_wrap _sspine_as_sampler_wrap(spAtlasWrap wrap) { - switch (wrap) { - case SP_ATLAS_MIRROREDREPEAT: return SG_WRAP_MIRRORED_REPEAT; - case SP_ATLAS_CLAMPTOEDGE: return SG_WRAP_CLAMP_TO_EDGE; - case SP_ATLAS_REPEAT: return SG_WRAP_REPEAT; - default: return _SG_WRAP_DEFAULT; - } -} - -static void _sspine_init_image_info(const _sspine_atlas_t* atlas, int index, sspine_image_info* info, bool with_overrides) { - spAtlasPage* page = _sspine_lookup_atlas_page(atlas->slot.id, index); - SOKOL_ASSERT(page); - SOKOL_ASSERT(page->name); - info->valid = true; - info->sgimage = _sspine_image_from_renderer_object(page->rendererObject); - info->sgsampler = _sspine_sampler_from_renderer_object(page->rendererObject); - if (with_overrides && (atlas->overrides.min_filter != _SG_FILTER_DEFAULT)) { - info->min_filter = atlas->overrides.min_filter; - } else { - info->min_filter = _sspine_as_sampler_filter(page->minFilter); - } - if (with_overrides && (atlas->overrides.mag_filter != _SG_FILTER_DEFAULT)) { - info->mag_filter = atlas->overrides.mag_filter; - } else { - info->mag_filter = _sspine_as_sampler_filter(page->magFilter); - } - if (with_overrides && (atlas->overrides.mipmap_filter != _SG_FILTER_DEFAULT)) { - info->mipmap_filter = atlas->overrides.mipmap_filter; - } else { - info->mipmap_filter = _sspine_as_sampler_mipmap_filter(page->minFilter); - } - if (with_overrides && (atlas->overrides.wrap_u != _SG_WRAP_DEFAULT)) { - info->wrap_u = atlas->overrides.wrap_u; - } else { - info->wrap_u = _sspine_as_sampler_wrap(page->uWrap); - } - if (with_overrides && (atlas->overrides.wrap_v != _SG_WRAP_DEFAULT)) { - info->wrap_v = atlas->overrides.wrap_v; - } else { - info->wrap_v = _sspine_as_sampler_wrap(page->vWrap); - } - info->width = page->width; - info->height = page->height; - // NOTE: override already happened in atlas init - info->premul_alpha = page->pma != 0; - info->filename = _sspine_string(page->name); - if (info->filename.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } -} - -static void _sspine_init_shared(void) { - sg_shader_desc shd_desc; - _sspine_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.vs.uniform_blocks[0].size = sizeof(_sspine_vsparams_t); - shd_desc.vs.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140; - shd_desc.vs.uniform_blocks[0].uniforms[0].name = "vs_params"; - shd_desc.vs.uniform_blocks[0].uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - shd_desc.vs.uniform_blocks[0].uniforms[0].array_count = 4; - shd_desc.fs.uniform_blocks[0].size = 16; - shd_desc.fs.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140; - shd_desc.fs.uniform_blocks[0].uniforms[0].name = "fs_params"; - shd_desc.fs.uniform_blocks[0].uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - shd_desc.fs.uniform_blocks[0].uniforms[0].array_count = 1; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.label = "sspine-shader"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _sspine_vs_source_glsl330; - shd_desc.fs.source = _sspine_fs_source_glsl330; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _sspine_vs_source_glsl300es; - shd_desc.fs.source = _sspine_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sspine_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sspine_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sspine_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sspine_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = _sspine_vs_source_metal_sim; - shd_desc.fs.source = _sspine_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sspine_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sspine_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _sspine_vs_source_wgsl; - shd_desc.fs.source = _sspine_fs_source_wgsl; - #else - shd_desc.vs.source = _sspine_vs_source_dummy; - shd_desc.fs.source = _sspine_fs_source_dummy; - #endif - _sspine.shd = sg_make_shader(&shd_desc); -} - -static void _sspine_destroy_shared(void) { - sg_destroy_shader(_sspine.shd); -} - -// called from inside sokol-gfx sg_commit() -static void _sspine_commit_listener_func(void* userdata) { - (void)userdata; - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine.frame_id++; -} - -static sg_commit_listener _sspine_make_commit_listener(void) { - sg_commit_listener commit_listener = { _sspine_commit_listener_func, 0 }; - return commit_listener; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sspine_setup(const sspine_desc* desc) { - SOKOL_ASSERT(desc); - spBone_setYDown(1); - _sspine_clear(&_sspine, sizeof(_sspine)); - _sspine.init_cookie = _SSPINE_INIT_COOKIE; - _sspine.desc = _sspine_desc_defaults(desc); - _sspine_init_shared(); - // important, need to setup the frame id with a non-zero value, - // otherwise updates won't trigger in the first frame - _sspine.frame_id = 1; - _sspine_setup_context_pool(_sspine.desc.context_pool_size); - _sspine_setup_atlas_pool(_sspine.desc.atlas_pool_size); - _sspine_setup_skeleton_pool(_sspine.desc.skeleton_pool_size); - _sspine_setup_skinset_pool(_sspine.desc.skinset_pool_size); - _sspine_setup_instance_pool(_sspine.desc.instance_pool_size); - const sspine_context_desc ctx_desc = _sspine_as_context_desc(&_sspine.desc); - _sspine.def_ctx_id = sspine_make_context(&ctx_desc); - SOKOL_ASSERT(_sspine_is_default_context(_sspine.def_ctx_id)); - sspine_set_context(_sspine.def_ctx_id); - if (!sg_add_commit_listener(_sspine_make_commit_listener())) { - _SSPINE_ERROR(ADD_COMMIT_LISTENER_FAILED); - } -} - -SOKOL_API_IMPL void sspine_shutdown(void) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sg_remove_commit_listener(_sspine_make_commit_listener()); - _sspine_destroy_all_instances(); - _sspine_destroy_all_skinsets(); - _sspine_destroy_all_skeletons(); - _sspine_destroy_all_atlases(); - _sspine_destroy_all_contexts(); - _sspine_discard_instance_pool(); - _sspine_discard_skinset_pool(); - _sspine_discard_skeleton_pool(); - _sspine_discard_atlas_pool(); - _sspine_discard_context_pool(); - _sspine_destroy_shared(); - _sspine.init_cookie = 0; -} - -SOKOL_API_IMPL sspine_context sspine_make_context(const sspine_context_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_context_desc desc_def = _sspine_context_desc_defaults(desc); - sspine_context ctx_id = _sspine_alloc_context(); - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - ctx->slot.state = _sspine_init_context(ctx, &desc_def); - SOKOL_ASSERT((ctx->slot.state == SSPINE_RESOURCESTATE_VALID) || (ctx->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (ctx->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_context(ctx); - } - } else { - ctx->slot.state = SSPINE_RESOURCESTATE_FAILED; - _SSPINE_ERROR(CONTEXT_POOL_EXHAUSTED); - } - return ctx_id; -} - -SOKOL_API_IMPL void sspine_destroy_context(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - if (_sspine_is_default_context(ctx_id)) { - _SSPINE_ERROR(CANNOT_DESTROY_DEFAULT_CONTEXT); - return; - } - _sspine_destroy_context(ctx_id); - // re-validate the current context pointer (this will return a nullptr - // if we just destroyed the current context) - _sspine.cur_ctx = _sspine_lookup_context(_sspine.cur_ctx_id.id); -} - -SOKOL_API_IMPL void sspine_set_context(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - if (_sspine_is_default_context(ctx_id)) { - _sspine.cur_ctx_id = _sspine.def_ctx_id; - } else { - _sspine.cur_ctx_id = ctx_id; - } - // this will return null if the handle isn't valid - _sspine.cur_ctx = _sspine_lookup_context(_sspine.cur_ctx_id.id); -} - -SOKOL_API_IMPL sspine_context sspine_get_context(void) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return _sspine.cur_ctx_id; -} - -SOKOL_API_IMPL sspine_context sspine_default_context(void) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return _sspine_make_context_handle(0x00010001); -} - -SOKOL_API_IMPL sspine_context_info sspine_get_context_info(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_context_info res; - _sspine_clear(&res, sizeof(res)); - const _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - res.num_vertices = ctx->vertices.next; - res.num_indices = ctx->indices.next; - res.num_commands = ctx->commands.next; - } - return res; -} - -SOKOL_API_IMPL void sspine_set_skinset(sspine_instance instance_id, sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (_sspine_instance_and_deps_valid(instance) && _sspine_skinset_and_deps_valid(skinset) && (instance->skel.id == skinset->skel.id)) { - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - SOKOL_ASSERT(skinset->sp_skin); - spSkeleton_setSkin(instance->sp_skel, 0); - spSkeleton_setSkin(instance->sp_skel, skinset->sp_skin); - spSkeleton_setSlotsToSetupPose(instance->sp_skel); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - } -} - -SOKOL_API_IMPL void sspine_update_instance(sspine_instance instance_id, float delta_time) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - _sspine_rewind_triggered_events(instance); - spAnimationState_update(instance->sp_anim_state, delta_time); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - spSkeleton_updateWorldTransform(instance->sp_skel); - } -} - -SOKOL_API_IMPL int sspine_num_triggered_events(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT((instance->cur_triggered_event_index >= 0) && (instance->cur_triggered_event_index <= _SSPINE_MAX_TRIGGERED_EVENTS)); - return instance->cur_triggered_event_index; - } - return 0; -} - -SOKOL_API_IMPL sspine_triggered_event_info sspine_get_triggered_event_info(sspine_instance instance_id, int triggered_event_index) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_triggered_event_info res; - _sspine_clear(&res, sizeof(res)); - if (_sspine_instance_and_deps_valid(instance)) { - if ((triggered_event_index >= 0) && (triggered_event_index < instance->cur_triggered_event_index)) { - res = instance->triggered_events[triggered_event_index]; - } - } - return res; -} - -SOKOL_API_IMPL void sspine_draw_instance_in_layer(sspine_instance instance_id, int layer) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_context_t* ctx = _sspine.cur_ctx; - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (ctx && _sspine_instance_and_deps_valid(instance)) { - _sspine_draw_instance(ctx, instance, layer); - } -} - -SOKOL_API_IMPL sspine_mat4 sspine_layer_transform_to_mat4(const sspine_layer_transform* tform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_mat4 res; - _sspine_layer_transform_to_proj(tform, res.m); - return res; -} - -SOKOL_API_IMPL void sspine_context_draw_instance_in_layer(sspine_context ctx_id, sspine_instance instance_id, int layer) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (ctx && _sspine_instance_and_deps_valid(instance)) { - _sspine_draw_instance(ctx, instance, layer); - } -} - -SOKOL_API_IMPL void sspine_draw_layer(int layer, const sspine_layer_transform* tform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(tform); - _sspine_context_t* ctx = _sspine.cur_ctx; - if (ctx) { - _sspine_draw_layer(ctx, layer, tform); - } -} - -SOKOL_API_IMPL void sspine_context_draw_layer(sspine_context ctx_id, int layer, const sspine_layer_transform* tform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(tform); - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - _sspine_draw_layer(ctx, layer, tform); - } -} - -SOKOL_API_IMPL sspine_atlas sspine_make_atlas(const sspine_atlas_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_atlas_desc desc_def = _sspine_atlas_desc_defaults(desc); - sspine_atlas atlas_id = _sspine_alloc_atlas(); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - atlas->slot.state = _sspine_init_atlas(atlas, &desc_def); - SOKOL_ASSERT((atlas->slot.state == SSPINE_RESOURCESTATE_VALID) || (atlas->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (atlas->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_atlas(atlas); - } - } else { - _SSPINE_ERROR(ATLAS_POOL_EXHAUSTED); - } - return atlas_id; -} - -SOKOL_API_IMPL void sspine_destroy_atlas(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_atlas(atlas_id); -} - -SOKOL_API_IMPL sspine_skeleton sspine_make_skeleton(const sspine_skeleton_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_skeleton_desc desc_def = _sspine_skeleton_desc_defaults(desc); - sspine_skeleton skeleton_id = _sspine_alloc_skeleton(); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (skeleton) { - skeleton->slot.state = _sspine_init_skeleton(skeleton, &desc_def); - SOKOL_ASSERT((skeleton->slot.state == SSPINE_RESOURCESTATE_VALID) || (skeleton->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (skeleton->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_skeleton(skeleton); - } - } else { - _SSPINE_ERROR(SKELETON_POOL_EXHAUSTED); - } - return skeleton_id; -} - -SOKOL_API_IMPL void sspine_destroy_skeleton(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_skeleton(skeleton_id); -} - -SOKOL_API_IMPL sspine_skinset sspine_make_skinset(const sspine_skinset_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_skinset_desc desc_def = _sspine_skinset_desc_defaults(desc); - sspine_skinset skinset_id = _sspine_alloc_skinset(); - _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (skinset) { - skinset->slot.state = _sspine_init_skinset(skinset, &desc_def); - SOKOL_ASSERT((skinset->slot.state == SSPINE_RESOURCESTATE_VALID) || (skinset->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (skinset->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_skinset(skinset); - } - } else { - _SSPINE_ERROR(SKINSET_POOL_EXHAUSTED); - } - return skinset_id; -} - -SOKOL_API_IMPL void sspine_destroy_skinset(sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_skinset(skinset_id); -} - -SOKOL_API_IMPL sspine_instance sspine_make_instance(const sspine_instance_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_instance_desc desc_def = _sspine_instance_desc_defaults(desc); - sspine_instance instance_id = _sspine_alloc_instance(); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - instance->slot.state = _sspine_init_instance(instance, &desc_def); - SOKOL_ASSERT((instance->slot.state == SSPINE_RESOURCESTATE_VALID) || (instance->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (instance->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_instance(instance); - } - } else { - _SSPINE_ERROR(INSTANCE_POOL_EXHAUSTED); - } - return instance_id; -} - -SOKOL_API_IMPL void sspine_destroy_instance(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_instance(instance_id); -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_context_resource_state(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - return ctx->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_atlas_resource_state(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - return atlas->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_skeleton_resource_state(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (skeleton) { - return skeleton->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_skinset_resource_state(sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (skinset) { - return skinset->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_instance_resource_state(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - return instance->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL bool sspine_context_valid(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_context_resource_state(ctx_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_atlas_valid(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_atlas_resource_state(atlas_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_skeleton_valid(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_skeleton_resource_state(skeleton_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_skinset_valid(sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_skinset_resource_state(skinset_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_instance_valid(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_instance_resource_state(instance_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL sspine_atlas sspine_get_skeleton_atlas(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - sspine_atlas res; - _sspine_clear(&res, sizeof(res)); - if (skeleton) { - res.id = skeleton->atlas.id; - } - return res; -} - -SOKOL_API_IMPL sspine_skeleton sspine_get_instance_skeleton(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_skeleton res; - _sspine_clear(&res, sizeof(res)); - if (instance) { - res.id = instance->skel.id; - } - return res; -} - -SOKOL_API_IMPL int sspine_num_images(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - return atlas->num_pages; - } - return 0; -} - -SOKOL_API_IMPL sspine_image sspine_image_by_index(sspine_atlas atlas_id, int index) { - return _sspine_image(atlas_id.id, index); -} - -SOKOL_API_IMPL bool sspine_image_valid(sspine_image image) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(image.atlas_id); - return atlas && (image.index >= 0) && (image.index < atlas->num_pages); -} - -SOKOL_API_IMPL bool sspine_image_equal(sspine_image first, sspine_image second) { - return (first.atlas_id == second.atlas_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_image_info sspine_get_image_info(sspine_image image) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(image.atlas_id); - sspine_image_info img_info; - _sspine_clear(&img_info, sizeof(img_info)); - if (atlas && (image.index >= 0) && (image.index < atlas->num_pages)) { - _sspine_init_image_info(atlas, image.index, &img_info, true); - } - return img_info; -} - -SOKOL_API_IMPL int sspine_num_atlas_pages(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - return atlas->num_pages; - } else { - return 0; - } -} - -SOKOL_API_IMPL sspine_atlas_page sspine_atlas_page_by_index(sspine_atlas atlas_id, int index) { - return _sspine_atlas_page(atlas_id.id, index); -} - -SOKOL_API_IMPL bool sspine_atlas_page_valid(sspine_atlas_page page) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(page.atlas_id); - if (atlas) { - return (page.index >= 0) && (page.index < atlas->num_pages); - } - return false; -} - -SOKOL_API_IMPL bool sspine_atlas_page_equal(sspine_atlas_page first, sspine_atlas_page second) { - return (first.atlas_id == second.atlas_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_atlas_page_info sspine_get_atlas_page_info(sspine_atlas_page page) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_atlas_page_info res; - _sspine_clear(&res, sizeof(res)); - const spAtlasPage* sp_page = _sspine_lookup_atlas_page(page.atlas_id, page.index); - if (sp_page) { - // at this point, atlas is guaranteed to be valid - const _sspine_atlas_t* atlas = _sspine_lookup_atlas(page.atlas_id); - res.valid = true; - res.atlas.id = page.atlas_id; - // write image info without overrides - _sspine_init_image_info(atlas, page.index, &res.image, false); - // ...and provide the overrides separately - res.overrides = atlas->overrides; - } - return res; -} - -SOKOL_API_IMPL void sspine_set_position(sspine_instance instance_id, sspine_vec2 position) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_skel); - instance->sp_skel->x = position.x; - instance->sp_skel->y = position.y; - } -} - -SOKOL_API_IMPL void sspine_set_scale(sspine_instance instance_id, sspine_vec2 scale) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - instance->sp_skel->scaleX = scale.x; - instance->sp_skel->scaleY = scale.y; - } -} - -SOKOL_API_IMPL void sspine_set_color(sspine_instance instance_id, sspine_color color) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - instance->sp_skel->color.r = color.r; - instance->sp_skel->color.g = color.g; - instance->sp_skel->color.b = color.b; - instance->sp_skel->color.a = color.a; - } -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_position(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_vec2 v = { 0.0f, 0.0f }; - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - v.x = instance->sp_skel->x; - v.y = instance->sp_skel->y; - } - return v; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_scale(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_vec2 v = { 0.0f, 0.0f }; - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - v.x = instance->sp_skel->scaleX; - v.y = instance->sp_skel->scaleY; - } - return v; -} - -SOKOL_API_IMPL sspine_color sspine_get_color(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_color c = { 0.0f, 0.0f, 0.0f, 0.0f }; - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - c.r = instance->sp_skel->color.r; - c.g = instance->sp_skel->color.g; - c.b = instance->sp_skel->color.b; - c.a = instance->sp_skel->color.a; - } - return c; -} - -SOKOL_API_IMPL int sspine_num_anims(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->animationsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_anim sspine_anim_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - // NOTE: there's a spSkeletonData_findAnimation function, but that doesn't - // give us access to the index, so we'll need to do the loop ourselves - SOKOL_ASSERT(skeleton->sp_skel_data); - const spSkeletonData* sp_skel_data = skeleton->sp_skel_data; - const int num_anims = sp_skel_data->animationsCount; - SOKOL_ASSERT(sp_skel_data->animations); - for (int i = 0; i < num_anims; i++) { - SOKOL_ASSERT(sp_skel_data->animations[i]); - SOKOL_ASSERT(sp_skel_data->animations[i]->name); - if (0 == strcmp(sp_skel_data->animations[i]->name, name)) { - return _sspine_anim(skeleton_id.id, i); - } - } - } - return _sspine_anim(0, 0); -} - -SOKOL_API_IMPL sspine_anim sspine_anim_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_anim(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_anim_valid(sspine_anim anim) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(anim.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (anim.index >= 0) && (anim.index < skeleton->sp_skel_data->animationsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_anim_equal(sspine_anim first, sspine_anim second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_anim_info sspine_get_anim_info(sspine_anim anim) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_anim_info res; - _sspine_clear(&res, sizeof(res)); - const spAnimation* sp_anim = _sspine_lookup_skeleton_anim(anim.skeleton_id, anim.index); - if (sp_anim) { - res.valid = true; - res.index = anim.index; - res.duration = sp_anim->duration; - res.name = _sspine_string(sp_anim->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_clear_animation_tracks(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_clearTracks(instance->sp_anim_state); - } -} - -SOKOL_API_IMPL void sspine_clear_animation_track(sspine_instance instance_id, int track_index) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_clearTrack(instance->sp_anim_state, track_index); - } -} - -SOKOL_API_IMPL void sspine_set_animation(sspine_instance instance_id, sspine_anim anim, int track_index, bool loop) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spAnimation* sp_anim = _sspine_lookup_instance_anim(instance_id.id, anim.skeleton_id, anim.index); - if (sp_anim) { - // NOTE: at this point, instance is guaranteed to be valid - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - SOKOL_ASSERT(instance); - spAnimationState_setAnimation(instance->sp_anim_state, track_index, sp_anim, loop?1:0); - } -} - -SOKOL_API_IMPL void sspine_add_animation(sspine_instance instance_id, sspine_anim anim, int track_index, bool loop, float delay) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spAnimation* sp_anim = _sspine_lookup_instance_anim(instance_id.id, anim.skeleton_id, anim.index); - if (sp_anim) { - // NOTE: at this point, instance is guaranteed to be valid - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - SOKOL_ASSERT(instance); - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_addAnimation(instance->sp_anim_state, track_index, sp_anim, loop?1:0, delay); - } -} - -SOKOL_API_IMPL void sspine_set_empty_animation(sspine_instance instance_id, int track_index, float mix_duration) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_setEmptyAnimation(instance->sp_anim_state, track_index, mix_duration); - } -} - -SOKOL_API_IMPL void sspine_add_empty_animation(sspine_instance instance_id, int track_index, float mix_duration, float delay) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_addEmptyAnimation(instance->sp_anim_state, track_index, mix_duration, delay); - } -} - -SOKOL_API_IMPL int sspine_num_bones(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->bonesCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_bone sspine_bone_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - spBoneData* sp_bone_data = spSkeletonData_findBone(skeleton->sp_skel_data, name); - if (sp_bone_data) { - return _sspine_bone(skeleton_id.id, sp_bone_data->index); - } - } - return _sspine_bone(0, 0); -} - -SOKOL_API_IMPL sspine_bone sspine_bone_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_bone(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_bone_valid(sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(bone.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (bone.index >= 0) && (bone.index < skeleton->sp_skel_data->bonesCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_bone_equal(sspine_bone first, sspine_bone second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_bone_info sspine_get_bone_info(sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_bone_info res; - _sspine_clear(&res, sizeof(res)); - const spBoneData* sp_bone_data = _sspine_lookup_bone_data(bone.skeleton_id, bone.index); - if (sp_bone_data) { - SOKOL_ASSERT(sp_bone_data->index == bone.index); - SOKOL_ASSERT(sp_bone_data->name); - res.valid = true; - res.index = sp_bone_data->index; - if (sp_bone_data->parent) { - res.parent_bone = _sspine_bone(bone.skeleton_id, sp_bone_data->parent->index); - } - res.length = sp_bone_data->length; - res.pose.position.x = sp_bone_data->x; - res.pose.position.y = sp_bone_data->y; - res.pose.rotation = sp_bone_data->rotation; - res.pose.scale.x = sp_bone_data->scaleX; - res.pose.scale.y = sp_bone_data->scaleY; - res.pose.shear.x = sp_bone_data->shearX; - res.pose.shear.y = sp_bone_data->shearY; - res.color.r = sp_bone_data->color.r; - res.color.g = sp_bone_data->color.g; - res.color.b = sp_bone_data->color.b; - res.color.a = sp_bone_data->color.a; - res.name = _sspine_string(sp_bone_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_set_bone_transform(sspine_instance instance_id, sspine_bone bone, const sspine_bone_transform* transform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(transform); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->x = transform->position.x; - sp_bone->y = transform->position.y; - sp_bone->rotation = transform->rotation; - sp_bone->scaleX = transform->scale.x; - sp_bone->scaleY = transform->scale.y; - sp_bone->shearX = transform->shear.x; - sp_bone->shearY = transform->shear.y; - } -} - -SOKOL_API_IMPL void sspine_set_bone_position(sspine_instance instance_id, sspine_bone bone, sspine_vec2 position) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->x = position.x; - sp_bone->y = position.y; - } -} - -SOKOL_API_IMPL void sspine_set_bone_rotation(sspine_instance instance_id, sspine_bone bone, float rotation) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->rotation = rotation; - } -} - -SOKOL_API_IMPL void sspine_set_bone_scale(sspine_instance instance_id, sspine_bone bone, sspine_vec2 scale) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->scaleX = scale.x; - sp_bone->scaleY = scale.y; - } -} - -SOKOL_API_IMPL void sspine_set_bone_shear(sspine_instance instance_id, sspine_bone bone, sspine_vec2 shear) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->shearX = shear.x; - sp_bone->shearY = shear.y; - } -} - -SOKOL_API_IMPL sspine_bone_transform sspine_get_bone_transform(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_bone_transform res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.position.x = sp_bone->x; - res.position.y = sp_bone->y; - res.rotation = sp_bone->rotation; - res.scale.x = sp_bone->scaleX; - res.scale.y = sp_bone->scaleY; - res.shear.x = sp_bone->shearX; - res.shear.y = sp_bone->shearY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_position(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->x; - res.y = sp_bone->y; - } - return res; -} - -SOKOL_API_IMPL float sspine_get_bone_rotation(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - return sp_bone->rotation; - } else { - return 0.0f; - } -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_scale(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->scaleX; - res.y = sp_bone->scaleY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_shear(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->shearX; - res.y = sp_bone->shearY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_world_position(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->worldX; - res.y = sp_bone->worldY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_bone_local_to_world(sspine_instance instance_id, sspine_bone bone, sspine_vec2 local_pos) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - spBone_localToWorld(sp_bone, local_pos.x, local_pos.y, &res.x, &res.y); - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_bone_world_to_local(sspine_instance instance_id, sspine_bone bone, sspine_vec2 world_pos) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - spBone_worldToLocal(sp_bone, world_pos.x, world_pos.y, &res.x, &res.y); - } - return res; -} - -SOKOL_API_IMPL int sspine_num_slots(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->slotsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_slot sspine_slot_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - spSlotData* sp_slot_data = spSkeletonData_findSlot(skeleton->sp_skel_data, name); - if (sp_slot_data) { - return _sspine_slot(skeleton_id.id, sp_slot_data->index); - } - } - return _sspine_slot(0, 0); -} - -SOKOL_API_IMPL sspine_slot sspine_slot_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_slot(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_slot_valid(sspine_slot slot) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(slot.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (slot.index >= 0) && (slot.index < skeleton->sp_skel_data->slotsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_slot_equal(sspine_slot first, sspine_slot second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_slot_info sspine_get_slot_info(sspine_slot slot) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_slot_info res; - _sspine_clear(&res, sizeof(res)); - const spSlotData* sp_slot_data = _sspine_lookup_slot_data(slot.skeleton_id, slot.index); - if (sp_slot_data) { - SOKOL_ASSERT(sp_slot_data->index == slot.index); - SOKOL_ASSERT(sp_slot_data->name); - SOKOL_ASSERT(sp_slot_data->boneData); - res.valid = true; - res.index = sp_slot_data->index; - res.bone = _sspine_bone(slot.skeleton_id, sp_slot_data->boneData->index); - res.color.r = sp_slot_data->color.r; - res.color.g = sp_slot_data->color.g; - res.color.b = sp_slot_data->color.b; - res.color.a = sp_slot_data->color.a; - res.attachment_name = _sspine_string(sp_slot_data->attachmentName); - if (res.attachment_name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - res.name = _sspine_string(sp_slot_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_set_slot_color(sspine_instance instance_id, sspine_slot slot, sspine_color color) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spSlot* sp_slot = _sspine_lookup_slot(instance_id.id, slot.skeleton_id, slot.index); - if (sp_slot) { - sp_slot->color.r = color.r; - sp_slot->color.g = color.g; - sp_slot->color.b = color.b; - sp_slot->color.a = color.a; - } -} - -SOKOL_API_IMPL sspine_color sspine_get_slot_color(sspine_instance instance_id, sspine_slot slot) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_color color; - _sspine_clear(&color, sizeof(color)); - spSlot* sp_slot = _sspine_lookup_slot(instance_id.id, slot.skeleton_id, slot.index); - if (sp_slot) { - color.r = sp_slot->color.r; - color.g = sp_slot->color.g; - color.b = sp_slot->color.b; - color.a = sp_slot->color.a; - } - return color; -} - -SOKOL_API_IMPL int sspine_num_events(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->eventsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_event sspine_event_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_skel_data->events); - // spEventData has no embedded index, so we need to loop over the events - for (int i = 0; i < skeleton->sp_skel_data->eventsCount; i++) { - SOKOL_ASSERT(skeleton->sp_skel_data->events[i]); - SOKOL_ASSERT(skeleton->sp_skel_data->events[i]->name); - if (0 == strcmp(skeleton->sp_skel_data->events[i]->name, name)) { - return _sspine_event(skeleton_id.id, i); - } - } - } - return _sspine_event(0, 0); -} - -SOKOL_API_IMPL sspine_event sspine_event_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_event(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_event_valid(sspine_event event) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(event.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (event.index >= 0) && (event.index < skeleton->sp_skel_data->eventsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_event_equal(sspine_event first, sspine_event second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_event_info sspine_get_event_info(sspine_event event) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_event_info res; - _sspine_clear(&res, sizeof(res)); - const spEventData* sp_event_data = _sspine_lookup_event_data(event.skeleton_id, event.index); - if (sp_event_data) { - res.valid = true; - res.index = event.index; - res.int_value = sp_event_data->intValue; - res.float_value = sp_event_data->floatValue; - res.volume = sp_event_data->volume; - res.balance = sp_event_data->balance; - res.name = _sspine_string(sp_event_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - res.string_value = _sspine_string(sp_event_data->stringValue); - if (res.string_value.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - res.audio_path = _sspine_string(sp_event_data->audioPath); - if (res.audio_path.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL int sspine_num_iktargets(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->ikConstraintsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_iktarget sspine_iktarget_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_skel_data->ikConstraints); - // spIkConstraintData has no embedded index, so we need to loop over the events - for (int i = 0; i < skeleton->sp_skel_data->ikConstraintsCount; i++) { - SOKOL_ASSERT(skeleton->sp_skel_data->ikConstraints[i]); - SOKOL_ASSERT(skeleton->sp_skel_data->ikConstraints[i]->name); - if (0 == strcmp(skeleton->sp_skel_data->ikConstraints[i]->name, name)) { - return _sspine_iktarget(skeleton_id.id, i); - } - } - } - return _sspine_iktarget(0, 0); -} - -SOKOL_API_IMPL sspine_iktarget sspine_iktarget_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_iktarget(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_iktarget_valid(sspine_iktarget iktarget) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(iktarget.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (iktarget.index >= 0) && (iktarget.index < skeleton->sp_skel_data->ikConstraintsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_iktarget_equal(sspine_iktarget first, sspine_iktarget second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_iktarget_info sspine_get_iktarget_info(sspine_iktarget iktarget) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_iktarget_info res; - _sspine_clear(&res, sizeof(res)); - const spIkConstraintData* ik_data = _sspine_lookup_ikconstraint_data(iktarget.skeleton_id, iktarget.index); - if (ik_data) { - res.valid = true; - res.index = iktarget.index; - res.target_bone = _sspine_bone(iktarget.skeleton_id, ik_data->target->index); - res.name = _sspine_string(ik_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_set_iktarget_world_pos(sspine_instance instance_id, sspine_iktarget iktarget, sspine_vec2 world_pos) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spIkConstraint* ik_data = _sspine_lookup_ikconstraint(instance_id.id, iktarget.skeleton_id, iktarget.index); - if (ik_data) { - spBone* bone = ik_data->target; - spBone* parent_bone = bone->parent; - if (parent_bone) { - spBone_worldToLocal(parent_bone, world_pos.x, world_pos.y, &bone->x, &bone->y); - } - } -} - -SOKOL_API_IMPL int sspine_num_skins(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->skinsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_skin sspine_skin_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_skel_data->skins); - // spSkin has no embedded index, so we need to loop over the skins - for (int i = 0; i < skeleton->sp_skel_data->skinsCount; i++) { - SOKOL_ASSERT(skeleton->sp_skel_data->skins[i]); - SOKOL_ASSERT(skeleton->sp_skel_data->skins[i]->name); - if (0 == strcmp(skeleton->sp_skel_data->skins[i]->name, name)) { - return _sspine_skin(skeleton_id.id, i); - } - } - } - return _sspine_skin(0, 0); -} - -SOKOL_API_IMPL sspine_skin sspine_skin_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_skin(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_skin_valid(sspine_skin skin) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skin.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (skin.index >= 0) && (skin.index < skeleton->sp_skel_data->skinsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_skin_equal(sspine_skin first, sspine_skin second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_skin_info sspine_get_skin_info(sspine_skin skin) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_skin_info res; - _sspine_clear(&res, sizeof(res)); - const spSkin* sp_skin = _sspine_lookup_skin(skin.skeleton_id, skin.index); - if (sp_skin) { - res.valid = true; - res.index = skin.index; - res.name = _sspine_string(sp_skin->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_SPINE_API_DECL void sspine_set_skin(sspine_instance instance_id, sspine_skin skin) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skin.skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - // clear any currently set skinset - instance->skinset.id = SSPINE_INVALID_ID; - instance->skinset.ptr = 0; - spSkin* sp_skin = _sspine_lookup_skin(skin.skeleton_id, skin.index); - if (sp_skin) { - spSkeleton_setSkin(instance->sp_skel, 0); - spSkeleton_setSkin(instance->sp_skel, sp_skin); - spSkeleton_setSlotsToSetupPose(instance->sp_skel); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - } - } -} - -#endif // SOKOL_SPINE_IMPL -#endif // SOKOL_SPINE_INCLUDED diff --git a/source/engine/thirdparty/stb/data/atari_8bit_font_revised.png b/source/engine/thirdparty/stb/data/atari_8bit_font_revised.png deleted file mode 100644 index 91c553c..0000000 Binary files a/source/engine/thirdparty/stb/data/atari_8bit_font_revised.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/easy_font_raw.png b/source/engine/thirdparty/stb/data/easy_font_raw.png deleted file mode 100644 index 2f08148..0000000 Binary files a/source/engine/thirdparty/stb/data/easy_font_raw.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/license.txt b/source/engine/thirdparty/stb/data/herringbone/license.txt deleted file mode 100644 index 11ffc42..0000000 --- a/source/engine/thirdparty/stb/data/herringbone/license.txt +++ /dev/null @@ -1,4 +0,0 @@ -All files in this directory are in the public domain. Where -a public domain declaration is not recognized, you are granted -a license to freely use, modify, and redistribute them in -any way you choose. \ No newline at end of file diff --git a/source/engine/thirdparty/stb/data/herringbone/template_caves_limit_connectivity.png b/source/engine/thirdparty/stb/data/herringbone/template_caves_limit_connectivity.png deleted file mode 100644 index 1c286e7..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_caves_limit_connectivity.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_caves_tiny_corridors.png b/source/engine/thirdparty/stb/data/herringbone/template_caves_tiny_corridors.png deleted file mode 100644 index e9b0d44..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_caves_tiny_corridors.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_corner_caves.png b/source/engine/thirdparty/stb/data/herringbone/template_corner_caves.png deleted file mode 100644 index 73421e9..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_corner_caves.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v1.png b/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v1.png deleted file mode 100644 index c14380d..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v1.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v2.png b/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v2.png deleted file mode 100644 index 8a35bec..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v2.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v3.png b/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v3.png deleted file mode 100644 index f921807..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_horizontal_corridors_v3.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_limit_connectivity_fat.png b/source/engine/thirdparty/stb/data/herringbone/template_limit_connectivity_fat.png deleted file mode 100644 index dda1302..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_limit_connectivity_fat.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_limited_connectivity.png b/source/engine/thirdparty/stb/data/herringbone/template_limited_connectivity.png deleted file mode 100644 index d9f97c9..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_limited_connectivity.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_maze_2_wide.png b/source/engine/thirdparty/stb/data/herringbone/template_maze_2_wide.png deleted file mode 100644 index 0e5bfad..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_maze_2_wide.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_maze_plus_2_wide.png b/source/engine/thirdparty/stb/data/herringbone/template_maze_plus_2_wide.png deleted file mode 100644 index d27f7bd..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_maze_plus_2_wide.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_open_areas.png b/source/engine/thirdparty/stb/data/herringbone/template_open_areas.png deleted file mode 100644 index 7ac4eab..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_open_areas.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_ref2_corner_caves.png b/source/engine/thirdparty/stb/data/herringbone/template_ref2_corner_caves.png deleted file mode 100644 index b6c70c9..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_ref2_corner_caves.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_rooms_and_corridors.png b/source/engine/thirdparty/stb/data/herringbone/template_rooms_and_corridors.png deleted file mode 100644 index c0467f3..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_rooms_and_corridors.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_rooms_and_corridors_2_wide_diagonal_bias.png b/source/engine/thirdparty/stb/data/herringbone/template_rooms_and_corridors_2_wide_diagonal_bias.png deleted file mode 100644 index 45c669c..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_rooms_and_corridors_2_wide_diagonal_bias.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_rooms_limit_connectivity.png b/source/engine/thirdparty/stb/data/herringbone/template_rooms_limit_connectivity.png deleted file mode 100644 index e07599e..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_rooms_limit_connectivity.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_round_rooms_diagonal_corridors.png b/source/engine/thirdparty/stb/data/herringbone/template_round_rooms_diagonal_corridors.png deleted file mode 100644 index 2073f98..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_round_rooms_diagonal_corridors.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_sean_dungeon.png b/source/engine/thirdparty/stb/data/herringbone/template_sean_dungeon.png deleted file mode 100644 index 5be3b24..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_sean_dungeon.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_simple_caves_2_wide.png b/source/engine/thirdparty/stb/data/herringbone/template_simple_caves_2_wide.png deleted file mode 100644 index 3217271..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_simple_caves_2_wide.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/herringbone/template_square_rooms_with_random_rects.png b/source/engine/thirdparty/stb/data/herringbone/template_square_rooms_with_random_rects.png deleted file mode 100644 index 0d7e82e..0000000 Binary files a/source/engine/thirdparty/stb/data/herringbone/template_square_rooms_with_random_rects.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/map_01.png b/source/engine/thirdparty/stb/data/map_01.png deleted file mode 100644 index 2da3f5c..0000000 Binary files a/source/engine/thirdparty/stb/data/map_01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/map_02.png b/source/engine/thirdparty/stb/data/map_02.png deleted file mode 100644 index 461796b..0000000 Binary files a/source/engine/thirdparty/stb/data/map_02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/data/map_03.png b/source/engine/thirdparty/stb/data/map_03.png deleted file mode 100644 index 3aebcb9..0000000 Binary files a/source/engine/thirdparty/stb/data/map_03.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/deprecated/rrsprintf.h b/source/engine/thirdparty/stb/deprecated/rrsprintf.h deleted file mode 100644 index 62962e3..0000000 --- a/source/engine/thirdparty/stb/deprecated/rrsprintf.h +++ /dev/null @@ -1,1055 +0,0 @@ -#ifndef RR_SPRINTF_H_INCLUDE -#define RR_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define RR_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int rrsprintf( char * buf, char const * fmt, ... ) -int rrsnprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. rrsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int rrvsprintf( char * buf, char const * fmt, va_list va ) -int rrvsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. rrvsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int rrvsprintfcb( RRSPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * RRSPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every RR_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least RR_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void rrsetseparators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define RR_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1024 is "1.0 k", "%$.2d" 2536000 is -"2.42 m", etc. - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#ifdef RR_SPRINTF_STATIC -#define RRPUBLIC_DEC static -#define RRPUBLIC_DEF static -#else -#ifdef __cplusplus -#define RRPUBLIC_DEC extern "C" -#define RRPUBLIC_DEF extern "C" -#else -#define RRPUBLIC_DEC extern -#define RRPUBLIC_DEF -#endif -#endif - -#include // for va_list() - -#ifndef RR_SPRINTF_MIN -#define RR_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char * RRSPRINTFCB( char * buf, void * user, int len ); - -#ifndef RR_SPRINTF_DECORATE -#define RR_SPRINTF_DECORATE(name) rr##name // define this before including if you want to change the names -#endif - -#ifndef RR_SPRINTF_IMPLEMENTATION - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( vsprintf )( char * buf, char const * fmt, va_list va ); -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ); -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( sprintf ) ( char * buf, char const * fmt, ... ); -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( snprintf )( char * buf, int count, char const * fmt, ... ); - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( vsprintfcb )( RRSPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ); -RRPUBLIC_DEF void RR_SPRINTF_DECORATE( setseparators )( char comma, char period ); - -#else - -#include // for va_arg() - -#define rU32 unsigned int -#define rS32 signed int - -#ifdef _MSC_VER -#define rU64 unsigned __int64 -#define rS64 signed __int64 -#else -#define rU64 unsigned long long -#define rS64 signed long long -#endif -#define rU16 unsigned short - -#ifndef rUINTa -#if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) -#define rUINTa rU64 -#else -#define rUINTa rU32 -#endif -#endif - -#ifndef RR_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER<1900) -#define RR_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef RR_SPRINTF_NOUNALIGNED // define this before inclusion to force rrsprint to always use aligned accesses -#define RR_UNALIGNED(code) -#else -#define RR_UNALIGNED(code) code -#endif - -#ifndef RR_SPRINTF_NOFLOAT -// internal float utility functions -static rS32 rrreal_to_str( char const * * start, rU32 * len, char *out, rS32 * decimal_pos, double value, rU32 frac_digits ); -static rS32 rrreal_to_parts( rS64 * bits, rS32 * expo, double value ); -#define RRSPECIAL 0x7000 -#endif - -static char RRperiod='.'; -static char RRcomma=','; -static char rrdiglookup[201]="00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"; - -RRPUBLIC_DEF void RR_SPRINTF_DECORATE( setseparators )( char pcomma, char pperiod ) -{ - RRperiod=pperiod; - RRcomma=pcomma; -} - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( vsprintfcb )( RRSPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) -{ - static char hex[]="0123456789abcdefxp"; - static char hexu[]="0123456789ABCDEFXP"; - char * bf; - char const * f; - int tlen = 0; - - bf = buf; - f = fmt; - for(;;) - { - rS32 fw,pr,tz; rU32 fl; - - #define LJ 1 - #define LP 2 - #define LS 4 - #define LX 8 - #define LZ 16 - #define BI 32 - #define CS 64 - #define NG 128 - #define KI 256 - #define HW 512 - - // macros for the callback buffer stuff - #define chk_cb_bufL(bytes) { int len = (int)(bf-buf); if ((len+(bytes))>=RR_SPRINTF_MIN) { tlen+=len; if (0==(bf=buf=callback(buf,user,len))) goto done; } } - #define chk_cb_buf(bytes) { if ( callback ) { chk_cb_bufL(bytes); } } - #define flush_cb() { chk_cb_bufL(RR_SPRINTF_MIN-1); } //flush if there is even one byte in the buffer - #define cb_buf_clamp(cl,v) cl = v; if ( callback ) { int lg = RR_SPRINTF_MIN-(int)(bf-buf); if (cl>lg) cl=lg; } - - // fast copy everything up to the next % (or end of string) - for(;;) - { - while (((rUINTa)f)&3) - { - schk1: if (f[0]=='%') goto scandd; - schk2: if (f[0]==0) goto endfmt; - chk_cb_buf(1); *bf++=f[0]; ++f; - } - for(;;) - { - rU32 v,c; - v=*(rU32*)f; c=(~v)&0x80808080; - if ((v-0x26262626)&c) goto schk1; - if ((v-0x01010101)&c) goto schk2; - if (callback) if ((RR_SPRINTF_MIN-(int)(bf-buf))<4) goto schk1; - *(rU32*)bf=v; bf+=4; f+=4; - } - } scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; pr = -1; fl = 0; tz = 0; - - // flags - for(;;) - { - switch(f[0]) - { - // if we have left just - case '-': fl|=LJ; ++f; continue; - // if we have leading plus - case '+': fl|=LP; ++f; continue; - // if we have leading space - case ' ': fl|=LS; ++f; continue; - // if we have leading 0x - case '#': fl|=LX; ++f; continue; - // if we have thousand commas - case '\'': fl|=CS; ++f; continue; - // if we have kilo marker - case '$': fl|=KI; ++f; continue; - // if we have leading zero - case '0': fl|=LZ; ++f; goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if ( f[0] == '*' ) {fw = va_arg(va,rU32); ++f;} else { while (( f[0] >= '0' ) && ( f[0] <= '9' )) { fw = fw * 10 + f[0] - '0'; f++; } } - // get the precision - if ( f[0]=='.' ) { ++f; if ( f[0] == '*' ) {pr = va_arg(va,rU32); ++f;} else { pr = 0; while (( f[0] >= '0' ) && ( f[0] <= '9' )) { pr = pr * 10 + f[0] - '0'; f++; } } } - - // handle integer size overrides - switch(f[0]) - { - // are we halfwidth? - case 'h': fl|=HW; ++f; break; - // are we 64-bit (unix style) - case 'l': ++f; if ( f[0]=='l') { fl|=BI; ++f; } break; - // are we 64-bit on intmax? (c99) - case 'j': fl|=BI; ++f; break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': case 't': fl|=((sizeof(char*)==8)?BI:0); ++f; break; - // are we 64-bit (msft style) - case 'I': if ( ( f[1]=='6') && ( f[2]=='4') ) { fl|=BI; f+=3; } else if ( ( f[1]=='3') && ( f[2]=='2') ) { f+=3; } else { fl|=((sizeof(void*)==8)?BI:0); ++f; } break; - default: break; - } - - // handle each replacement - switch( f[0] ) - { - #define NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - rU32 l,n,cs; - rU64 n64; - #ifndef RR_SPRINTF_NOFLOAT - double fv; - #endif - rS32 dp; char const * sn; - - case 's': - // get the string - s = va_arg(va,char*); if (s==0) s = (char*)"null"; - // get the length - sn = s; - for(;;) - { - if ((((rUINTa)sn)&3)==0) break; - lchk: - if (sn[0]==0) goto ld; - ++sn; - } - n = 0xffffffff; - if (pr>=0) { n=(rU32)(sn-s); if (n>=(rU32)pr) goto ld; n=((rU32)(pr-n))>>2; } - while(n) - { - rU32 v=*(rU32*)sn; - if ((v-0x01010101)&(~v)&0x80808080UL) goto lchk; - sn+=4; - --n; - } - goto lchk; - ld: - - l = (rU32) ( sn - s ); - // clamp to precision - if ( l > (rU32)pr ) l = pr; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - // copy the string in - goto scopy; - - case 'c': // char - // get the character - s = num + NUMSZ -1; *s = (char)va_arg(va,int); - l = 1; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { int * d = va_arg(va,int*); - *d = tlen + (int)( bf - buf ); } - break; - -#ifdef RR_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va,double); // eat it - s = (char*)"No float"; - l = 8; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - goto scopy; -#else - case 'A': // float - h=hexu; - goto hexfloat; - - case 'a': // hex float - h=hex; - hexfloat: - fv = va_arg(va,double); - if (pr==-1) pr=6; // default is 6 - // read the double into a string - if ( rrreal_to_parts( (rS64*)&n64, &dp, fv ) ) - fl |= NG; - - s = num+64; - - // sign - lead[0]=0; if (fl&NG) { lead[0]=1; lead[1]='-'; } else if (fl&LS) { lead[0]=1; lead[1]=' '; } else if (fl&LP) { lead[0]=1; lead[1]='+'; }; - - if (dp==-1023) dp=(n64)?-1022:0; else n64|=(((rU64)1)<<52); - n64<<=(64-56); - if (pr<15) n64+=((((rU64)8)<<56)>>(pr*4)); - // add leading chars - - #ifdef RR_SPRINTF_MSVC_MODE - *s++='0';*s++='x'; - #else - lead[1+lead[0]]='0'; lead[2+lead[0]]='x'; lead[0]+=2; - #endif - *s++=h[(n64>>60)&15]; n64<<=4; - if ( pr ) *s++=RRperiod; - sn = s; - - // print the bits - n = pr; if (n>13) n = 13; if (pr>(rS32)n) tz=pr-n; pr = 0; - while(n--) { *s++=h[(n64>>60)&15]; n64<<=4; } - - // print the expo - tail[1]=h[17]; - if (dp<0) { tail[2]='-'; dp=-dp;} else tail[2]='+'; - n = (dp>=1000)?6:((dp>=100)?5:((dp>=10)?4:3)); - tail[0]=(char)n; - for(;;) { tail[n]='0'+dp%10; if (n<=3) break; --n; dp/=10; } - - dp = (int)(s-sn); - l = (int)(s-(num+64)); - s = num+64; - cs = 1 + (3<<24); - goto scopy; - - case 'G': // float - h=hexu; - goto dosmallfloat; - - case 'g': // float - h=hex; - dosmallfloat: - fv = va_arg(va,double); - if (pr==-1) pr=6; else if (pr==0) pr = 1; // default is 6 - // read the double into a string - if ( rrreal_to_str( &sn, &l, num, &dp, fv, (pr-1)|0x80000000 ) ) - fl |= NG; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if ( l > (rU32)pr ) l = pr; while ((l>1)&&(pr)&&(sn[l-1]=='0')) { --pr; --l; } - - // should we use %e - if ((dp<=-4)||(dp>(rS32)n)) - { - if ( pr > (rS32)l ) pr = l-1; else if ( pr ) --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g sematics for %f - if(dp>0) { pr=(dp<(rS32)l)?l-dp:0; } else { pr = -dp+((pr>(rS32)l)?l:pr); } - goto dofloatfromg; - - case 'E': // float - h=hexu; - goto doexp; - - case 'e': // float - h=hex; - doexp: - fv = va_arg(va,double); - if (pr==-1) pr=6; // default is 6 - // read the double into a string - if ( rrreal_to_str( &sn, &l, num, &dp, fv, pr|0x80000000 ) ) - fl |= NG; - doexpfromg: - tail[0]=0; - lead[0]=0; if (fl&NG) { lead[0]=1; lead[1]='-'; } else if (fl&LS) { lead[0]=1; lead[1]=' '; } else if (fl&LP) { lead[0]=1; lead[1]='+'; }; - if ( dp == RRSPECIAL ) { s=(char*)sn; cs=0; pr=0; goto scopy; } - s=num+64; - // handle leading chars - *s++=sn[0]; - - if (pr) *s++=RRperiod; - - // handle after decimal - if ((l-1)>(rU32)pr) l=pr+1; - for(n=1;n=100)?5:4; - #endif - tail[0]=(char)n; - for(;;) { tail[n]='0'+dp%10; if (n<=3) break; --n; dp/=10; } - cs = 1 + (3<<24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va,double); - doafloat: - // do kilos - if (fl&KI) {while(fl<0x4000000) { if ((fv<1024.0) && (fv>-1024.0)) break; fv/=1024.0; fl+=0x1000000; }} - if (pr==-1) pr=6; // default is 6 - // read the double into a string - if ( rrreal_to_str( &sn, &l, num, &dp, fv, pr ) ) - fl |= NG; - dofloatfromg: - tail[0]=0; - // sign - lead[0]=0; if (fl&NG) { lead[0]=1; lead[1]='-'; } else if (fl&LS) { lead[0]=1; lead[1]=' '; } else if (fl&LP) { lead[0]=1; lead[1]='+'; }; - if ( dp == RRSPECIAL ) { s=(char*)sn; cs=0; pr=0; goto scopy; } - s=num+64; - - // handle the three decimal varieties - if (dp<=0) - { - rS32 i; - // handle 0.000*000xxxx - *s++='0'; if (pr) *s++=RRperiod; - n=-dp; if((rS32)n>pr) n=pr; i=n; while(i) { if ((((rUINTa)s)&3)==0) break; *s++='0'; --i; } while(i>=4) { *(rU32*)s=0x30303030; s+=4; i-=4; } while(i) { *s++='0'; --i; } - if ((rS32)(l+n)>pr) l=pr-n; i=l; while(i) { *s++=*sn++; --i; } - tz = pr-(n+l); - cs = 1 + (3<<24); // how many tens did we write (for commas below) - } - else - { - cs = (fl&CS)?((600-(rU32)dp)%3):0; - if ((rU32)dp>=l) - { - // handle xxxx000*000.0 - n=0; for(;;) { if ((fl&CS) && (++cs==4)) { cs = 0; *s++=RRcomma; } else { *s++=sn[n]; ++n; if (n>=l) break; } } - if (n<(rU32)dp) - { - n = dp - n; - if ((fl&CS)==0) { while(n) { if ((((rUINTa)s)&3)==0) break; *s++='0'; --n; } while(n>=4) { *(rU32*)s=0x30303030; s+=4; n-=4; } } - while(n) { if ((fl&CS) && (++cs==4)) { cs = 0; *s++=RRcomma; } else { *s++='0'; --n; } } - } - cs = (int)(s-(num+64)) + (3<<24); // cs is how many tens - if (pr) { *s++=RRperiod; tz=pr;} - } - else - { - // handle xxxxx.xxxx000*000 - n=0; for(;;) { if ((fl&CS) && (++cs==4)) { cs = 0; *s++=RRcomma; } else { *s++=sn[n]; ++n; if (n>=(rU32)dp) break; } } - cs = (int)(s-(num+64)) + (3<<24); // cs is how many tens - if (pr) *s++=RRperiod; - if ((l-dp)>(rU32)pr) l=pr+dp; - while(n>24) { tail[2]="_kmgt"[fl>>24]; tail[0]=2; } } }; - - flt_lead: - // get the length that we copied - l = (rU32) ( s-(num+64) ); - s=num+64; - goto scopy; -#endif - - case 'B': // upper binary - h = hexu; - goto binary; - - case 'b': // lower binary - h = hex; - binary: - lead[0]=0; - if (fl&LX) { lead[0]=2;lead[1]='0';lead[2]=h[0xb]; } - l=(8<<4)|(1<<8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0]=0; - if (fl&LX) { lead[0]=1;lead[1]='0'; } - l=(3<<4)|(3<<8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void*)==8)?BI:0; - pr = sizeof(void*)*2; - fl &= ~LZ; // 'p' only prints the pointer with zeros - // drop through to X - - case 'X': // upper binary - h = hexu; - goto dohexb; - - case 'x': // lower binary - h = hex; dohexb: - l=(4<<4)|(4<<8); - lead[0]=0; - if (fl&LX) { lead[0]=2;lead[1]='0';lead[2]=h[16]; } - radixnum: - // get the number - if ( fl&BI ) - n64 = va_arg(va,rU64); - else - n64 = va_arg(va,rU32); - - s = num + NUMSZ; dp = 0; - // clear tail, and clear leading if value is zero - tail[0]=0; if (n64==0) { lead[0]=0; if (pr==0) { l=0; cs = ( ((l>>4)&15)) << 24; goto scopy; } } - // convert to string - for(;;) { *--s = h[n64&((1<<(l>>8))-1)]; n64>>=(l>>8); if ( ! ( (n64) || ((rS32) ( (num+NUMSZ) - s ) < pr ) ) ) break; if ( fl&CS) { ++l; if ((l&15)==((l>>4)&15)) { l&=~15; *--s=RRcomma; } } }; - // get the tens and the comma pos - cs = (rU32) ( (num+NUMSZ) - s ) + ( ( ((l>>4)&15)) << 24 ); - // get the length that we copied - l = (rU32) ( (num+NUMSZ) - s ); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if ( fl&BI ) - { - rS64 i64 = va_arg(va,rS64); n64 = (rU64)i64; if ((f[0]!='u') && (i64<0)) { n64=(rU64)-i64; fl|=NG; } - } - else - { - rS32 i = va_arg(va,rS32); n64 = (rU32)i; if ((f[0]!='u') && (i<0)) { n64=(rU32)-i; fl|=NG; } - } - - #ifndef RR_SPRINTF_NOFLOAT - if (fl&KI) { if (n64<1024) pr=0; else if (pr==-1) pr=1; fv=(double)(rS64)n64; goto doafloat; } - #endif - - // convert to string - s = num+NUMSZ; l=0; - - for(;;) - { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char * o=s-8; - if (n64>=100000000) { n = (rU32)( n64 % 100000000); n64 /= 100000000; } else {n = (rU32)n64; n64 = 0; } - if((fl&CS)==0) { while(n) { s-=2; *(rU16*)s=*(rU16*)&rrdiglookup[(n%100)*2]; n/=100; } } - while (n) { if ( ( fl&CS) && (l++==3) ) { l=0; *--s=RRcomma; --o; } else { *--s=(char)(n%10)+'0'; n/=10; } } - if (n64==0) { if ((s[0]=='0') && (s!=(num+NUMSZ))) ++s; break; } - while (s!=o) if ( ( fl&CS) && (l++==3) ) { l=0; *--s=RRcomma; --o; } else { *--s='0'; } - } - - tail[0]=0; - // sign - lead[0]=0; if (fl&NG) { lead[0]=1; lead[1]='-'; } else if (fl&LS) { lead[0]=1; lead[1]=' '; } else if (fl&LP) { lead[0]=1; lead[1]='+'; }; - - // get the length that we copied - l = (rU32) ( (num+NUMSZ) - s ); if ( l == 0 ) { *--s='0'; l = 1; } - cs = l + (3<<24); - if (pr<0) pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr<(rS32)l) pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw<(rS32)n) fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ( (fl&LJ)==0 ) - { - if (fl&LZ) // if leading zeros, everything is in pr - { - pr = (fw>pr)?fw:pr; - fw = 0; - } - else - { - fl &= ~CS; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw+pr) - { - rS32 i; rU32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ( (fl&LJ)==0 ) while(fw>0) { cb_buf_clamp(i,fw); fw -= i; while(i) { if ((((rUINTa)bf)&3)==0) break; *bf++=' '; --i; } while(i>=4) { *(rU32*)bf=0x20202020; bf+=4; i-=4; } while (i) {*bf++=' '; --i;} chk_cb_buf(1); } - - // copy leader - sn=lead+1; while(lead[0]) { cb_buf_clamp(i,lead[0]); lead[0] -= (char)i; while (i) {*bf++=*sn++; --i;} chk_cb_buf(1); } - - // copy leading zeros - c = cs >> 24; cs &= 0xffffff; - cs = (fl&CS)?((rU32)(c-((pr+cs)%(c+1)))):0; - while(pr>0) { cb_buf_clamp(i,pr); pr -= i; if((fl&CS)==0) { while(i) { if ((((rUINTa)bf)&3)==0) break; *bf++='0'; --i; } while(i>=4) { *(rU32*)bf=0x30303030; bf+=4; i-=4; } } while (i) { if((fl&CS) && (cs++==c)) { cs = 0; *bf++=RRcomma; } else *bf++='0'; --i; } chk_cb_buf(1); } - } - - // copy leader if there is still one - sn=lead+1; while(lead[0]) { rS32 i; cb_buf_clamp(i,lead[0]); lead[0] -= (char)i; while (i) {*bf++=*sn++; --i;} chk_cb_buf(1); } - - // copy the string - n = l; while (n) { rS32 i; cb_buf_clamp(i,n); n-=i; RR_UNALIGNED( while(i>=4) { *(rU32*)bf=*(rU32*)s; bf+=4; s+=4; i-=4; } ) while (i) {*bf++=*s++; --i;} chk_cb_buf(1); } - - // copy trailing zeros - while(tz) { rS32 i; cb_buf_clamp(i,tz); tz -= i; while(i) { if ((((rUINTa)bf)&3)==0) break; *bf++='0'; --i; } while(i>=4) { *(rU32*)bf=0x30303030; bf+=4; i-=4; } while (i) {*bf++='0'; --i;} chk_cb_buf(1); } - - // copy tail if there is one - sn=tail+1; while(tail[0]) { rS32 i; cb_buf_clamp(i,tail[0]); tail[0] -= (char)i; while (i) {*bf++=*sn++; --i;} chk_cb_buf(1); } - - // handle the left justify - if (fl&LJ) if (fw>0) { while (fw) { rS32 i; cb_buf_clamp(i,fw); fw-=i; while(i) { if ((((rUINTa)bf)&3)==0) break; *bf++=' '; --i; } while(i>=4) { *(rU32*)bf=0x20202020; bf+=4; i-=4; } while (i--) *bf++=' '; chk_cb_buf(1); } } - break; - - default: // unknown, just copy code - s = num + NUMSZ -1; *s = f[0]; - l = 1; - fw=pr=fl=0; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - goto scopy; - } - ++f; - } - endfmt: - - if (!callback) - *bf = 0; - else - flush_cb(); - - done: - return tlen + (int)(bf-buf); -} - -// cleanup -#undef LJ -#undef LP -#undef LS -#undef LX -#undef LZ -#undef BI -#undef CS -#undef NG -#undef KI -#undef NUMSZ -#undef chk_cb_bufL -#undef chk_cb_buf -#undef flush_cb -#undef cb_buf_clamp - -// ============================================================================ -// wrapper functions - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( sprintf )( char * buf, char const * fmt, ... ) -{ - va_list va; - va_start( va, fmt ); - return RR_SPRINTF_DECORATE( vsprintfcb )( 0, 0, buf, fmt, va ); -} - -typedef struct RRCCS -{ - char * buf; - int count; - char tmp[ RR_SPRINTF_MIN ]; -} RRCCS; - -static char * rrclampcallback( char * buf, void * user, int len ) -{ - RRCCS * c = (RRCCS*)user; - - if ( len > c->count ) len = c->count; - - if (len) - { - if ( buf != c->buf ) - { - char * s, * d, * se; - d = c->buf; s = buf; se = buf+len; - do{ *d++ = *s++; } while (sbuf += len; - c->count -= len; - } - - if ( c->count <= 0 ) return 0; - return ( c->count >= RR_SPRINTF_MIN ) ? c->buf : c->tmp; // go direct into buffer if you can -} - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - RRCCS c; - int l; - - if ( count == 0 ) - return 0; - - c.buf = buf; - c.count = count; - - RR_SPRINTF_DECORATE( vsprintfcb )( rrclampcallback, &c, rrclampcallback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - - return l; -} - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( snprintf )( char * buf, int count, char const * fmt, ... ) -{ - va_list va; - va_start( va, fmt ); - - return RR_SPRINTF_DECORATE( vsnprintf )( buf, count, fmt, va ); -} - -RRPUBLIC_DEF int RR_SPRINTF_DECORATE( vsprintf )( char * buf, char const * fmt, va_list va ) -{ - return RR_SPRINTF_DECORATE( vsprintfcb )( 0, 0, buf, fmt, va ); -} - -// ======================================================================= -// low level float utility functions - -#ifndef RR_SPRINTF_NOFLOAT - - // copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) - #define RRCOPYFP(dest,src) { int cn; for(cn=0;cn<8;cn++) ((char*)&dest)[cn]=((char*)&src)[cn]; } - -// get float info -static rS32 rrreal_to_parts( rS64 * bits, rS32 * expo, double value ) -{ - double d; - rS64 b = 0; - - // load value and round at the frac_digits - d = value; - - RRCOPYFP( b, d ); - - *bits = b & ((((rU64)1)<<52)-1); - *expo = ((b >> 52) & 2047)-1023; - - return (rS32)(b >> 63); -} - -static double const rrbot[23]={1e+000,1e+001,1e+002,1e+003,1e+004,1e+005,1e+006,1e+007,1e+008,1e+009,1e+010,1e+011,1e+012,1e+013,1e+014,1e+015,1e+016,1e+017,1e+018,1e+019,1e+020,1e+021,1e+022}; -static double const rrnegbot[22]={1e-001,1e-002,1e-003,1e-004,1e-005,1e-006,1e-007,1e-008,1e-009,1e-010,1e-011,1e-012,1e-013,1e-014,1e-015,1e-016,1e-017,1e-018,1e-019,1e-020,1e-021,1e-022}; -static double const rrnegboterr[22]={-5.551115123125783e-018,-2.0816681711721684e-019,-2.0816681711721686e-020,-4.7921736023859299e-021,-8.1803053914031305e-022,4.5251888174113741e-023,4.5251888174113739e-024,-2.0922560830128471e-025,-6.2281591457779853e-026,-3.6432197315497743e-027,6.0503030718060191e-028,2.0113352370744385e-029,-3.0373745563400371e-030,1.1806906454401013e-032,-7.7705399876661076e-032,2.0902213275965398e-033,-7.1542424054621921e-034,-7.1542424054621926e-035,2.4754073164739869e-036,5.4846728545790429e-037,9.2462547772103625e-038,-4.8596774326570872e-039}; -static double const rrtop[13]={1e+023,1e+046,1e+069,1e+092,1e+115,1e+138,1e+161,1e+184,1e+207,1e+230,1e+253,1e+276,1e+299}; -static double const rrnegtop[13]={1e-023,1e-046,1e-069,1e-092,1e-115,1e-138,1e-161,1e-184,1e-207,1e-230,1e-253,1e-276,1e-299}; -static double const rrtoperr[13]={8388608,6.8601809640529717e+028,-7.253143638152921e+052,-4.3377296974619174e+075,-1.5559416129466825e+098,-3.2841562489204913e+121,-3.7745893248228135e+144,-1.7356668416969134e+167,-3.8893577551088374e+190,-9.9566444326005119e+213,6.3641293062232429e+236,-5.2069140800249813e+259,-5.2504760255204387e+282}; -static double const rrnegtoperr[13]={3.9565301985100693e-040,-2.299904345391321e-063,3.6506201437945798e-086,1.1875228833981544e-109,-5.0644902316928607e-132,-6.7156837247865426e-155,-2.812077463003139e-178,-5.7778912386589953e-201,7.4997100559334532e-224,-4.6439668915134491e-247,-6.3691100762962136e-270,-9.436808465446358e-293,8.0970921678014997e-317}; - -#if defined(_MSC_VER) && (_MSC_VER<=1200) -static rU64 const rrpot[20]={1,10,100,1000, 10000,100000,1000000,10000000, 100000000,1000000000,10000000000,100000000000, 1000000000000,10000000000000,100000000000000,1000000000000000, 10000000000000000,100000000000000000,1000000000000000000,10000000000000000000U }; -#define rrtento19th ((rU64)1000000000000000000) -#else -static rU64 const rrpot[20]={1,10,100,1000, 10000,100000,1000000,10000000, 100000000,1000000000,10000000000ULL,100000000000ULL, 1000000000000ULL,10000000000000ULL,100000000000000ULL,1000000000000000ULL, 10000000000000000ULL,100000000000000000ULL,1000000000000000000ULL,10000000000000000000ULL }; -#define rrtento19th (1000000000000000000ULL) -#endif - -#define rrddmulthi(oh,ol,xh,yh) \ -{ \ - double ahi=0,alo,bhi=0,blo; \ - rS64 bt; \ - oh = xh * yh; \ - RRCOPYFP(bt,xh); bt&=((~(rU64)0)<<27); RRCOPYFP(ahi,bt); alo = xh-ahi; \ - RRCOPYFP(bt,yh); bt&=((~(rU64)0)<<27); RRCOPYFP(bhi,bt); blo = yh-bhi; \ - ol = ((ahi*bhi-oh)+ahi*blo+alo*bhi)+alo*blo; \ -} - -#define rrddtoS64(ob,xh,xl) \ -{ \ - double ahi=0,alo,vh,t;\ - ob = (rS64)ph;\ - vh=(double)ob;\ - ahi = ( xh - vh );\ - t = ( ahi - xh );\ - alo = (xh-(ahi-t))-(vh+t);\ - ob += (rS64)(ahi+alo+xl);\ -} - - -#define rrddrenorm(oh,ol) { double s; s=oh+ol; ol=ol-(s-oh); oh=s; } - -#define rrddmultlo(oh,ol,xh,xl,yh,yl) \ - ol = ol + ( xh*yl + xl*yh ); \ - -#define rrddmultlos(oh,ol,xh,yl) \ - ol = ol + ( xh*yl ); \ - -static void rrraise_to_power10( double *ohi, double *olo, double d, rS32 power ) // power can be -323 to +350 -{ - double ph, pl; - if ((power>=0) && (power<=22)) - { - rrddmulthi(ph,pl,d,rrbot[power]); - } - else - { - rS32 e,et,eb; - double p2h,p2l; - - e=power; if (power<0) e=-e; - et = (e*0x2c9)>>14;/* %23 */ if (et>13) et=13; eb = e-(et*23); - - ph = d; pl = 0.0; - if (power<0) - { - if (eb) { --eb; rrddmulthi(ph,pl,d,rrnegbot[eb]); rrddmultlos(ph,pl,d,rrnegboterr[eb]); } - if (et) - { - rrddrenorm(ph,pl); - --et; rrddmulthi(p2h,p2l,ph,rrnegtop[et]); rrddmultlo(p2h,p2l,ph,pl,rrnegtop[et],rrnegtoperr[et]); ph=p2h;pl=p2l; - } - } - else - { - if (eb) - { - e = eb; if (eb>22) eb=22; e -= eb; - rrddmulthi(ph,pl,d,rrbot[eb]); - if ( e ) { rrddrenorm(ph,pl); rrddmulthi(p2h,p2l,ph,rrbot[e]); rrddmultlos(p2h,p2l,rrbot[e],pl); ph=p2h;pl=p2l; } - } - if (et) - { - rrddrenorm(ph,pl); - --et; rrddmulthi(p2h,p2l,ph,rrtop[et]); rrddmultlo(p2h,p2l,ph,pl,rrtop[et],rrtoperr[et]); ph=p2h;pl=p2l; - } - } - } - rrddrenorm(ph,pl); - *ohi = ph; *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static rS32 rrreal_to_str( char const * * start, rU32 * len, char *out, rS32 * decimal_pos, double value, rU32 frac_digits ) -{ - double d; - rS64 bits = 0; - rS32 expo, e, ng, tens; - - d = value; - RRCOPYFP(bits,d); - expo = (bits >> 52) & 2047; - ng = (rS32)(bits >> 63); - if (ng) d=-d; - - if ( expo == 2047 ) // is nan or inf? - { - *start = (bits&((((rU64)1)<<52)-1)) ? "NaN" : "Inf"; - *decimal_pos = RRSPECIAL; - *len = 3; - return ng; - } - - if ( expo == 0 ) // is zero or denormal - { - if ((bits<<1)==0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; *len = 1; - return ng; - } - // find the right expo for denormals - { - rS64 v = ((rU64)1)<<51; - while ((bits&v)==0) { --expo; v >>= 1; } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph,pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens=expo-1023; tens = (tens<0)?((tens*617)/2048):(((tens*1233)/4096)+1); - - // move the significant bits into position and stick them into an int - rrraise_to_power10( &ph, &pl, d, 18-tens ); - - // get full as much precision from double-double as possible - rrddtoS64( bits, ph,pl ); - - // check if we undershot - if ( ((rU64)bits) >= rrtento19th ) ++tens; - } - - // now do the rounding in integer land - frac_digits = ( frac_digits & 0x80000000 ) ? ( (frac_digits&0x7ffffff) + 1 ) : ( tens + frac_digits ); - if ( ( frac_digits < 24 ) ) - { - rU32 dg = 1; if ((rU64)bits >= rrpot[9] ) dg=10; while( (rU64)bits >= rrpot[dg] ) { ++dg; if (dg==20) goto noround; } - if ( frac_digits < dg ) - { - rU64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ( (rU32)e >= 24 ) goto noround; - r = rrpot[e]; - bits = bits + (r/2); - if ( (rU64)bits >= rrpot[dg] ) ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if ( bits ) - { - rU32 n; for(;;) { if ( bits<=0xffffffff ) break; if (bits%1000) goto donez; bits/=1000; } n = (rU32)bits; while ((n%1000)==0) n/=1000; bits=n; donez:; - } - - // convert to string - out += 64; - e = 0; - for(;;) - { - rU32 n; - char * o = out-8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits>=100000000) { n = (rU32)( bits % 100000000); bits /= 100000000; } else {n = (rU32)bits; bits = 0; } - while(n) { out-=2; *(rU16*)out=*(rU16*)&rrdiglookup[(n%100)*2]; n/=100; e+=2; } - if (bits==0) { if ((e) && (out[0]=='0')) { ++out; --e; } break; } - while( out!=o ) { *--out ='0'; ++e; } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef rrddmulthi -#undef rrddrenorm -#undef rrddmultlo -#undef rrddmultlos -#undef RRSPECIAL -#undef RRCOPYFP - -#endif - -// clean up -#undef rU16 -#undef rU32 -#undef rS32 -#undef rU64 -#undef rS64 -#undef RRPUBLIC_DEC -#undef RRPUBLIC_DEF -#undef RR_SPRINTF_DECORATE -#undef RR_UNALIGNED - -#endif - -#endif diff --git a/source/engine/thirdparty/stb/deprecated/stb.h b/source/engine/thirdparty/stb/deprecated/stb.h deleted file mode 100644 index 1633c3b..0000000 --- a/source/engine/thirdparty/stb/deprecated/stb.h +++ /dev/null @@ -1,13111 +0,0 @@ -/* stb.h - v2.37 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h - no warranty is offered or implied; use this code at your own risk - - This is a single header file with a bunch of useful utilities - for getting stuff done in C/C++. - - Documentation: http://nothings.org/stb/stb_h.html - Unit tests: http://nothings.org/stb/stb.c - - ============================================================================ - You MUST - - #define STB_DEFINE - - in EXACTLY _one_ C or C++ file that includes this header, BEFORE the - include, like this: - - #define STB_DEFINE - #include "stb.h" - - All other files should just #include "stb.h" without the #define. - ============================================================================ - -Version History - - 2.36 various fixes - 2.35 fix clang-cl issues with swprintf - 2.34 fix warnings - 2.33 more fixes to random numbers - 2.32 stb_intcmprev, stb_uidict, fix random numbers on Linux - 2.31 stb_ucharcmp - 2.30 MinGW fix - 2.29 attempt to fix use of swprintf() - 2.28 various new functionality - 2.27 test _WIN32 not WIN32 in STB_THREADS - 2.26 various warning & bugfixes - 2.25 various warning & bugfixes - 2.24 various warning & bugfixes - 2.23 fix 2.22 - 2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name - 2.21 utf-8 decoder rejects "overlong" encodings; attempted 64-bit improvements - 2.20 fix to hash "copy" function--reported by someone with handle "!=" - 2.19 ??? - 2.18 stb_readdir_subdirs_mask - 2.17 stb_cfg_dir - 2.16 fix stb_bgio_, add stb_bgio_stat(); begin a streaming wrapper - 2.15 upgraded hash table template to allow: - - aggregate keys (explicit comparison func for EMPTY and DEL keys) - - "static" implementations (so they can be culled if unused) - 2.14 stb_mprintf - 2.13 reduce identifiable strings in STB_NO_STB_STRINGS - 2.12 fix STB_ONLY -- lots of uint32s, TRUE/FALSE things had crept in - 2.11 fix bug in stb_dirtree_get() which caused "c://path" sorts of stuff - 2.10 STB_F(), STB_I() inline constants (also KI,KU,KF,KD) - 2.09 stb_box_face_vertex_axis_side - 2.08 bugfix stb_trimwhite() - 2.07 colored printing in windows (why are we in 1985?) - 2.06 comparison functions are now functions-that-return-functions and - accept a struct-offset as a parameter (not thread-safe) - 2.05 compile and pass tests under Linux (but no threads); thread cleanup - 2.04 stb_cubic_bezier_1d, smoothstep, avoid dependency on registry - 2.03 ? - 2.02 remove integrated documentation - 2.01 integrate various fixes; stb_force_uniprocessor - 2.00 revised stb_dupe to use multiple hashes - 1.99 stb_charcmp - 1.98 stb_arr_deleten, stb_arr_insertn - 1.97 fix stb_newell_normal() - 1.96 stb_hash_number() - 1.95 hack stb__rec_max; clean up recursion code to use new functions - 1.94 stb_dirtree; rename stb_extra to stb_ptrmap - 1.93 stb_sem_new() API cleanup (no blockflag-starts blocked; use 'extra') - 1.92 stb_threadqueue--multi reader/writer queue, fixed size or resizeable - 1.91 stb_bgio_* for reading disk asynchronously - 1.90 stb_mutex uses CRITICAL_REGION; new stb_sync primitive for thread - joining; workqueue supports stb_sync instead of stb_semaphore - 1.89 support ';' in constant-string wildcards; stb_mutex wrapper (can - implement with EnterCriticalRegion eventually) - 1.88 portable threading API (only for win32 so far); worker thread queue - 1.87 fix wildcard handling in stb_readdir_recursive - 1.86 support ';' in wildcards - 1.85 make stb_regex work with non-constant strings; - beginnings of stb_introspect() - 1.84 (forgot to make notes) - 1.83 whoops, stb_keep_if_different wasn't deleting the temp file - 1.82 bring back stb_compress from stb_file.h for cmirror - 1.81 various bugfixes, STB_FASTMALLOC_INIT inits FASTMALLOC in release - 1.80 stb_readdir returns utf8; write own utf8-utf16 because lib was wrong - 1.79 stb_write - 1.78 calloc() support for malloc wrapper, STB_FASTMALLOC - 1.77 STB_FASTMALLOC - 1.76 STB_STUA - Lua-like language; (stb_image, stb_csample, stb_bilinear) - 1.75 alloc/free array of blocks; stb_hheap bug; a few stb_ps_ funcs; - hash*getkey, hash*copy; stb_bitset; stb_strnicmp; bugfix stb_bst - 1.74 stb_replaceinplace; use stdlib C function to convert utf8 to UTF-16 - 1.73 fix performance bug & leak in stb_ischar (C++ port lost a 'static') - 1.72 remove stb_block, stb_block_manager, stb_decompress (to stb_file.h) - 1.71 stb_trimwhite, stb_tokens_nested, etc. - 1.70 back out 1.69 because it might problemize mixed builds; stb_filec() - 1.69 (stb_file returns 'char *' in C++) - 1.68 add a special 'tree root' data type for stb_bst; stb_arr_end - 1.67 full C++ port. (stb_block_manager) - 1.66 stb_newell_normal - 1.65 stb_lex_item_wild -- allow wildcard items which MUST match entirely - 1.64 stb_data - 1.63 stb_log_name - 1.62 stb_define_sort; C++ cleanup - 1.61 stb_hash_fast -- Paul Hsieh's hash function (beats Bob Jenkins'?) - 1.60 stb_delete_directory_recursive - 1.59 stb_readdir_recursive - 1.58 stb_bst variant with parent pointer for O(1) iteration, not O(log N) - 1.57 replace LCG random with Mersenne Twister (found a public domain one) - 1.56 stb_perfect_hash, stb_ischar, stb_regex - 1.55 new stb_bst API allows multiple BSTs per node (e.g. secondary keys) - 1.54 bugfix: stb_define_hash, stb_wildmatch, regexp - 1.53 stb_define_hash; recoded stb_extra, stb_sdict use it - 1.52 stb_rand_define, stb_bst, stb_reverse - 1.51 fix 'stb_arr_setlen(NULL, 0)' - 1.50 stb_wordwrap - 1.49 minor improvements to enable the scripting language - 1.48 better approach for stb_arr using stb_malloc; more invasive, clearer - 1.47 stb_lex (lexes stb.h at 1.5ML/s on 3Ghz P4; 60/70% of optimal/flex) - 1.46 stb_wrapper_*, STB_MALLOC_WRAPPER - 1.45 lightly tested DFA acceleration of regexp searching - 1.44 wildcard matching & searching; regexp matching & searching - 1.43 stb_temp - 1.42 allow stb_arr to use stb_malloc/realloc; note this is global - 1.41 make it compile in C++; (disable stb_arr in C++) - 1.40 stb_dupe tweak; stb_swap; stb_substr - 1.39 stb_dupe; improve stb_file_max to be less stupid - 1.38 stb_sha1_file: generate sha1 for file, even > 4GB - 1.37 stb_file_max; partial support for utf8 filenames in Windows - 1.36 remove STB__NO_PREFIX - poor interaction with IDE, not worth it - streamline stb_arr to make it separately publishable - 1.35 bugfixes for stb_sdict, stb_malloc(0), stristr - 1.34 (streaming interfaces for stb_compress) - 1.33 stb_alloc; bug in stb_getopt; remove stb_overflow - 1.32 (stb_compress returns, smaller&faster; encode window & 64-bit len) - 1.31 stb_prefix_count - 1.30 (STB__NO_PREFIX - remove stb_ prefixes for personal projects) - 1.29 stb_fput_varlen64, etc. - 1.28 stb_sha1 - 1.27 ? - 1.26 stb_extra - 1.25 ? - 1.24 stb_copyfile - 1.23 stb_readdir - 1.22 ? - 1.21 ? - 1.20 ? - 1.19 ? - 1.18 ? - 1.17 ? - 1.16 ? - 1.15 stb_fixpath, stb_splitpath, stb_strchr2 - 1.14 stb_arr - 1.13 ?stb, stb_log, stb_fatal - 1.12 ?stb_hash2 - 1.11 miniML - 1.10 stb_crc32, stb_adler32 - 1.09 stb_sdict - 1.08 stb_bitreverse, stb_ispow2, stb_big32 - stb_fopen, stb_fput_varlen, stb_fput_ranged - stb_fcmp, stb_feq - 1.07 (stb_encompress) - 1.06 stb_compress - 1.05 stb_tokens, (stb_hheap) - 1.04 stb_rand - 1.03 ?(s-strings) - 1.02 ?stb_filelen, stb_tokens - 1.01 stb_tolower - 1.00 stb_hash, stb_intcmp - stb_file, stb_stringfile, stb_fgets - stb_prefix, stb_strlower, stb_strtok - stb_image - (stb_array), (stb_arena) - -Parenthesized items have since been removed. - -LICENSE - - See end of file for license information. - -CREDITS - - Written by Sean Barrett. - - Fixes: - Philipp Wiesemann - Robert Nix - r-lyeh - blackpawn - github:Mojofreem - Ryan Whitworth - Vincent Isambart - Mike Sartain - Eugene Opalev - Tim Sjostrand - github:infatum - Dave Butler (Croepha) - Ethan Lee (flibitijibibo) - Brian Collins - Kyle Langley -*/ - -#include - -#ifndef STB__INCLUDE_STB_H -#define STB__INCLUDE_STB_H - -#define STB_VERSION 1 - -#ifdef STB_INTROSPECT - #define STB_DEFINE -#endif - -#ifdef STB_DEFINE_THREADS - #ifndef STB_DEFINE - #define STB_DEFINE - #endif - #ifndef STB_THREADS - #define STB_THREADS - #endif -#endif - -#if defined(_WIN32) && !defined(__MINGW32__) - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif - #ifndef _CRT_NON_CONFORMING_SWPRINTFS - #define _CRT_NON_CONFORMING_SWPRINTFS - #endif - #if !defined(_MSC_VER) || _MSC_VER > 1700 - #include // _BitScanReverse - #endif -#endif - -#include // stdlib could have min/max -#include // need FILE -#include // stb_define_hash needs memcpy/memset -#include // stb_dirtree -#ifdef __MINGW32__ - #include // O_RDWR -#endif - -#ifdef STB_PERSONAL - typedef int Bool; - #define False 0 - #define True 1 -#endif - -#ifdef STB_MALLOC_WRAPPER_PAGED - #define STB_MALLOC_WRAPPER_DEBUG -#endif -#ifdef STB_MALLOC_WRAPPER_DEBUG - #define STB_MALLOC_WRAPPER -#endif -#ifdef STB_MALLOC_WRAPPER_FASTMALLOC - #define STB_FASTMALLOC - #define STB_MALLOC_WRAPPER -#endif - -#ifdef STB_FASTMALLOC - #ifndef _WIN32 - #undef STB_FASTMALLOC - #endif -#endif - -#ifdef STB_DEFINE - #include - #include - #include - #include - #include - #ifndef _WIN32 - #include - #else - #include // _mktemp - #include // _rmdir - #endif - #include // stat()/_stat() - #include // stat()/_stat() -#endif - -#define stb_min(a,b) ((a) < (b) ? (a) : (b)) -#define stb_max(a,b) ((a) > (b) ? (a) : (b)) - -#ifndef STB_ONLY - #if !defined(__cplusplus) && !defined(min) && !defined(max) - #define min(x,y) stb_min(x,y) - #define max(x,y) stb_max(x,y) - #endif - - #ifndef M_PI - #define M_PI 3.14159265358979323846f - #endif - - #ifndef TRUE - #define TRUE 1 - #define FALSE 0 - #endif - - #ifndef deg2rad - #define deg2rad(a) ((a)*(M_PI/180)) - #endif - #ifndef rad2deg - #define rad2deg(a) ((a)*(180/M_PI)) - #endif - - #ifndef swap - #ifndef __cplusplus - #define swap(TYPE,a,b) \ - do { TYPE stb__t; stb__t = (a); (a) = (b); (b) = stb__t; } while (0) - #endif - #endif - - typedef unsigned char uint8 ; - typedef signed char int8 ; - typedef unsigned short uint16; - typedef signed short int16; - #if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32) - typedef unsigned long uint32; - typedef signed long int32; - #else - typedef unsigned int uint32; - typedef signed int int32; - #endif - - typedef unsigned char uchar ; - typedef unsigned short ushort; - typedef unsigned int uint ; - typedef unsigned long ulong ; - - // produce compile errors if the sizes aren't right - typedef char stb__testsize16[sizeof(int16)==2]; - typedef char stb__testsize32[sizeof(int32)==4]; -#endif - -#ifndef STB_TRUE - #define STB_TRUE 1 - #define STB_FALSE 0 -#endif - -// if we're STB_ONLY, can't rely on uint32 or even uint, so all the -// variables we'll use herein need typenames prefixed with 'stb': -typedef unsigned char stb_uchar; -typedef unsigned char stb_uint8; -typedef unsigned int stb_uint; -typedef unsigned short stb_uint16; -typedef short stb_int16; -typedef signed char stb_int8; -#if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32) - typedef unsigned long stb_uint32; - typedef long stb_int32; -#else - typedef unsigned int stb_uint32; - typedef int stb_int32; -#endif -typedef char stb__testsize2_16[sizeof(stb_uint16)==2 ? 1 : -1]; -typedef char stb__testsize2_32[sizeof(stb_uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER - typedef unsigned __int64 stb_uint64; - typedef __int64 stb_int64; - #define STB_IMM_UINT64(literalui64) (literalui64##ui64) - #define STB_IMM_INT64(literali64) (literali64##i64) -#else - // ?? - typedef unsigned long long stb_uint64; - typedef long long stb_int64; - #define STB_IMM_UINT64(literalui64) (literalui64##ULL) - #define STB_IMM_INT64(literali64) (literali64##LL) -#endif -typedef char stb__testsize2_64[sizeof(stb_uint64)==8 ? 1 : -1]; - -// add platform-specific ways of checking for sizeof(char*) == 8, -// and make those define STB_PTR64 -#if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__) || defined(__LP64__) - #define STB_PTR64 -#endif - -#ifdef STB_PTR64 -typedef char stb__testsize2_ptr[sizeof(char *) == 8]; -typedef stb_uint64 stb_uinta; -typedef stb_int64 stb_inta; -#else -typedef char stb__testsize2_ptr[sizeof(char *) == 4]; -typedef stb_uint32 stb_uinta; -typedef stb_int32 stb_inta; -#endif -typedef char stb__testsize2_uinta[sizeof(stb_uinta)==sizeof(char*) ? 1 : -1]; - -// if so, we should define an int type that is the pointer size. until then, -// we'll have to make do with this (which is not the same at all!) - -typedef union -{ - unsigned int i; - void * p; -} stb_uintptr; - - -#ifdef __cplusplus - #define STB_EXTERN extern "C" -#else - #define STB_EXTERN extern -#endif - -// check for well-known debug defines -#if defined(DEBUG) || defined(_DEBUG) || defined(DBG) - #ifndef NDEBUG - #define STB_DEBUG - #endif -#endif - -#ifdef STB_DEBUG - #include -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// C library function platform handling -// - -#ifdef STB_DEFINE - -#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) -static FILE * stb_p_fopen(const char *filename, const char *mode) -{ - FILE *f; - if (0 == fopen_s(&f, filename, mode)) - return f; - else - return NULL; -} -static FILE * stb_p_wfopen(const wchar_t *filename, const wchar_t *mode) -{ - FILE *f; - if (0 == _wfopen_s(&f, filename, mode)) - return f; - else - return NULL; -} -static char *stb_p_strcpy_s(char *a, size_t size, const char *b) -{ - strcpy_s(a,size,b); - return a; -} -static char *stb_p_strncpy_s(char *a, size_t size, const char *b, size_t count) -{ - strncpy_s(a,size,b,count); - return a; -} -#define stb_p_mktemp(s) (_mktemp_s(s, strlen(s)+1) == 0) -#define stb_p_sprintf sprintf_s -#define stb_p_size(x) ,(x) -#else -#define stb_p_fopen fopen -#define stb_p_wfopen _wfopen -#define stb_p_strcpy_s(a,s,b) strcpy(a,b) -#define stb_p_strncpy_s(a,s,b,c) strncpy(a,b,c) -#define stb_p_mktemp(s) (mktemp(s) != NULL) - -#define stb_p_sprintf sprintf -#define stb_p_size(x) -#endif - -#if defined(_WIN32) -#define stb_p_vsnprintf _vsnprintf -#else -#define stb_p_vsnprintf vsnprintf -#endif -#endif // STB_DEFINE - -#if defined(_WIN32) && (_MSC_VER >= 1300) -#define stb_p_stricmp _stricmp -#define stb_p_strnicmp _strnicmp -#define stb_p_strdup _strdup -#else -#define stb_p_strdup strdup -#define stb_p_stricmp stricmp -#define stb_p_strnicmp strnicmp -#endif - -STB_EXTERN void stb_wrapper_malloc(void *newp, size_t sz, char *file, int line); -STB_EXTERN void stb_wrapper_free(void *oldp, char *file, int line); -STB_EXTERN void stb_wrapper_realloc(void *oldp, void *newp, size_t sz, char *file, int line); -STB_EXTERN void stb_wrapper_calloc(size_t num, size_t sz, char *file, int line); -STB_EXTERN void stb_wrapper_listall(void (*func)(void *ptr, size_t sz, char *file, int line)); -STB_EXTERN void stb_wrapper_dump(char *filename); -STB_EXTERN size_t stb_wrapper_allocsize(void *oldp); -STB_EXTERN void stb_wrapper_check(void *oldp); - -#ifdef STB_DEFINE -// this is a special function used inside malloc wrapper -// to do allocations that aren't tracked (to avoid -// reentrancy). Of course if someone _else_ wraps realloc, -// this breaks, but if they're doing that AND the malloc -// wrapper they need to explicitly check for reentrancy. -// -// only define realloc_raw() and we do realloc(NULL,sz) -// for malloc() and realloc(p,0) for free(). -static void * stb__realloc_raw(void *p, int sz) -{ - if (p == NULL) return malloc(sz); - if (sz == 0) { free(p); return NULL; } - return realloc(p,sz); -} -#endif - -#ifdef _WIN32 -STB_EXTERN void * stb_smalloc(size_t sz); -STB_EXTERN void stb_sfree(void *p); -STB_EXTERN void * stb_srealloc(void *p, size_t sz); -STB_EXTERN void * stb_scalloc(size_t n, size_t sz); -STB_EXTERN char * stb_sstrdup(char *s); -#endif - -#ifdef STB_FASTMALLOC -#define malloc stb_smalloc -#define free stb_sfree -#define realloc stb_srealloc -#define strdup stb_sstrdup -#define calloc stb_scalloc -#endif - -#ifndef STB_MALLOC_ALLCHECK - #define stb__check(p) 1 -#else - #ifndef STB_MALLOC_WRAPPER - #error STB_MALLOC_ALLCHECK requires STB_MALLOC_WRAPPER - #else - #define stb__check(p) stb_mcheck(p) - #endif -#endif - -#ifdef STB_MALLOC_WRAPPER - STB_EXTERN void * stb__malloc(size_t, char *, int); - STB_EXTERN void * stb__realloc(void *, size_t, char *, int); - STB_EXTERN void * stb__calloc(size_t n, size_t s, char *, int); - STB_EXTERN void stb__free(void *, char *file, int); - STB_EXTERN char * stb__strdup(char *s, char *file, int); - STB_EXTERN void stb_malloc_checkall(void); - STB_EXTERN void stb_malloc_check_counter(int init_delay, int rep_delay); - #ifndef STB_MALLOC_WRAPPER_DEBUG - #define stb_mcheck(p) 1 - #else - STB_EXTERN int stb_mcheck(void *); - #endif - - - #ifdef STB_DEFINE - - #ifdef STB_MALLOC_WRAPPER_DEBUG - #define STB__PAD 32 - #define STB__BIAS 16 - #define STB__SIG 0x51b01234 - #define STB__FIXSIZE(sz) (((sz+3) & ~3) + STB__PAD) - #define STB__ptr(x,y) ((char *) (x) + (y)) - #else - #define STB__ptr(x,y) (x) - #define STB__FIXSIZE(sz) (sz) - #endif - - #ifdef STB_MALLOC_WRAPPER_DEBUG - int stb_mcheck(void *p) - { - unsigned int sz; - if (p == NULL) return 1; - p = ((char *) p) - STB__BIAS; - sz = * (unsigned int *) p; - assert(* (unsigned int *) STB__ptr(p,4) == STB__SIG); - assert(* (unsigned int *) STB__ptr(p,8) == STB__SIG); - assert(* (unsigned int *) STB__ptr(p,12) == STB__SIG); - assert(* (unsigned int *) STB__ptr(p,sz-4) == STB__SIG+1); - assert(* (unsigned int *) STB__ptr(p,sz-8) == STB__SIG+1); - assert(* (unsigned int *) STB__ptr(p,sz-12) == STB__SIG+1); - assert(* (unsigned int *) STB__ptr(p,sz-16) == STB__SIG+1); - stb_wrapper_check(STB__ptr(p, STB__BIAS)); - return 1; - } - - static void stb__check2(void *p, size_t sz, char *file, int line) - { - stb_mcheck(p); - } - - void stb_malloc_checkall(void) - { - stb_wrapper_listall(stb__check2); - } - #else - void stb_malloc_checkall(void) { } - #endif - - static int stb__malloc_wait=(1 << 30), stb__malloc_next_wait = (1 << 30), stb__malloc_iter; - void stb_malloc_check_counter(int init_delay, int rep_delay) - { - stb__malloc_wait = init_delay; - stb__malloc_next_wait = rep_delay; - } - - void stb_mcheck_all(void) - { - #ifdef STB_MALLOC_WRAPPER_DEBUG - ++stb__malloc_iter; - if (--stb__malloc_wait <= 0) { - stb_malloc_checkall(); - stb__malloc_wait = stb__malloc_next_wait; - } - #endif - } - - #ifdef STB_MALLOC_WRAPPER_PAGED - #define STB__WINDOWS_PAGE (1 << 12) - #ifndef _WINDOWS_ - STB_EXTERN __declspec(dllimport) void * __stdcall VirtualAlloc(void *p, unsigned long size, unsigned long type, unsigned long protect); - STB_EXTERN __declspec(dllimport) int __stdcall VirtualFree(void *p, unsigned long size, unsigned long freetype); - #endif - #endif - - static void *stb__malloc_final(size_t sz) - { - #ifdef STB_MALLOC_WRAPPER_PAGED - size_t aligned = (sz + STB__WINDOWS_PAGE - 1) & ~(STB__WINDOWS_PAGE-1); - char *p = VirtualAlloc(NULL, aligned + STB__WINDOWS_PAGE, 0x2000, 0x04); // RESERVE, READWRITE - if (p == NULL) return p; - VirtualAlloc(p, aligned, 0x1000, 0x04); // COMMIT, READWRITE - return p; - #else - return malloc(sz); - #endif - } - - static void stb__free_final(void *p) - { - #ifdef STB_MALLOC_WRAPPER_PAGED - VirtualFree(p, 0, 0x8000); // RELEASE - #else - free(p); - #endif - } - - int stb__malloc_failure; - #ifdef STB_MALLOC_WRAPPER_PAGED - static void *stb__realloc_final(void *p, size_t sz, size_t old_sz) - { - void *q = stb__malloc_final(sz); - if (q == NULL) - return ++stb__malloc_failure, q; - // @TODO: deal with p being smaller! - memcpy(q, p, sz < old_sz ? sz : old_sz); - stb__free_final(p); - return q; - } - #endif - - void stb__free(void *p, char *file, int line) - { - stb_mcheck_all(); - if (!p) return; - #ifdef STB_MALLOC_WRAPPER_DEBUG - stb_mcheck(p); - #endif - stb_wrapper_free(p,file,line); - #ifdef STB_MALLOC_WRAPPER_DEBUG - p = STB__ptr(p,-STB__BIAS); - * (unsigned int *) STB__ptr(p,0) = 0xdeadbeef; - * (unsigned int *) STB__ptr(p,4) = 0xdeadbeef; - * (unsigned int *) STB__ptr(p,8) = 0xdeadbeef; - * (unsigned int *) STB__ptr(p,12) = 0xdeadbeef; - #endif - stb__free_final(p); - } - - void * stb__malloc(size_t sz, char *file, int line) - { - void *p; - stb_mcheck_all(); - if (sz == 0) return NULL; - p = stb__malloc_final(STB__FIXSIZE(sz)); - if (p == NULL) p = stb__malloc_final(STB__FIXSIZE(sz)); - if (p == NULL) p = stb__malloc_final(STB__FIXSIZE(sz)); - if (p == NULL) { - ++stb__malloc_failure; - #ifdef STB_MALLOC_WRAPPER_DEBUG - stb_malloc_checkall(); - #endif - return p; - } - #ifdef STB_MALLOC_WRAPPER_DEBUG - * (int *) STB__ptr(p,0) = STB__FIXSIZE(sz); - * (unsigned int *) STB__ptr(p,4) = STB__SIG; - * (unsigned int *) STB__ptr(p,8) = STB__SIG; - * (unsigned int *) STB__ptr(p,12) = STB__SIG; - * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-4) = STB__SIG+1; - * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-8) = STB__SIG+1; - * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-12) = STB__SIG+1; - * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-16) = STB__SIG+1; - p = STB__ptr(p, STB__BIAS); - #endif - stb_wrapper_malloc(p,sz,file,line); - return p; - } - - void * stb__realloc(void *p, size_t sz, char *file, int line) - { - void *q; - - stb_mcheck_all(); - if (p == NULL) return stb__malloc(sz,file,line); - if (sz == 0 ) { stb__free(p,file,line); return NULL; } - - #ifdef STB_MALLOC_WRAPPER_DEBUG - stb_mcheck(p); - p = STB__ptr(p,-STB__BIAS); - #endif - #ifdef STB_MALLOC_WRAPPER_PAGED - { - size_t n = stb_wrapper_allocsize(STB__ptr(p,STB__BIAS)); - if (!n) - stb_wrapper_check(STB__ptr(p,STB__BIAS)); - q = stb__realloc_final(p, STB__FIXSIZE(sz), STB__FIXSIZE(n)); - } - #else - q = realloc(p, STB__FIXSIZE(sz)); - #endif - if (q == NULL) - return ++stb__malloc_failure, q; - #ifdef STB_MALLOC_WRAPPER_DEBUG - * (int *) STB__ptr(q,0) = STB__FIXSIZE(sz); - * (unsigned int *) STB__ptr(q,4) = STB__SIG; - * (unsigned int *) STB__ptr(q,8) = STB__SIG; - * (unsigned int *) STB__ptr(q,12) = STB__SIG; - * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-4) = STB__SIG+1; - * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-8) = STB__SIG+1; - * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-12) = STB__SIG+1; - * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-16) = STB__SIG+1; - - q = STB__ptr(q, STB__BIAS); - p = STB__ptr(p, STB__BIAS); - #endif - stb_wrapper_realloc(p,q,sz,file,line); - return q; - } - - STB_EXTERN int stb_log2_ceil(size_t); - static void *stb__calloc(size_t n, size_t sz, char *file, int line) - { - void *q; - stb_mcheck_all(); - if (n == 0 || sz == 0) return NULL; - if (stb_log2_ceil(n) + stb_log2_ceil(sz) >= 32) return NULL; - q = stb__malloc(n*sz, file, line); - if (q) memset(q, 0, n*sz); - return q; - } - - char * stb__strdup(char *s, char *file, int line) - { - char *p; - stb_mcheck_all(); - p = stb__malloc(strlen(s)+1, file, line); - if (!p) return p; - stb_p_strcpy_s(p, strlen(s)+1, s); - return p; - } - #endif // STB_DEFINE - - #ifdef STB_FASTMALLOC - #undef malloc - #undef realloc - #undef free - #undef strdup - #undef calloc - #endif - - // include everything that might define these, BEFORE making macros - #include - #include - #include - - #define malloc(s) stb__malloc ( s, __FILE__, __LINE__) - #define realloc(p,s) stb__realloc(p,s, __FILE__, __LINE__) - #define calloc(n,s) stb__calloc (n,s, __FILE__, __LINE__) - #define free(p) stb__free (p, __FILE__, __LINE__) - #define strdup(p) stb__strdup (p, __FILE__, __LINE__) -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Windows pretty display -// - -STB_EXTERN void stbprint(const char *fmt, ...); -STB_EXTERN char *stb_sprintf(const char *fmt, ...); -STB_EXTERN char *stb_mprintf(const char *fmt, ...); -STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...); -STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v); - -#ifdef STB_DEFINE -int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v) -{ - int res; - #ifdef _WIN32 - #ifdef __STDC_WANT_SECURE_LIB__ - res = _vsnprintf_s(s, n, _TRUNCATE, fmt, v); - #else - res = stb_p_vsnprintf(s,n,fmt,v); - #endif - #else - res = vsnprintf(s,n,fmt,v); - #endif - if (n) s[n-1] = 0; - // Unix returns length output would require, Windows returns negative when truncated. - return (res >= (int) n || res < 0) ? -1 : res; -} - -int stb_snprintf(char *s, size_t n, const char *fmt, ...) -{ - int res; - va_list v; - va_start(v,fmt); - res = stb_vsnprintf(s, n, fmt, v); - va_end(v); - return res; -} - -char *stb_sprintf(const char *fmt, ...) -{ - static char buffer[1024]; - va_list v; - va_start(v,fmt); - stb_vsnprintf(buffer,1024,fmt,v); - va_end(v); - return buffer; -} - -char *stb_mprintf(const char *fmt, ...) -{ - static char buffer[1024]; - va_list v; - va_start(v,fmt); - stb_vsnprintf(buffer,1024,fmt,v); - va_end(v); - return stb_p_strdup(buffer); -} - -#ifdef _WIN32 - -#ifndef _WINDOWS_ -STB_EXTERN __declspec(dllimport) int __stdcall WriteConsoleA(void *, const void *, unsigned int, unsigned int *, void *); -STB_EXTERN __declspec(dllimport) void * __stdcall GetStdHandle(unsigned int); -STB_EXTERN __declspec(dllimport) int __stdcall SetConsoleTextAttribute(void *, unsigned short); -#endif - -static void stb__print_one(void *handle, char *s, ptrdiff_t len) -{ - if (len) - if (0==WriteConsoleA(handle, s, (unsigned) len, NULL,NULL)) - // if it fails, maybe redirected, so output normally... - // but it's supriously reporting failure now on Win7 and later - {}//fwrite(s, 1, (unsigned) len, stdout); -} - -static void stb__print(char *s) -{ - void *handle = GetStdHandle((unsigned int) -11); // STD_OUTPUT_HANDLE - int pad=0; // number of padding characters to add - - char *t = s; - while (*s) { - int lpad; - while (*s && *s != '{') { - if (pad) { - if (*s == '\r' || *s == '\n') - pad = 0; - else if (s[0] == ' ' && s[1] == ' ') { - stb__print_one(handle, t, s-t); - t = s; - while (pad) { - stb__print_one(handle, t, 1); - --pad; - } - } - } - ++s; - } - if (!*s) break; - stb__print_one(handle, t, s-t); - if (s[1] == '{') { - ++s; - continue; - } - - if (s[1] == '#') { - t = s+3; - if (isxdigit(s[2])) - if (isdigit(s[2])) - SetConsoleTextAttribute(handle, s[2] - '0'); - else - SetConsoleTextAttribute(handle, tolower(s[2]) - 'a' + 10); - else { - SetConsoleTextAttribute(handle, 0x0f); - t=s+2; - } - } else if (s[1] == '!') { - SetConsoleTextAttribute(handle, 0x0c); - t = s+2; - } else if (s[1] == '@') { - SetConsoleTextAttribute(handle, 0x09); - t = s+2; - } else if (s[1] == '$') { - SetConsoleTextAttribute(handle, 0x0a); - t = s+2; - } else { - SetConsoleTextAttribute(handle, 0x08); // 0,7,8,15 => shades of grey - t = s+1; - } - - lpad = (int) (t-s); - s = t; - while (*s && *s != '}') ++s; - if (!*s) break; - stb__print_one(handle, t, s-t); - if (s[1] == '}') { - t = s+2; - } else { - pad += 1+lpad; - t = s+1; - } - s=t; - SetConsoleTextAttribute(handle, 0x07); - } - stb__print_one(handle, t, s-t); - SetConsoleTextAttribute(handle, 0x07); -} - -void stbprint(const char *fmt, ...) -{ - int res; - char buffer[1024]; - char *tbuf = buffer; - va_list v; - - va_start(v,fmt); - res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v); - va_end(v); - - if (res < 0) { - tbuf = (char *) malloc(16384); - va_start(v,fmt); - res = stb_vsnprintf(tbuf,16384, fmt, v); - va_end(v); - tbuf[16383] = 0; - } - - stb__print(tbuf); - - if (tbuf != buffer) - free(tbuf); -} - -#else // _WIN32 -void stbprint(const char *fmt, ...) -{ - va_list v; - va_start(v,fmt); - vprintf(fmt,v); - va_end(v); -} -#endif // _WIN32 -#endif // STB_DEFINE - - - -////////////////////////////////////////////////////////////////////////////// -// -// Windows UTF8 filename handling -// -// Windows stupidly treats 8-bit filenames as some dopey code page, -// rather than utf-8. If we want to use utf8 filenames, we have to -// convert them to WCHAR explicitly and call WCHAR versions of the -// file functions. So, ok, we do. - - -#ifdef _WIN32 - #define stb__fopen(x,y) stb_p_wfopen((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y)) - #define stb__windows(x,y) x -#else - #define stb__fopen(x,y) stb_p_fopen(x,y) - #define stb__windows(x,y) y -#endif - - -typedef unsigned short stb__wchar; - -STB_EXTERN stb__wchar * stb_from_utf8(stb__wchar *buffer, const char *str, int n); -STB_EXTERN char * stb_to_utf8 (char *buffer, const stb__wchar *str, int n); - -STB_EXTERN stb__wchar *stb__from_utf8(const char *str); -STB_EXTERN stb__wchar *stb__from_utf8_alt(const char *str); -STB_EXTERN char *stb__to_utf8(const stb__wchar *str); - - -#ifdef STB_DEFINE -stb__wchar * stb_from_utf8(stb__wchar *buffer, const char *ostr, int n) -{ - unsigned char *str = (unsigned char *) ostr; - stb_uint32 c; - int i=0; - --n; - while (*str) { - if (i >= n) - return NULL; - if (!(*str & 0x80)) - buffer[i++] = *str++; - else if ((*str & 0xe0) == 0xc0) { - if (*str < 0xc2) return NULL; - c = (*str++ & 0x1f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = c + (*str++ & 0x3f); - } else if ((*str & 0xf0) == 0xe0) { - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; - if (*str == 0xed && str[1] > 0x9f) return NULL; // str[1] < 0x80 is checked below - c = (*str++ & 0x0f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = c + (*str++ & 0x3f); - } else if ((*str & 0xf8) == 0xf0) { - if (*str > 0xf4) return NULL; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; - if (*str == 0xf4 && str[1] > 0x8f) return NULL; // str[1] < 0x80 is checked below - c = (*str++ & 0x07) << 18; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f); - // utf-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xFFFFF800) == 0xD800) return NULL; - if (c >= 0x10000) { - c -= 0x10000; - if (i + 2 > n) return NULL; - buffer[i++] = 0xD800 | (0x3ff & (c >> 10)); - buffer[i++] = 0xDC00 | (0x3ff & (c )); - } - } else - return NULL; - } - buffer[i] = 0; - return buffer; -} - -char * stb_to_utf8(char *buffer, const stb__wchar *str, int n) -{ - int i=0; - --n; - while (*str) { - if (*str < 0x80) { - if (i+1 > n) return NULL; - buffer[i++] = (char) *str++; - } else if (*str < 0x800) { - if (i+2 > n) return NULL; - buffer[i++] = 0xc0 + (*str >> 6); - buffer[i++] = 0x80 + (*str & 0x3f); - str += 1; - } else if (*str >= 0xd800 && *str < 0xdc00) { - stb_uint32 c; - if (i+4 > n) return NULL; - c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; - buffer[i++] = 0xf0 + (c >> 18); - buffer[i++] = 0x80 + ((c >> 12) & 0x3f); - buffer[i++] = 0x80 + ((c >> 6) & 0x3f); - buffer[i++] = 0x80 + ((c ) & 0x3f); - str += 2; - } else if (*str >= 0xdc00 && *str < 0xe000) { - return NULL; - } else { - if (i+3 > n) return NULL; - buffer[i++] = 0xe0 + (*str >> 12); - buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); - buffer[i++] = 0x80 + ((*str ) & 0x3f); - str += 1; - } - } - buffer[i] = 0; - return buffer; -} - -stb__wchar *stb__from_utf8(const char *str) -{ - static stb__wchar buffer[4096]; - return stb_from_utf8(buffer, str, 4096); -} - -stb__wchar *stb__from_utf8_alt(const char *str) -{ - static stb__wchar buffer[4096]; - return stb_from_utf8(buffer, str, 4096); -} - -char *stb__to_utf8(const stb__wchar *str) -{ - static char buffer[4096]; - return stb_to_utf8(buffer, str, 4096); -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Miscellany -// - -STB_EXTERN void stb_fatal(const char *fmt, ...); -STB_EXTERN void stb_(char *fmt, ...); -STB_EXTERN void stb_append_to_file(char *file, char *fmt, ...); -STB_EXTERN void stb_log(int active); -STB_EXTERN void stb_log_fileline(int active); -STB_EXTERN void stb_log_name(char *filename); - -STB_EXTERN void stb_swap(void *p, void *q, size_t sz); -STB_EXTERN void *stb_copy(void *p, size_t sz); -STB_EXTERN void stb_pointer_array_free(void *p, int len); -STB_EXTERN void **stb_array_block_alloc(int count, int blocksize); - -#define stb_arrcount(x) (sizeof(x)/sizeof((x)[0])) - - -STB_EXTERN int stb__record_fileline(const char *f, int n); - -#ifdef STB_DEFINE - -static char *stb__file; -static int stb__line; - -int stb__record_fileline(const char *f, int n) -{ - stb__file = (char*) f; - stb__line = n; - return 0; -} - -void stb_fatal(const char *s, ...) -{ - va_list a; - if (stb__file) - fprintf(stderr, "[%s:%d] ", stb__file, stb__line); - va_start(a,s); - fputs("Fatal error: ", stderr); - vfprintf(stderr, s, a); - va_end(a); - fputs("\n", stderr); - #ifdef STB_DEBUG - #ifdef _MSC_VER - #ifndef STB_PTR64 - __asm int 3; // trap to debugger! - #else - __debugbreak(); - #endif - #else - __builtin_trap(); - #endif - #endif - exit(1); -} - -static int stb__log_active=1, stb__log_fileline=1; - -void stb_log(int active) -{ - stb__log_active = active; -} - -void stb_log_fileline(int active) -{ - stb__log_fileline = active; -} - -#ifdef STB_NO_STB_STRINGS -const char *stb__log_filename = "temp.log"; -#else -const char *stb__log_filename = "stb.log"; -#endif - -void stb_log_name(char *s) -{ - stb__log_filename = s; -} - -void stb_(char *s, ...) -{ - if (stb__log_active) { - FILE *f = stb_p_fopen(stb__log_filename, "a"); - if (f) { - va_list a; - if (stb__log_fileline && stb__file) - fprintf(f, "[%s:%4d] ", stb__file, stb__line); - va_start(a,s); - vfprintf(f, s, a); - va_end(a); - fputs("\n", f); - fclose(f); - } - } -} - -void stb_append_to_file(char *filename, char *s, ...) -{ - FILE *f = stb_p_fopen(filename, "a"); - if (f) { - va_list a; - va_start(a,s); - vfprintf(f, s, a); - va_end(a); - fputs("\n", f); - fclose(f); - } -} - - -typedef struct { char d[4]; } stb__4; -typedef struct { char d[8]; } stb__8; - -// optimize the small cases, though you shouldn't be calling this for those! -void stb_swap(void *p, void *q, size_t sz) -{ - char buffer[256]; - if (p == q) return; - if (sz == 4) { - stb__4 temp = * ( stb__4 *) p; - * (stb__4 *) p = * ( stb__4 *) q; - * (stb__4 *) q = temp; - return; - } else if (sz == 8) { - stb__8 temp = * ( stb__8 *) p; - * (stb__8 *) p = * ( stb__8 *) q; - * (stb__8 *) q = temp; - return; - } - - while (sz > sizeof(buffer)) { - stb_swap(p, q, sizeof(buffer)); - p = (char *) p + sizeof(buffer); - q = (char *) q + sizeof(buffer); - sz -= sizeof(buffer); - } - - memcpy(buffer, p , sz); - memcpy(p , q , sz); - memcpy(q , buffer, sz); -} - -void *stb_copy(void *p, size_t sz) -{ - void *q = malloc(sz); - memcpy(q, p, sz); - return q; -} - -void stb_pointer_array_free(void *q, int len) -{ - void **p = (void **) q; - int i; - for (i=0; i < len; ++i) - free(p[i]); -} - -void **stb_array_block_alloc(int count, int blocksize) -{ - int i; - char *p = (char *) malloc(sizeof(void *) * count + count * blocksize); - void **q; - if (p == NULL) return NULL; - q = (void **) p; - p += sizeof(void *) * count; - for (i=0; i < count; ++i) - q[i] = p + i * blocksize; - return q; -} -#endif - -#ifdef STB_DEBUG - // tricky hack to allow recording FILE,LINE even in varargs functions - #define STB__RECORD_FILE(x) (stb__record_fileline(__FILE__, __LINE__),(x)) - #define stb_log STB__RECORD_FILE(stb_log) - #define stb_ STB__RECORD_FILE(stb_) - #ifndef STB_FATAL_CLEAN - #define stb_fatal STB__RECORD_FILE(stb_fatal) - #endif - #define STB__DEBUG(x) x -#else - #define STB__DEBUG(x) -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// stb_temp -// - -#define stb_temp(block, sz) stb__temp(block, sizeof(block), (sz)) - -STB_EXTERN void * stb__temp(void *b, int b_sz, int want_sz); -STB_EXTERN void stb_tempfree(void *block, void *ptr); - -#ifdef STB_DEFINE - -void * stb__temp(void *b, int b_sz, int want_sz) -{ - if (b_sz >= want_sz) - return b; - else - return malloc(want_sz); -} - -void stb_tempfree(void *b, void *p) -{ - if (p != b) - free(p); -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// math/sampling operations -// - - -#define stb_lerp(t,a,b) ( (a) + (t) * (float) ((b)-(a)) ) -#define stb_unlerp(t,a,b) ( ((t) - (a)) / (float) ((b) - (a)) ) - -#define stb_clamp(x,xmin,xmax) ((x) < (xmin) ? (xmin) : (x) > (xmax) ? (xmax) : (x)) - -STB_EXTERN void stb_newell_normal(float *normal, int num_vert, float **vert, int normalize); -STB_EXTERN int stb_box_face_vertex_axis_side(int face_number, int vertex_number, int axis); -STB_EXTERN void stb_linear_controller(float *curpos, float target_pos, float acc, float deacc, float dt); - -STB_EXTERN int stb_float_eq(float x, float y, float delta, int max_ulps); -STB_EXTERN int stb_is_prime(unsigned int m); -STB_EXTERN unsigned int stb_power_of_two_nearest_prime(int n); - -STB_EXTERN float stb_smoothstep(float t); -STB_EXTERN float stb_cubic_bezier_1d(float t, float p0, float p1, float p2, float p3); - -STB_EXTERN double stb_linear_remap(double x, double a, double b, - double c, double d); - -#ifdef STB_DEFINE -float stb_smoothstep(float t) -{ - return (3 - 2*t)*(t*t); -} - -float stb_cubic_bezier_1d(float t, float p0, float p1, float p2, float p3) -{ - float it = 1-t; - return it*it*it*p0 + 3*it*it*t*p1 + 3*it*t*t*p2 + t*t*t*p3; -} - -void stb_newell_normal(float *normal, int num_vert, float **vert, int normalize) -{ - int i,j; - float p; - normal[0] = normal[1] = normal[2] = 0; - for (i=num_vert-1,j=0; j < num_vert; i=j++) { - float *u = vert[i]; - float *v = vert[j]; - normal[0] += (u[1] - v[1]) * (u[2] + v[2]); - normal[1] += (u[2] - v[2]) * (u[0] + v[0]); - normal[2] += (u[0] - v[0]) * (u[1] + v[1]); - } - if (normalize) { - p = normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]; - p = (float) (1.0 / sqrt(p)); - normal[0] *= p; - normal[1] *= p; - normal[2] *= p; - } -} - -int stb_box_face_vertex_axis_side(int face_number, int vertex_number, int axis) -{ - static int box_vertices[6][4][3] = - { - { { 1,1,1 }, { 1,0,1 }, { 1,0,0 }, { 1,1,0 } }, - { { 0,0,0 }, { 0,0,1 }, { 0,1,1 }, { 0,1,0 } }, - { { 0,0,0 }, { 0,1,0 }, { 1,1,0 }, { 1,0,0 } }, - { { 0,0,0 }, { 1,0,0 }, { 1,0,1 }, { 0,0,1 } }, - { { 1,1,1 }, { 0,1,1 }, { 0,0,1 }, { 1,0,1 } }, - { { 1,1,1 }, { 1,1,0 }, { 0,1,0 }, { 0,1,1 } }, - }; - assert(face_number >= 0 && face_number < 6); - assert(vertex_number >= 0 && vertex_number < 4); - assert(axis >= 0 && axis < 3); - return box_vertices[face_number][vertex_number][axis]; -} - -void stb_linear_controller(float *curpos, float target_pos, float acc, float deacc, float dt) -{ - float sign = 1, p, cp = *curpos; - if (cp == target_pos) return; - if (target_pos < cp) { - target_pos = -target_pos; - cp = -cp; - sign = -1; - } - // first decelerate - if (cp < 0) { - p = cp + deacc * dt; - if (p > 0) { - p = 0; - dt = dt - cp / deacc; - if (dt < 0) dt = 0; - } else { - dt = 0; - } - cp = p; - } - // now accelerate - p = cp + acc*dt; - if (p > target_pos) p = target_pos; - *curpos = p * sign; - // @TODO: testing -} - -float stb_quadratic_controller(float target_pos, float curpos, float maxvel, float maxacc, float dt, float *curvel) -{ - return 0; // @TODO -} - -int stb_float_eq(float x, float y, float delta, int max_ulps) -{ - if (fabs(x-y) <= delta) return 1; - if (abs(*(int *)&x - *(int *)&y) <= max_ulps) return 1; - return 0; -} - -int stb_is_prime(unsigned int m) -{ - unsigned int i,j; - if (m < 2) return 0; - if (m == 2) return 1; - if (!(m & 1)) return 0; - if (m % 3 == 0) return (m == 3); - for (i=5; (j=i*i), j <= m && j > i; i += 6) { - if (m % i == 0) return 0; - if (m % (i+2) == 0) return 0; - } - return 1; -} - -unsigned int stb_power_of_two_nearest_prime(int n) -{ - static signed char tab[32] = { 0,0,0,0,1,0,-1,0,1,-1,-1,3,-1,0,-1,2,1, - 0,2,0,-1,-4,-1,5,-1,18,-2,15,2,-1,2,0 }; - if (!tab[0]) { - int i; - for (i=0; i < 32; ++i) - tab[i] = (1 << i) + 2*tab[i] - 1; - tab[1] = 2; - tab[0] = 1; - } - if (n >= 32) return 0xfffffffb; - return tab[n]; -} - -double stb_linear_remap(double x, double x_min, double x_max, - double out_min, double out_max) -{ - return stb_lerp(stb_unlerp(x,x_min,x_max),out_min,out_max); -} -#endif - -// create a macro so it's faster, but you can get at the function pointer -#define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d) - - -////////////////////////////////////////////////////////////////////////////// -// -// bit operations -// - -#define stb_big32(c) (((c)[0]<<24) + (c)[1]*65536 + (c)[2]*256 + (c)[3]) -#define stb_little32(c) (((c)[3]<<24) + (c)[2]*65536 + (c)[1]*256 + (c)[0]) -#define stb_big16(c) ((c)[0]*256 + (c)[1]) -#define stb_little16(c) ((c)[1]*256 + (c)[0]) - -STB_EXTERN int stb_bitcount(unsigned int a); -STB_EXTERN unsigned int stb_bitreverse8(unsigned char n); -STB_EXTERN unsigned int stb_bitreverse(unsigned int n); - -STB_EXTERN int stb_is_pow2(size_t); -STB_EXTERN int stb_log2_ceil(size_t); -STB_EXTERN int stb_log2_floor(size_t); - -STB_EXTERN int stb_lowbit8(unsigned int n); -STB_EXTERN int stb_highbit8(unsigned int n); - -#ifdef STB_DEFINE -int stb_bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -unsigned int stb_bitreverse8(unsigned char n) -{ - n = ((n & 0xAA) >> 1) + ((n & 0x55) << 1); - n = ((n & 0xCC) >> 2) + ((n & 0x33) << 2); - return (unsigned char) ((n >> 4) + (n << 4)); -} - -unsigned int stb_bitreverse(unsigned int n) -{ - n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); - n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); - n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); - n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); - return (n >> 16) | (n << 16); -} - -int stb_is_pow2(size_t n) -{ - return (n & (n-1)) == 0; -} - -// tricky use of 4-bit table to identify 5 bit positions (note the '-1') -// 3-bit table would require another tree level; 5-bit table wouldn't save one -#if defined(_WIN32) && !defined(__MINGW32__) -#pragma warning(push) -#pragma warning(disable: 4035) // disable warning about no return value -int stb_log2_floor(size_t n) -{ - #if _MSC_VER > 1700 - unsigned long i; - #ifdef STB_PTR64 - _BitScanReverse64(&i, n); - #else - _BitScanReverse(&i, n); - #endif - return i != 0 ? i : -1; - #else - __asm { - bsr eax,n - jnz done - mov eax,-1 - } - done:; - #endif -} -#pragma warning(pop) -#else -int stb_log2_floor(size_t n) -{ - static signed char log2_4[16] = { -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3 }; - -#ifdef STB_PTR64 - if (n >= ((size_t) 1u << 32)) - return stb_log2_floor(n >> 32); -#endif - - // 2 compares if n < 16, 3 compares otherwise - if (n < (1U << 14)) - if (n < (1U << 4)) return 0 + log2_4[n ]; - else if (n < (1U << 9)) return 5 + log2_4[n >> 5]; - else return 10 + log2_4[n >> 10]; - else if (n < (1U << 24)) - if (n < (1U << 19)) return 15 + log2_4[n >> 15]; - else return 20 + log2_4[n >> 20]; - else if (n < (1U << 29)) return 25 + log2_4[n >> 25]; - else return 30 + log2_4[n >> 30]; -} -#endif - -// define ceil from floor -int stb_log2_ceil(size_t n) -{ - if (stb_is_pow2(n)) return stb_log2_floor(n); - else return 1 + stb_log2_floor(n); -} - -int stb_highbit8(unsigned int n) -{ - return stb_log2_ceil(n&255); -} - -int stb_lowbit8(unsigned int n) -{ - static signed char lowbit4[16] = { -1,0,1,0, 2,0,1,0, 3,0,1,0, 2,0,1,0 }; - int k = lowbit4[n & 15]; - if (k >= 0) return k; - k = lowbit4[(n >> 4) & 15]; - if (k >= 0) return k+4; - return k; -} -#endif - - - -////////////////////////////////////////////////////////////////////////////// -// -// qsort Compare Routines -// - -#ifdef _WIN32 - #define stb_stricmp(a,b) stb_p_stricmp(a,b) - #define stb_strnicmp(a,b,n) stb_p_strnicmp(a,b,n) -#else - #define stb_stricmp(a,b) strcasecmp(a,b) - #define stb_strnicmp(a,b,n) strncasecmp(a,b,n) -#endif - - -STB_EXTERN int (*stb_intcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_intcmprev(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_qsort_strcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_qsort_stricmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_floatcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b); - -#ifdef STB_DEFINE -static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset; -static int stb__floatcmpoffset, stb__doublecmpoffset; -static int stb__memcmpoffset, stb__memcmpsize; - -int stb__intcmp(const void *a, const void *b) -{ - const int p = *(const int *) ((const char *) a + stb__intcmpoffset); - const int q = *(const int *) ((const char *) b + stb__intcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__intcmprev(const void *a, const void *b) -{ - const int p = *(const int *) ((const char *) a + stb__intcmpoffset); - const int q = *(const int *) ((const char *) b + stb__intcmpoffset); - return q < p ? -1 : q > p; -} - -int stb__ucharcmp(const void *a, const void *b) -{ - const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset); - const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__floatcmp(const void *a, const void *b) -{ - const float p = *(const float *) ((const char *) a + stb__floatcmpoffset); - const float q = *(const float *) ((const char *) b + stb__floatcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__doublecmp(const void *a, const void *b) -{ - const double p = *(const double *) ((const char *) a + stb__doublecmpoffset); - const double q = *(const double *) ((const char *) b + stb__doublecmpoffset); - return p < q ? -1 : p > q; -} - -int stb__qsort_strcmp(const void *a, const void *b) -{ - const char *p = *(const char **) ((const char *) a + stb__strcmpoffset); - const char *q = *(const char **) ((const char *) b + stb__strcmpoffset); - return strcmp(p,q); -} - -int stb__qsort_stricmp(const void *a, const void *b) -{ - const char *p = *(const char **) ((const char *) a + stb__strcmpoffset); - const char *q = *(const char **) ((const char *) b + stb__strcmpoffset); - return stb_stricmp(p,q); -} - -int stb__memcmp(const void *a, const void *b) -{ - return memcmp((char *) a + stb__memcmpoffset, (char *) b + stb__memcmpoffset, stb__memcmpsize); -} - -int (*stb_intcmp(int offset))(const void *, const void *) -{ - stb__intcmpoffset = offset; - return &stb__intcmp; -} - -int (*stb_intcmprev(int offset))(const void *, const void *) -{ - stb__intcmpoffset = offset; - return &stb__intcmprev; -} - -int (*stb_ucharcmp(int offset))(const void *, const void *) -{ - stb__ucharcmpoffset = offset; - return &stb__ucharcmp; -} - -int (*stb_qsort_strcmp(int offset))(const void *, const void *) -{ - stb__strcmpoffset = offset; - return &stb__qsort_strcmp; -} - -int (*stb_qsort_stricmp(int offset))(const void *, const void *) -{ - stb__strcmpoffset = offset; - return &stb__qsort_stricmp; -} - -int (*stb_floatcmp(int offset))(const void *, const void *) -{ - stb__floatcmpoffset = offset; - return &stb__floatcmp; -} - -int (*stb_doublecmp(int offset))(const void *, const void *) -{ - stb__doublecmpoffset = offset; - return &stb__doublecmp; -} - -int (*stb_memcmp(int offset, int size))(const void *, const void *) -{ - stb__memcmpoffset = offset; - stb__memcmpsize = size; - return &stb__memcmp; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Binary Search Toolkit -// - -typedef struct -{ - int minval, maxval, guess; - int mode, step; -} stb_search; - -STB_EXTERN int stb_search_binary(stb_search *s, int minv, int maxv, int find_smallest); -STB_EXTERN int stb_search_open(stb_search *s, int minv, int find_smallest); -STB_EXTERN int stb_probe(stb_search *s, int compare, int *result); // return 0 when done - -#ifdef STB_DEFINE -enum -{ - STB_probe_binary_smallest, - STB_probe_binary_largest, - STB_probe_open_smallest, - STB_probe_open_largest, -}; - -static int stb_probe_guess(stb_search *s, int *result) -{ - switch(s->mode) { - case STB_probe_binary_largest: - if (s->minval == s->maxval) { - *result = s->minval; - return 0; - } - assert(s->minval < s->maxval); - // if a < b, then a < p <= b - s->guess = s->minval + (((unsigned) s->maxval - s->minval + 1) >> 1); - break; - - case STB_probe_binary_smallest: - if (s->minval == s->maxval) { - *result = s->minval; - return 0; - } - assert(s->minval < s->maxval); - // if a < b, then a <= p < b - s->guess = s->minval + (((unsigned) s->maxval - s->minval) >> 1); - break; - case STB_probe_open_smallest: - case STB_probe_open_largest: - s->guess = s->maxval; // guess the current maxval - break; - } - *result = s->guess; - return 1; -} - -int stb_probe(stb_search *s, int compare, int *result) -{ - switch(s->mode) { - case STB_probe_open_smallest: - case STB_probe_open_largest: { - if (compare <= 0) { - // then it lies within minval & maxval - if (s->mode == STB_probe_open_smallest) - s->mode = STB_probe_binary_smallest; - else - s->mode = STB_probe_binary_largest; - } else { - // otherwise, we need to probe larger - s->minval = s->maxval + 1; - s->maxval = s->minval + s->step; - s->step += s->step; - } - break; - } - case STB_probe_binary_smallest: { - // if compare < 0, then s->minval <= a < p - // if compare = 0, then s->minval <= a <= p - // if compare > 0, then p < a <= s->maxval - if (compare <= 0) - s->maxval = s->guess; - else - s->minval = s->guess+1; - break; - } - case STB_probe_binary_largest: { - // if compare < 0, then s->minval <= a < p - // if compare = 0, then p <= a <= s->maxval - // if compare > 0, then p < a <= s->maxval - if (compare < 0) - s->maxval = s->guess-1; - else - s->minval = s->guess; - break; - } - } - return stb_probe_guess(s, result); -} - -int stb_search_binary(stb_search *s, int minv, int maxv, int find_smallest) -{ - int r; - if (maxv < minv) return minv-1; - s->minval = minv; - s->maxval = maxv; - s->mode = find_smallest ? STB_probe_binary_smallest : STB_probe_binary_largest; - stb_probe_guess(s, &r); - return r; -} - -int stb_search_open(stb_search *s, int minv, int find_smallest) -{ - int r; - s->step = 4; - s->minval = minv; - s->maxval = minv+s->step; - s->mode = find_smallest ? STB_probe_open_smallest : STB_probe_open_largest; - stb_probe_guess(s, &r); - return r; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// String Processing -// - -#define stb_prefixi(s,t) (0==stb_strnicmp((s),(t),strlen(t))) - -enum stb_splitpath_flag -{ - STB_PATH = 1, - STB_FILE = 2, - STB_EXT = 4, - STB_PATH_FILE = STB_PATH + STB_FILE, - STB_FILE_EXT = STB_FILE + STB_EXT, - STB_EXT_NO_PERIOD = 8, -}; - -STB_EXTERN char * stb_skipwhite(char *s); -STB_EXTERN char * stb_trimwhite(char *s); -STB_EXTERN char * stb_skipnewline(char *s); -STB_EXTERN char * stb_strncpy(char *s, char *t, int n); -STB_EXTERN char * stb_substr(char *t, int n); -STB_EXTERN char * stb_duplower(char *s); -STB_EXTERN void stb_tolower (char *s); -STB_EXTERN char * stb_strchr2 (char *s, char p1, char p2); -STB_EXTERN char * stb_strrchr2(char *s, char p1, char p2); -STB_EXTERN char * stb_strtok(char *output, char *src, char *delimit); -STB_EXTERN char * stb_strtok_keep(char *output, char *src, char *delimit); -STB_EXTERN char * stb_strtok_invert(char *output, char *src, char *allowed); -STB_EXTERN char * stb_dupreplace(char *s, char *find, char *replace); -STB_EXTERN void stb_replaceinplace(char *s, char *find, char *replace); -STB_EXTERN char * stb_splitpath(char *output, char *src, int flag); -STB_EXTERN char * stb_splitpathdup(char *src, int flag); -STB_EXTERN char * stb_replacedir(char *output, char *src, char *dir); -STB_EXTERN char * stb_replaceext(char *output, char *src, char *ext); -STB_EXTERN void stb_fixpath(char *path); -STB_EXTERN char * stb_shorten_path_readable(char *path, int max_len); -STB_EXTERN int stb_suffix (char *s, char *t); -STB_EXTERN int stb_suffixi(char *s, char *t); -STB_EXTERN int stb_prefix (char *s, char *t); -STB_EXTERN char * stb_strichr(char *s, char t); -STB_EXTERN char * stb_stristr(char *s, char *t); -STB_EXTERN int stb_prefix_count(char *s, char *t); -STB_EXTERN const char * stb_plural(int n); // "s" or "" -STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); - -STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out); -STB_EXTERN char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out); -STB_EXTERN char **stb_tokens_allowempty(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_stripwhite(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_withdelim(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count); -// with 'quoted', allow delimiters to appear inside quotation marks, and don't -// strip whitespace inside them (and we delete the quotation marks unless they -// appear back to back, in which case they're considered escaped) - -#ifdef STB_DEFINE - -size_t stb_strscpy(char *d, const char *s, size_t n) -{ - size_t len = strlen(s); - if (len >= n) { - if (n) d[0] = 0; - return 0; - } - stb_p_strcpy_s(d,n,s); - return len; -} - -const char *stb_plural(int n) -{ - return n == 1 ? "" : "s"; -} - -int stb_prefix(char *s, char *t) -{ - while (*t) - if (*s++ != *t++) - return STB_FALSE; - return STB_TRUE; -} - -int stb_prefix_count(char *s, char *t) -{ - int c=0; - while (*t) { - if (*s++ != *t++) - break; - ++c; - } - return c; -} - -int stb_suffix(char *s, char *t) -{ - size_t n = strlen(s); - size_t m = strlen(t); - if (m <= n) - return 0 == strcmp(s+n-m, t); - else - return 0; -} - -int stb_suffixi(char *s, char *t) -{ - size_t n = strlen(s); - size_t m = strlen(t); - if (m <= n) - return 0 == stb_stricmp(s+n-m, t); - else - return 0; -} - -// originally I was using this table so that I could create known sentinel -// values--e.g. change whitetable[0] to be true if I was scanning for whitespace, -// and false if I was scanning for nonwhite. I don't appear to be using that -// functionality anymore (I do for tokentable, though), so just replace it -// with isspace() -char *stb_skipwhite(char *s) -{ - while (isspace((unsigned char) *s)) ++s; - return s; -} - -char *stb_skipnewline(char *s) -{ - if (s[0] == '\r' || s[0] == '\n') { - if (s[0]+s[1] == '\r' + '\n') ++s; - ++s; - } - return s; -} - -char *stb_trimwhite(char *s) -{ - int i,n; - s = stb_skipwhite(s); - n = (int) strlen(s); - for (i=n-1; i >= 0; --i) - if (!isspace(s[i])) - break; - s[i+1] = 0; - return s; -} - -char *stb_strncpy(char *s, char *t, int n) -{ - stb_p_strncpy_s(s,n+1,t,n); - s[n] = 0; - return s; -} - -char *stb_substr(char *t, int n) -{ - char *a; - int z = (int) strlen(t); - if (z < n) n = z; - a = (char *) malloc(n+1); - stb_p_strncpy_s(a,n+1,t,n); - a[n] = 0; - return a; -} - -char *stb_duplower(char *s) -{ - char *p = stb_p_strdup(s), *q = p; - while (*q) { - *q = tolower(*q); - ++q; - } - return p; -} - -void stb_tolower(char *s) -{ - while (*s) { - *s = tolower(*s); - ++s; - } -} - -char *stb_strchr2(char *s, char x, char y) -{ - for(; *s; ++s) - if (*s == x || *s == y) - return s; - return NULL; -} - -char *stb_strrchr2(char *s, char x, char y) -{ - char *r = NULL; - for(; *s; ++s) - if (*s == x || *s == y) - r = s; - return r; -} - -char *stb_strichr(char *s, char t) -{ - if (tolower(t) == toupper(t)) - return strchr(s,t); - return stb_strchr2(s, (char) tolower(t), (char) toupper(t)); -} - -char *stb_stristr(char *s, char *t) -{ - size_t n = strlen(t); - char *z; - if (n==0) return s; - while ((z = stb_strichr(s, *t)) != NULL) { - if (0==stb_strnicmp(z, t, n)) - return z; - s = z+1; - } - return NULL; -} - -static char *stb_strtok_raw(char *output, char *src, char *delimit, int keep, int invert) -{ - if (invert) { - while (*src && strchr(delimit, *src) != NULL) { - *output++ = *src++; - } - } else { - while (*src && strchr(delimit, *src) == NULL) { - *output++ = *src++; - } - } - *output = 0; - if (keep) - return src; - else - return *src ? src+1 : src; -} - -char *stb_strtok(char *output, char *src, char *delimit) -{ - return stb_strtok_raw(output, src, delimit, 0, 0); -} - -char *stb_strtok_keep(char *output, char *src, char *delimit) -{ - return stb_strtok_raw(output, src, delimit, 1, 0); -} - -char *stb_strtok_invert(char *output, char *src, char *delimit) -{ - return stb_strtok_raw(output, src, delimit, 1,1); -} - -static char **stb_tokens_raw(char *src_, char *delimit, int *count, - int stripwhite, int allow_empty, char *start, char *end) -{ - int nested = 0; - unsigned char *src = (unsigned char *) src_; - static char stb_tokentable[256]; // rely on static initializion to 0 - static char stable[256],etable[256]; - char *out; - char **result; - int num=0; - unsigned char *s; - - s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 1; - if (start) { - s = (unsigned char *) start; while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1; - } - stable[0] = 1; - - // two passes through: the first time, counting how many - s = (unsigned char *) src; - while (*s) { - // state: just found delimiter - // skip further delimiters - if (!allow_empty) { - stb_tokentable[0] = 0; - while (stb_tokentable[*s]) - ++s; - if (!*s) break; - } - ++num; - // skip further non-delimiters - stb_tokentable[0] = 1; - if (stripwhite == 2) { // quoted strings - while (!stb_tokentable[*s]) { - if (*s != '"') - ++s; - else { - ++s; - if (*s == '"') - ++s; // "" -> ", not start a string - else { - // begin a string - while (*s) { - if (s[0] == '"') { - if (s[1] == '"') s += 2; // "" -> " - else { ++s; break; } // terminating " - } else - ++s; - } - } - } - } - } else - while (nested || !stb_tokentable[*s]) { - if (stable[*s]) { - if (!*s) break; - if (end ? etable[*s] : nested) - --nested; - else - ++nested; - } - ++s; - } - if (allow_empty) { - if (*s) ++s; - } - } - // now num has the actual count... malloc our output structure - // need space for all the strings: strings won't be any longer than - // original input, since for every '\0' there's at least one delimiter - result = (char **) malloc(sizeof(*result) * (num+1) + (s-src+1)); - if (result == NULL) return result; - out = (char *) (result + (num+1)); - // second pass: copy out the data - s = (unsigned char *) src; - num = 0; - nested = 0; - while (*s) { - char *last_nonwhite; - // state: just found delimiter - // skip further delimiters - if (!allow_empty) { - stb_tokentable[0] = 0; - if (stripwhite) - while (stb_tokentable[*s] || isspace(*s)) - ++s; - else - while (stb_tokentable[*s]) - ++s; - } else if (stripwhite) { - while (isspace(*s)) ++s; - } - if (!*s) break; - // we're past any leading delimiters and whitespace - result[num] = out; - ++num; - // copy non-delimiters - stb_tokentable[0] = 1; - last_nonwhite = out-1; - if (stripwhite == 2) { - while (!stb_tokentable[*s]) { - if (*s != '"') { - if (!isspace(*s)) last_nonwhite = out; - *out++ = *s++; - } else { - ++s; - if (*s == '"') { - if (!isspace(*s)) last_nonwhite = out; - *out++ = *s++; // "" -> ", not start string - } else { - // begin a quoted string - while (*s) { - if (s[0] == '"') { - if (s[1] == '"') { *out++ = *s; s += 2; } - else { ++s; break; } // terminating " - } else - *out++ = *s++; - } - last_nonwhite = out-1; // all in quotes counts as non-white - } - } - } - } else { - while (nested || !stb_tokentable[*s]) { - if (!isspace(*s)) last_nonwhite = out; - if (stable[*s]) { - if (!*s) break; - if (end ? etable[*s] : nested) - --nested; - else - ++nested; - } - *out++ = *s++; - } - } - - if (stripwhite) // rewind to last non-whitespace char - out = last_nonwhite+1; - *out++ = '\0'; - - if (*s) ++s; // skip delimiter - } - s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 0; - if (start) { - s = (unsigned char *) start; while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1; - } - if (count != NULL) *count = num; - result[num] = 0; - return result; -} - -char **stb_tokens(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,0,0,0,0); -} - -char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out) -{ - return stb_tokens_raw(src,delimit,count,0,0,nest_in,nest_out); -} - -char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out) -{ - return stb_tokens_raw(src,delimit,count,0,1,nest_in,nest_out); -} - -char **stb_tokens_allowempty(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,0,1,0,0); -} - -char **stb_tokens_stripwhite(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,1,1,0,0); -} - -char **stb_tokens_quoted(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,2,1,0,0); -} - -char *stb_dupreplace(char *src, char *find, char *replace) -{ - size_t len_find = strlen(find); - size_t len_replace = strlen(replace); - int count = 0; - - char *s,*p,*q; - - s = strstr(src, find); - if (s == NULL) return stb_p_strdup(src); - do { - ++count; - s = strstr(s + len_find, find); - } while (s != NULL); - - p = (char *) malloc(strlen(src) + count * (len_replace - len_find) + 1); - if (p == NULL) return p; - q = p; - s = src; - for (;;) { - char *t = strstr(s, find); - if (t == NULL) { - stb_p_strcpy_s(q,strlen(src)+count*(len_replace-len_find)+1,s); - assert(strlen(p) == strlen(src) + count*(len_replace-len_find)); - return p; - } - memcpy(q, s, t-s); - q += t-s; - memcpy(q, replace, len_replace); - q += len_replace; - s = t + len_find; - } -} - -void stb_replaceinplace(char *src, char *find, char *replace) -{ - size_t len_find = strlen(find); - size_t len_replace = strlen(replace); - int delta; - - char *s,*p,*q; - - delta = (int) (len_replace - len_find); - assert(delta <= 0); - if (delta > 0) return; - - p = strstr(src, find); - if (p == NULL) return; - - s = q = p; - while (*s) { - memcpy(q, replace, len_replace); - p += len_find; - q += len_replace; - s = strstr(p, find); - if (s == NULL) s = p + strlen(p); - memmove(q, p, s-p); - q += s-p; - p = s; - } - *q = 0; -} - -void stb_fixpath(char *path) -{ - for(; *path; ++path) - if (*path == '\\') - *path = '/'; -} - -void stb__add_section(char *buffer, char *data, ptrdiff_t curlen, ptrdiff_t newlen) -{ - if (newlen < curlen) { - ptrdiff_t z1 = newlen >> 1, z2 = newlen-z1; - memcpy(buffer, data, z1-1); - buffer[z1-1] = '.'; - buffer[z1-0] = '.'; - memcpy(buffer+z1+1, data+curlen-z2+1, z2-1); - } else - memcpy(buffer, data, curlen); -} - -char * stb_shorten_path_readable(char *path, int len) -{ - static char buffer[1024]; - ptrdiff_t n = strlen(path),n1,n2,r1,r2; - char *s; - if (n <= len) return path; - if (len > 1024) return path; - s = stb_strrchr2(path, '/', '\\'); - if (s) { - n1 = s - path + 1; - n2 = n - n1; - ++s; - } else { - n1 = 0; - n2 = n; - s = path; - } - // now we need to reduce r1 and r2 so that they fit in len - if (n1 < len>>1) { - r1 = n1; - r2 = len - r1; - } else if (n2 < len >> 1) { - r2 = n2; - r1 = len - r2; - } else { - r1 = n1 * len / n; - r2 = n2 * len / n; - if (r1 < len>>2) r1 = len>>2, r2 = len-r1; - if (r2 < len>>2) r2 = len>>2, r1 = len-r2; - } - assert(r1 <= n1 && r2 <= n2); - if (n1) - stb__add_section(buffer, path, n1, r1); - stb__add_section(buffer+r1, s, n2, r2); - buffer[len] = 0; - return buffer; -} - -static char *stb__splitpath_raw(char *buffer, char *path, int flag) -{ - ptrdiff_t len=0,x,y, n = (int) strlen(path), f1,f2; - char *s = stb_strrchr2(path, '/', '\\'); - char *t = strrchr(path, '.'); - if (s && t && t < s) t = NULL; - - if (!s) { - // check for drive - if (isalpha(path[0]) && path[1] == ':') - s = &path[1]; - } - if (s) ++s; - - if (flag == STB_EXT_NO_PERIOD) - flag |= STB_EXT; - - if (!(flag & (STB_PATH | STB_FILE | STB_EXT))) return NULL; - - f1 = s == NULL ? 0 : s-path; // start of filename - f2 = t == NULL ? n : t-path; // just past end of filename - - if (flag & STB_PATH) { - x = 0; if (f1 == 0 && flag == STB_PATH) len=2; - } else if (flag & STB_FILE) { - x = f1; - } else { - x = f2; - if (flag & STB_EXT_NO_PERIOD) - if (path[x] == '.') - ++x; - } - - if (flag & STB_EXT) - y = n; - else if (flag & STB_FILE) - y = f2; - else - y = f1; - - if (buffer == NULL) { - buffer = (char *) malloc(y-x + len + 1); - if (!buffer) return NULL; - } - - if (len) { stb_p_strcpy_s(buffer, 3, "./"); return buffer; } - stb_strncpy(buffer, path+(int)x, (int)(y-x)); - return buffer; -} - -char *stb_splitpath(char *output, char *src, int flag) -{ - return stb__splitpath_raw(output, src, flag); -} - -char *stb_splitpathdup(char *src, int flag) -{ - return stb__splitpath_raw(NULL, src, flag); -} - -char *stb_replacedir(char *output, char *src, char *dir) -{ - char buffer[4096]; - stb_splitpath(buffer, src, STB_FILE | STB_EXT); - if (dir) - stb_p_sprintf(output stb_p_size(9999), "%s/%s", dir, buffer); - else - stb_p_strcpy_s(output, sizeof(buffer), buffer); // @UNSAFE - return output; -} - -char *stb_replaceext(char *output, char *src, char *ext) -{ - char buffer[4096]; - stb_splitpath(buffer, src, STB_PATH | STB_FILE); - if (ext) - stb_p_sprintf(output stb_p_size(9999), "%s.%s", buffer, ext[0] == '.' ? ext+1 : ext); - else - stb_p_strcpy_s(output, sizeof(buffer), buffer); // @UNSAFE - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// stb_alloc - hierarchical allocator -// -// inspired by http://swapped.cc/halloc -// -// -// When you alloc a given block through stb_alloc, you have these choices: -// -// 1. does it have a parent? -// 2. can it have children? -// 3. can it be freed directly? -// 4. is it transferrable? -// 5. what is its alignment? -// -// Here are interesting combinations of those: -// -// children free transfer alignment -// arena Y Y N n/a -// no-overhead, chunked N N N normal -// string pool alloc N N N 1 -// parent-ptr, chunked Y N N normal -// low-overhead, unchunked N Y Y normal -// general purpose alloc Y Y Y normal -// -// Unchunked allocations will probably return 16-aligned pointers. If -// we 16-align the results, we have room for 4 pointers. For smaller -// allocations that allow finer alignment, we can reduce the pointers. -// -// The strategy is that given a pointer, assuming it has a header (only -// the no-overhead allocations have no header), we can determine the -// type of the header fields, and the number of them, by stepping backwards -// through memory and looking at the tags in the bottom bits. -// -// Implementation strategy: -// chunked allocations come from the middle of chunks, and can't -// be freed. thefore they do not need to be on a sibling chain. -// they may need child pointers if they have children. -// -// chunked, with-children -// void *parent; -// -// unchunked, no-children -- reduced storage -// void *next_sibling; -// void *prev_sibling_nextp; -// -// unchunked, general -// void *first_child; -// void *next_sibling; -// void *prev_sibling_nextp; -// void *chunks; -// -// so, if we code each of these fields with different bit patterns -// (actually same one for next/prev/child), then we can identify which -// each one is from the last field. - -STB_EXTERN void stb_free(void *p); -STB_EXTERN void *stb_malloc_global(size_t size); -STB_EXTERN void *stb_malloc(void *context, size_t size); -STB_EXTERN void *stb_malloc_nofree(void *context, size_t size); -STB_EXTERN void *stb_malloc_leaf(void *context, size_t size); -STB_EXTERN void *stb_malloc_raw(void *context, size_t size); -STB_EXTERN void *stb_realloc(void *ptr, size_t newsize); - -STB_EXTERN void stb_reassign(void *new_context, void *ptr); -STB_EXTERN void stb_malloc_validate(void *p, void *parent); - -extern int stb_alloc_chunk_size ; -extern int stb_alloc_count_free ; -extern int stb_alloc_count_alloc; -extern int stb_alloc_alignment ; - -#ifdef STB_DEFINE - -int stb_alloc_chunk_size = 65536; -int stb_alloc_count_free = 0; -int stb_alloc_count_alloc = 0; -int stb_alloc_alignment = -16; - -typedef struct stb__chunk -{ - struct stb__chunk *next; - int data_left; - int alloc; -} stb__chunk; - -typedef struct -{ - void * next; - void ** prevn; -} stb__nochildren; - -typedef struct -{ - void ** prevn; - void * child; - void * next; - stb__chunk *chunks; -} stb__alloc; - -typedef struct -{ - stb__alloc *parent; -} stb__chunked; - -#define STB__PARENT 1 -#define STB__CHUNKS 2 - -typedef enum -{ - STB__nochildren = 0, - STB__chunked = STB__PARENT, - STB__alloc = STB__CHUNKS, - - STB__chunk_raw = 4, -} stb__alloc_type; - -// these functions set the bottom bits of a pointer efficiently -#define STB__DECODE(x,v) ((void *) ((char *) (x) - (v))) -#define STB__ENCODE(x,v) ((void *) ((char *) (x) + (v))) - -#define stb__parent(z) (stb__alloc *) STB__DECODE((z)->parent, STB__PARENT) -#define stb__chunks(z) (stb__chunk *) STB__DECODE((z)->chunks, STB__CHUNKS) - -#define stb__setparent(z,p) (z)->parent = (stb__alloc *) STB__ENCODE((p), STB__PARENT) -#define stb__setchunks(z,c) (z)->chunks = (stb__chunk *) STB__ENCODE((c), STB__CHUNKS) - -static stb__alloc stb__alloc_global = -{ - NULL, - NULL, - NULL, - (stb__chunk *) STB__ENCODE(NULL, STB__CHUNKS) -}; - -static stb__alloc_type stb__identify(void *p) -{ - void **q = (void **) p; - return (stb__alloc_type) ((stb_uinta) q[-1] & 3); -} - -static void *** stb__prevn(void *p) -{ - if (stb__identify(p) == STB__alloc) { - stb__alloc *s = (stb__alloc *) p - 1; - return &s->prevn; - } else { - stb__nochildren *s = (stb__nochildren *) p - 1; - return &s->prevn; - } -} - -void stb_free(void *p) -{ - if (p == NULL) return; - - // count frees so that unit tests can see what's happening - ++stb_alloc_count_free; - - switch(stb__identify(p)) { - case STB__chunked: - // freeing a chunked-block with children does nothing; - // they only get freed when the parent does - // surely this is wrong, and it should free them immediately? - // otherwise how are they getting put on the right chain? - return; - case STB__nochildren: { - stb__nochildren *s = (stb__nochildren *) p - 1; - // unlink from sibling chain - *(s->prevn) = s->next; - if (s->next) - *stb__prevn(s->next) = s->prevn; - free(s); - return; - } - case STB__alloc: { - stb__alloc *s = (stb__alloc *) p - 1; - stb__chunk *c, *n; - void *q; - - // unlink from sibling chain, if any - *(s->prevn) = s->next; - if (s->next) - *stb__prevn(s->next) = s->prevn; - - // first free chunks - c = (stb__chunk *) stb__chunks(s); - while (c != NULL) { - n = c->next; - stb_alloc_count_free += c->alloc; - free(c); - c = n; - } - - // validating - stb__setchunks(s,NULL); - s->prevn = NULL; - s->next = NULL; - - // now free children - while ((q = s->child) != NULL) { - stb_free(q); - } - - // now free self - free(s); - return; - } - default: - assert(0); /* NOTREACHED */ - } -} - -void stb_malloc_validate(void *p, void *parent) -{ - if (p == NULL) return; - - switch(stb__identify(p)) { - case STB__chunked: - return; - case STB__nochildren: { - stb__nochildren *n = (stb__nochildren *) p - 1; - if (n->prevn) - assert(*n->prevn == p); - if (n->next) { - assert(*stb__prevn(n->next) == &n->next); - stb_malloc_validate(n, parent); - } - return; - } - case STB__alloc: { - stb__alloc *s = (stb__alloc *) p - 1; - - if (s->prevn) - assert(*s->prevn == p); - - if (s->child) { - assert(*stb__prevn(s->child) == &s->child); - stb_malloc_validate(s->child, p); - } - - if (s->next) { - assert(*stb__prevn(s->next) == &s->next); - stb_malloc_validate(s->next, parent); - } - return; - } - default: - assert(0); /* NOTREACHED */ - } -} - -static void * stb__try_chunk(stb__chunk *c, int size, int align, int pre_align) -{ - char *memblock = (char *) (c+1), *q; - stb_inta iq; - int start_offset; - - // we going to allocate at the end of the chunk, not the start. confusing, - // but it means we don't need both a 'limit' and a 'cur', just a 'cur'. - // the block ends at: p + c->data_left - // then we move back by size - start_offset = c->data_left - size; - - // now we need to check the alignment of that - q = memblock + start_offset; - iq = (stb_inta) q; - assert(sizeof(q) == sizeof(iq)); - - // suppose align = 2 - // then we need to retreat iq far enough that (iq & (2-1)) == 0 - // to get (iq & (align-1)) = 0 requires subtracting (iq & (align-1)) - - start_offset -= iq & (align-1); - assert(((stb_uinta) (memblock+start_offset) & (align-1)) == 0); - - // now, if that + pre_align works, go for it! - start_offset -= pre_align; - - if (start_offset >= 0) { - c->data_left = start_offset; - return memblock + start_offset; - } - - return NULL; -} - -static void stb__sort_chunks(stb__alloc *src) -{ - // of the first two chunks, put the chunk with more data left in it first - stb__chunk *c = stb__chunks(src), *d; - if (c == NULL) return; - d = c->next; - if (d == NULL) return; - if (c->data_left > d->data_left) return; - - c->next = d->next; - d->next = c; - stb__setchunks(src, d); -} - -static void * stb__alloc_chunk(stb__alloc *src, int size, int align, int pre_align) -{ - void *p; - stb__chunk *c = stb__chunks(src); - - if (c && size <= stb_alloc_chunk_size) { - - p = stb__try_chunk(c, size, align, pre_align); - if (p) { ++c->alloc; return p; } - - // try a second chunk to reduce wastage - if (c->next) { - p = stb__try_chunk(c->next, size, align, pre_align); - if (p) { ++c->alloc; return p; } - - // put the bigger chunk first, since the second will get buried - // the upshot of this is that, until it gets allocated from, chunk #2 - // is always the largest remaining chunk. (could formalize - // this with a heap!) - stb__sort_chunks(src); - c = stb__chunks(src); - } - } - - // allocate a new chunk - { - stb__chunk *n; - - int chunk_size = stb_alloc_chunk_size; - // we're going to allocate a new chunk to put this in - if (size > chunk_size) - chunk_size = size; - - assert(sizeof(*n) + pre_align <= 16); - - // loop trying to allocate a large enough chunk - // the loop is because the alignment may cause problems if it's big... - // and we don't know what our chunk alignment is going to be - while (1) { - n = (stb__chunk *) malloc(16 + chunk_size); - if (n == NULL) return NULL; - - n->data_left = chunk_size - sizeof(*n); - - p = stb__try_chunk(n, size, align, pre_align); - if (p != NULL) { - n->next = c; - stb__setchunks(src, n); - - // if we just used up the whole block immediately, - // move the following chunk up - n->alloc = 1; - if (size == chunk_size) - stb__sort_chunks(src); - - return p; - } - - free(n); - chunk_size += 16+align; - } - } -} - -static stb__alloc * stb__get_context(void *context) -{ - if (context == NULL) { - return &stb__alloc_global; - } else { - int u = stb__identify(context); - // if context is chunked, grab parent - if (u == STB__chunked) { - stb__chunked *s = (stb__chunked *) context - 1; - return stb__parent(s); - } else { - return (stb__alloc *) context - 1; - } - } -} - -static void stb__insert_alloc(stb__alloc *src, stb__alloc *s) -{ - s->prevn = &src->child; - s->next = src->child; - src->child = s+1; - if (s->next) - *stb__prevn(s->next) = &s->next; -} - -static void stb__insert_nochild(stb__alloc *src, stb__nochildren *s) -{ - s->prevn = &src->child; - s->next = src->child; - src->child = s+1; - if (s->next) - *stb__prevn(s->next) = &s->next; -} - -static void * malloc_base(void *context, size_t size, stb__alloc_type t, int align) -{ - void *p; - - stb__alloc *src = stb__get_context(context); - - if (align <= 0) { - // compute worst-case C packed alignment - // e.g. a 24-byte struct is 8-aligned - int align_proposed = 1 << stb_lowbit8((unsigned int) size); - - if (align_proposed < 0) - align_proposed = 4; - - if (align_proposed == 0) { - if (size == 0) - align_proposed = 1; - else - align_proposed = 256; - } - - // a negative alignment means 'don't align any larger - // than this'; so -16 means we align 1,2,4,8, or 16 - - if (align < 0) { - if (align_proposed > -align) - align_proposed = -align; - } - - align = align_proposed; - } - - assert(stb_is_pow2(align)); - - // don't cause misalignment when allocating nochildren - if (t == STB__nochildren && align > 8) - t = STB__alloc; - - switch (t) { - case STB__alloc: { - stb__alloc *s = (stb__alloc *) malloc(size + sizeof(*s)); - if (s == NULL) return NULL; - p = s+1; - s->child = NULL; - stb__insert_alloc(src, s); - - stb__setchunks(s,NULL); - break; - } - - case STB__nochildren: { - stb__nochildren *s = (stb__nochildren *) malloc(size + sizeof(*s)); - if (s == NULL) return NULL; - p = s+1; - stb__insert_nochild(src, s); - break; - } - - case STB__chunk_raw: { - p = stb__alloc_chunk(src, (int) size, align, 0); - if (p == NULL) return NULL; - break; - } - - case STB__chunked: { - stb__chunked *s; - if (align < sizeof(stb_uintptr)) align = sizeof(stb_uintptr); - s = (stb__chunked *) stb__alloc_chunk(src, (int) size, align, sizeof(*s)); - if (s == NULL) return NULL; - stb__setparent(s, src); - p = s+1; - break; - } - - default: p = NULL; assert(0); /* NOTREACHED */ - } - - ++stb_alloc_count_alloc; - return p; -} - -void *stb_malloc_global(size_t size) -{ - return malloc_base(NULL, size, STB__alloc, stb_alloc_alignment); -} - -void *stb_malloc(void *context, size_t size) -{ - return malloc_base(context, size, STB__alloc, stb_alloc_alignment); -} - -void *stb_malloc_nofree(void *context, size_t size) -{ - return malloc_base(context, size, STB__chunked, stb_alloc_alignment); -} - -void *stb_malloc_leaf(void *context, size_t size) -{ - return malloc_base(context, size, STB__nochildren, stb_alloc_alignment); -} - -void *stb_malloc_raw(void *context, size_t size) -{ - return malloc_base(context, size, STB__chunk_raw, stb_alloc_alignment); -} - -char *stb_malloc_string(void *context, size_t size) -{ - return (char *) malloc_base(context, size, STB__chunk_raw, 1); -} - -void *stb_realloc(void *ptr, size_t newsize) -{ - stb__alloc_type t; - - if (ptr == NULL) return stb_malloc(NULL, newsize); - if (newsize == 0) { stb_free(ptr); return NULL; } - - t = stb__identify(ptr); - assert(t == STB__alloc || t == STB__nochildren); - - if (t == STB__alloc) { - stb__alloc *s = (stb__alloc *) ptr - 1; - - s = (stb__alloc *) realloc(s, newsize + sizeof(*s)); - if (s == NULL) return NULL; - - ptr = s+1; - - // update pointers - (*s->prevn) = ptr; - if (s->next) - *stb__prevn(s->next) = &s->next; - - if (s->child) - *stb__prevn(s->child) = &s->child; - - return ptr; - } else { - stb__nochildren *s = (stb__nochildren *) ptr - 1; - - s = (stb__nochildren *) realloc(ptr, newsize + sizeof(s)); - if (s == NULL) return NULL; - - // update pointers - (*s->prevn) = s+1; - if (s->next) - *stb__prevn(s->next) = &s->next; - - return s+1; - } -} - -void *stb_realloc_c(void *context, void *ptr, size_t newsize) -{ - if (ptr == NULL) return stb_malloc(context, newsize); - if (newsize == 0) { stb_free(ptr); return NULL; } - // @TODO: verify you haven't changed contexts - return stb_realloc(ptr, newsize); -} - -void stb_reassign(void *new_context, void *ptr) -{ - stb__alloc *src = stb__get_context(new_context); - - stb__alloc_type t = stb__identify(ptr); - assert(t == STB__alloc || t == STB__nochildren); - - if (t == STB__alloc) { - stb__alloc *s = (stb__alloc *) ptr - 1; - - // unlink from old - *(s->prevn) = s->next; - if (s->next) - *stb__prevn(s->next) = s->prevn; - - stb__insert_alloc(src, s); - } else { - stb__nochildren *s = (stb__nochildren *) ptr - 1; - - // unlink from old - *(s->prevn) = s->next; - if (s->next) - *stb__prevn(s->next) = s->prevn; - - stb__insert_nochild(src, s); - } -} - -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_arr -// -// An stb_arr is directly useable as a pointer (use the actual type in your -// definition), but when it resizes, it returns a new pointer and you can't -// use the old one, so you have to be careful to copy-in-out as necessary. -// -// Use a NULL pointer as a 0-length array. -// -// float *my_array = NULL, *temp; -// -// // add elements on the end one at a time -// stb_arr_push(my_array, 0.0f); -// stb_arr_push(my_array, 1.0f); -// stb_arr_push(my_array, 2.0f); -// -// assert(my_array[1] == 2.0f); -// -// // add an uninitialized element at the end, then assign it -// *stb_arr_add(my_array) = 3.0f; -// -// // add three uninitialized elements at the end -// temp = stb_arr_addn(my_array,3); -// temp[0] = 4.0f; -// temp[1] = 5.0f; -// temp[2] = 6.0f; -// -// assert(my_array[5] == 5.0f); -// -// // remove the last one -// stb_arr_pop(my_array); -// -// assert(stb_arr_len(my_array) == 6); - - -#ifdef STB_MALLOC_WRAPPER - #define STB__PARAMS , char *file, int line - #define STB__ARGS , file, line -#else - #define STB__PARAMS - #define STB__ARGS -#endif - -// calling this function allocates an empty stb_arr attached to p -// (whereas NULL isn't attached to anything) -STB_EXTERN void stb_arr_malloc(void **target, void *context); - -// call this function with a non-NULL value to have all successive -// stbs that are created be attached to the associated parent. Note -// that once a given stb_arr is non-empty, it stays attached to its -// current parent, even if you call this function again. -// it turns the previous value, so you can restore it -STB_EXTERN void* stb_arr_malloc_parent(void *p); - -// simple functions written on top of other functions -#define stb_arr_empty(a) ( stb_arr_len(a) == 0 ) -#define stb_arr_add(a) ( stb_arr_addn((a),1) ) -#define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) ) - -typedef struct -{ - int len, limit; - int stb_malloc; - unsigned int signature; -} stb__arr; - -#define stb_arr_signature 0x51bada7b // ends with 0123 in decimal - -// access the header block stored before the data -#define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1) -#define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1) - -#ifdef STB_DEBUG -#define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature) -#define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature) -#else -#define stb_arr_check(a) ((void) 0) -#define stb_arr_check2(a) ((void) 0) -#endif - -// ARRAY LENGTH - -// get the array length; special case if pointer is NULL -#define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0) -#define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0) -#define stb_arr_lastn(a) (stb_arr_len(a)-1) - -// check whether a given index is valid -- tests 0 <= i < stb_arr_len(a) -#define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0) - -// change the array length so is is exactly N entries long, creating -// uninitialized entries as needed -#define stb_arr_setlen(a,n) \ - (stb__arr_setlen((void **) &(a), sizeof(a[0]), (n))) - -// change the array length so that N is a valid index (that is, so -// it is at least N entries long), creating uninitialized entries as needed -#define stb_arr_makevalid(a,n) \ - (stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a)) - -// remove the last element of the array, returning it -#define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len]) - -// access the last element in the array -#define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1]) - -// is iterator at end of list? -#define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)]) - -// (internal) change the allocated length of the array -#define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n)) - -// add N new uninitialized elements to the end of the array -#define stb_arr__addn(a,n) /*lint --e(826)*/ \ - ((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \ - ? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \ - : ((stb_arr__grow(a,n), 0))) - -// add N new uninitialized elements to the end of the array, and return -// a pointer to the first new one -#define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n)) - -// add N new uninitialized elements starting at index 'i' -#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), (i), (n))) - -// insert an element at i -#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), (i), (1)), ((a)[i] = v)) - -// delete N elements from the middle starting at index 'i' -#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), (i), (n))) - -// delete the i'th element -#define stb_arr_delete(a,i) stb_arr_deleten(a,i,1) - -// delete the i'th element, swapping down from the end -#define stb_arr_fastdelete(a,i) \ - (stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a)) - - -// ARRAY STORAGE - -// get the array maximum storage; special case if NULL -#define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0) -#define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0) - -// set the maxlength of the array to n in anticipation of further growth -#define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n)) - -// make sure maxlength is large enough for at least N new allocations -#define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \ - ? stb_arr_setsize((a), (n)) : 0) - -// make a copy of a given array (copies contents via 'memcpy'!) -#define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0])) - -// compute the storage needed to store all the elements of the array -#define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0])) - -#define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v)) - -// IMPLEMENTATION - -STB_EXTERN void stb_arr_free_(void **p); -STB_EXTERN void *stb__arr_copy_(void *p, int elem_size); -STB_EXTERN void stb__arr_setsize_(void **p, int size, int limit STB__PARAMS); -STB_EXTERN void stb__arr_setlen_(void **p, int size, int newlen STB__PARAMS); -STB_EXTERN void stb__arr_addlen_(void **p, int size, int addlen STB__PARAMS); -STB_EXTERN void stb__arr_deleten_(void **p, int size, int loc, int n STB__PARAMS); -STB_EXTERN void stb__arr_insertn_(void **p, int size, int loc, int n STB__PARAMS); - -#define stb_arr_free(p) stb_arr_free_((void **) &(p)) -#define stb__arr_copy stb__arr_copy_ - -#ifndef STB_MALLOC_WRAPPER - #define stb__arr_setsize stb__arr_setsize_ - #define stb__arr_setlen stb__arr_setlen_ - #define stb__arr_addlen stb__arr_addlen_ - #define stb__arr_deleten stb__arr_deleten_ - #define stb__arr_insertn stb__arr_insertn_ -#else - #define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__) - #define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__) - #define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__) - #define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__) - #define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__) -#endif - -#ifdef STB_DEFINE -static void *stb__arr_context; - -void *stb_arr_malloc_parent(void *p) -{ - void *q = stb__arr_context; - stb__arr_context = p; - return q; -} - -void stb_arr_malloc(void **target, void *context) -{ - stb__arr *q = (stb__arr *) stb_malloc(context, sizeof(*q)); - q->len = q->limit = 0; - q->stb_malloc = 1; - q->signature = stb_arr_signature; - *target = (void *) (q+1); -} - -static void * stb__arr_malloc(int size) -{ - if (stb__arr_context) - return stb_malloc(stb__arr_context, size); - return malloc(size); -} - -void * stb__arr_copy_(void *p, int elem_size) -{ - stb__arr *q; - if (p == NULL) return p; - q = (stb__arr *) stb__arr_malloc(sizeof(*q) + elem_size * stb_arrhead2(p)->limit); - stb_arr_check2(p); - memcpy(q, stb_arrhead2(p), sizeof(*q) + elem_size * stb_arrhead2(p)->len); - q->stb_malloc = !!stb__arr_context; - return q+1; -} - -void stb_arr_free_(void **pp) -{ - void *p = *pp; - stb_arr_check2(p); - if (p) { - stb__arr *q = stb_arrhead2(p); - if (q->stb_malloc) - stb_free(q); - else - free(q); - } - *pp = NULL; -} - -static void stb__arrsize_(void **pp, int size, int limit, int len STB__PARAMS) -{ - void *p = *pp; - stb__arr *a; - stb_arr_check2(p); - if (p == NULL) { - if (len == 0 && size == 0) return; - a = (stb__arr *) stb__arr_malloc(sizeof(*a) + size*limit); - a->limit = limit; - a->len = len; - a->stb_malloc = !!stb__arr_context; - a->signature = stb_arr_signature; - } else { - a = stb_arrhead2(p); - a->len = len; - if (a->limit < limit) { - void *p; - if (a->limit >= 4 && limit < a->limit * 2) - limit = a->limit * 2; - if (a->stb_malloc) - p = stb_realloc(a, sizeof(*a) + limit*size); - else - #ifdef STB_MALLOC_WRAPPER - p = stb__realloc(a, sizeof(*a) + limit*size, file, line); - #else - p = realloc(a, sizeof(*a) + limit*size); - #endif - if (p) { - a = (stb__arr *) p; - a->limit = limit; - } else { - // throw an error! - } - } - } - a->len = stb_min(a->len, a->limit); - *pp = a+1; -} - -void stb__arr_setsize_(void **pp, int size, int limit STB__PARAMS) -{ - void *p = *pp; - stb_arr_check2(p); - stb__arrsize_(pp, size, limit, stb_arr_len2(p) STB__ARGS); -} - -void stb__arr_setlen_(void **pp, int size, int newlen STB__PARAMS) -{ - void *p = *pp; - stb_arr_check2(p); - if (stb_arrcurmax2(p) < newlen || p == NULL) { - stb__arrsize_(pp, size, newlen, newlen STB__ARGS); - } else { - stb_arrhead2(p)->len = newlen; - } -} - -void stb__arr_addlen_(void **p, int size, int addlen STB__PARAMS) -{ - stb__arr_setlen_(p, size, stb_arr_len2(*p) + addlen STB__ARGS); -} - -void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS) -{ - void *p = *pp; - if (n) { - int z; - - if (p == NULL) { - stb__arr_addlen_(pp, size, n STB__ARGS); - return; - } - - z = stb_arr_len2(p); - stb__arr_addlen_(&p, size, n STB__ARGS); - memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i)); - } - *pp = p; -} - -void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS) -{ - void *p = *pp; - if (n) { - memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n))); - stb_arrhead2(p)->len -= n; - } - *pp = p; -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Hashing -// -// typical use for this is to make a power-of-two hash table. -// -// let N = size of table (2^n) -// let H = stb_hash(str) -// let S = stb_rehash(H) | 1 -// -// then hash probe sequence P(i) for i=0..N-1 -// P(i) = (H + S*i) & (N-1) -// -// the idea is that H has 32 bits of hash information, but the -// table has only, say, 2^20 entries so only uses 20 of the bits. -// then by rehashing the original H we get 2^12 different probe -// sequences for a given initial probe location. (So it's optimal -// for 64K tables and its optimality decreases past that.) -// -// ok, so I've added something that generates _two separate_ -// 32-bit hashes simultaneously which should scale better to -// very large tables. - - -STB_EXTERN unsigned int stb_hash(char *str); -STB_EXTERN unsigned int stb_hashptr(void *p); -STB_EXTERN unsigned int stb_hashlen(char *str, int len); -STB_EXTERN unsigned int stb_rehash_improved(unsigned int v); -STB_EXTERN unsigned int stb_hash_fast(void *p, int len); -STB_EXTERN unsigned int stb_hash2(char *str, unsigned int *hash2_ptr); -STB_EXTERN unsigned int stb_hash_number(unsigned int hash); - -#define stb_rehash(x) ((x) + ((x) >> 6) + ((x) >> 19)) - -#ifdef STB_DEFINE -unsigned int stb_hash(char *str) -{ - unsigned int hash = 0; - while (*str) - hash = (hash << 7) + (hash >> 25) + *str++; - return hash + (hash >> 16); -} - -unsigned int stb_hashlen(char *str, int len) -{ - unsigned int hash = 0; - while (len-- > 0 && *str) - hash = (hash << 7) + (hash >> 25) + *str++; - return hash + (hash >> 16); -} - -unsigned int stb_hashptr(void *p) -{ - unsigned int x = (unsigned int)(size_t) p; - - // typically lacking in low bits and high bits - x = stb_rehash(x); - x += x << 16; - - // pearson's shuffle - x ^= x << 3; - x += x >> 5; - x ^= x << 2; - x += x >> 15; - x ^= x << 10; - return stb_rehash(x); -} - -unsigned int stb_rehash_improved(unsigned int v) -{ - return stb_hashptr((void *)(size_t) v); -} - -unsigned int stb_hash2(char *str, unsigned int *hash2_ptr) -{ - unsigned int hash1 = 0x3141592c; - unsigned int hash2 = 0x77f044ed; - while (*str) { - hash1 = (hash1 << 7) + (hash1 >> 25) + *str; - hash2 = (hash2 << 11) + (hash2 >> 21) + *str; - ++str; - } - *hash2_ptr = hash2 + (hash1 >> 16); - return hash1 + (hash2 >> 16); -} - -// Paul Hsieh hash -#define stb__get16(p) ((p)[0] | ((p)[1] << 8)) - -unsigned int stb_hash_fast(void *p, int len) -{ - unsigned char *q = (unsigned char *) p; - unsigned int hash = len; - - if (len <= 0 || q == NULL) return 0; - - /* Main loop */ - for (;len > 3; len -= 4) { - unsigned int val; - hash += stb__get16(q); - val = (stb__get16(q+2) << 11); - hash = (hash << 16) ^ hash ^ val; - q += 4; - hash += hash >> 11; - } - - /* Handle end cases */ - switch (len) { - case 3: hash += stb__get16(q); - hash ^= hash << 16; - hash ^= q[2] << 18; - hash += hash >> 11; - break; - case 2: hash += stb__get16(q); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += q[0]; - hash ^= hash << 10; - hash += hash >> 1; - break; - case 0: break; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -unsigned int stb_hash_number(unsigned int hash) -{ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; -} - -#endif - -#ifdef STB_PERFECT_HASH -////////////////////////////////////////////////////////////////////////////// -// -// Perfect hashing for ints/pointers -// -// This is mainly useful for making faster pointer-indexed tables -// that don't change frequently. E.g. for stb_ischar(). -// - -typedef struct -{ - stb_uint32 addend; - stb_uint multiplicand; - stb_uint b_mask; - stb_uint8 small_bmap[16]; - stb_uint16 *large_bmap; - - stb_uint table_mask; - stb_uint32 *table; -} stb_perfect; - -STB_EXTERN int stb_perfect_create(stb_perfect *,unsigned int*,int n); -STB_EXTERN void stb_perfect_destroy(stb_perfect *); -STB_EXTERN int stb_perfect_hash(stb_perfect *, unsigned int x); -extern int stb_perfect_hash_max_failures; - -#ifdef STB_DEFINE - -int stb_perfect_hash_max_failures; - -int stb_perfect_hash(stb_perfect *p, unsigned int x) -{ - stb_uint m = x * p->multiplicand; - stb_uint y = x >> 16; - stb_uint bv = (m >> 24) + y; - stb_uint av = (m + y) >> 12; - if (p->table == NULL) return -1; // uninitialized table fails - bv &= p->b_mask; - av &= p->table_mask; - if (p->large_bmap) - av ^= p->large_bmap[bv]; - else - av ^= p->small_bmap[bv]; - return p->table[av] == x ? av : -1; -} - -static void stb__perfect_prehash(stb_perfect *p, stb_uint x, stb_uint16 *a, stb_uint16 *b) -{ - stb_uint m = x * p->multiplicand; - stb_uint y = x >> 16; - stb_uint bv = (m >> 24) + y; - stb_uint av = (m + y) >> 12; - bv &= p->b_mask; - av &= p->table_mask; - *b = bv; - *a = av; -} - -static unsigned long stb__perfect_rand(void) -{ - static unsigned long stb__rand; - stb__rand = stb__rand * 2147001325 + 715136305; - return 0x31415926 ^ ((stb__rand >> 16) + (stb__rand << 16)); -} - -typedef struct { - unsigned short count; - unsigned short b; - unsigned short map; - unsigned short *entries; -} stb__slot; - -static int stb__slot_compare(const void *p, const void *q) -{ - stb__slot *a = (stb__slot *) p; - stb__slot *b = (stb__slot *) q; - return a->count > b->count ? -1 : a->count < b->count; // sort large to small -} - -int stb_perfect_create(stb_perfect *p, unsigned int *v, int n) -{ - unsigned int buffer1[64], buffer2[64], buffer3[64], buffer4[64], buffer5[32]; - unsigned short *as = (unsigned short *) stb_temp(buffer1, sizeof(*v)*n); - unsigned short *bs = (unsigned short *) stb_temp(buffer2, sizeof(*v)*n); - unsigned short *entries = (unsigned short *) stb_temp(buffer4, sizeof(*entries) * n); - int size = 1 << stb_log2_ceil(n), bsize=8; - int failure = 0,i,j,k; - - assert(n <= 32768); - p->large_bmap = NULL; - - for(;;) { - stb__slot *bcount = (stb__slot *) stb_temp(buffer3, sizeof(*bcount) * bsize); - unsigned short *bloc = (unsigned short *) stb_temp(buffer5, sizeof(*bloc) * bsize); - unsigned short *e; - int bad=0; - - p->addend = stb__perfect_rand(); - p->multiplicand = stb__perfect_rand() | 1; - p->table_mask = size-1; - p->b_mask = bsize-1; - p->table = (stb_uint32 *) malloc(size * sizeof(*p->table)); - - for (i=0; i < bsize; ++i) { - bcount[i].b = i; - bcount[i].count = 0; - bcount[i].map = 0; - } - for (i=0; i < n; ++i) { - stb__perfect_prehash(p, v[i], as+i, bs+i); - ++bcount[bs[i]].count; - } - qsort(bcount, bsize, sizeof(*bcount), stb__slot_compare); - e = entries; // now setup up their entries index - for (i=0; i < bsize; ++i) { - bcount[i].entries = e; - e += bcount[i].count; - bcount[i].count = 0; - bloc[bcount[i].b] = i; - } - // now fill them out - for (i=0; i < n; ++i) { - int b = bs[i]; - int w = bloc[b]; - bcount[w].entries[bcount[w].count++] = i; - } - stb_tempfree(buffer5,bloc); - // verify - for (i=0; i < bsize; ++i) - for (j=0; j < bcount[i].count; ++j) - assert(bs[bcount[i].entries[j]] == bcount[i].b); - memset(p->table, 0, size*sizeof(*p->table)); - - // check if any b has duplicate a - for (i=0; i < bsize; ++i) { - if (bcount[i].count > 1) { - for (j=0; j < bcount[i].count; ++j) { - if (p->table[as[bcount[i].entries[j]]]) - bad = 1; - p->table[as[bcount[i].entries[j]]] = 1; - } - for (j=0; j < bcount[i].count; ++j) { - p->table[as[bcount[i].entries[j]]] = 0; - } - if (bad) break; - } - } - - if (!bad) { - // go through the bs and populate the table, first fit - for (i=0; i < bsize; ++i) { - if (bcount[i].count) { - // go through the candidate table[b] values - for (j=0; j < size; ++j) { - // go through the a values and see if they fit - for (k=0; k < bcount[i].count; ++k) { - int a = as[bcount[i].entries[k]]; - if (p->table[(a^j)&p->table_mask]) { - break; // fails - } - } - // if succeeded, accept - if (k == bcount[i].count) { - bcount[i].map = j; - for (k=0; k < bcount[i].count; ++k) { - int a = as[bcount[i].entries[k]]; - p->table[(a^j)&p->table_mask] = 1; - } - break; - } - } - if (j == size) - break; // no match for i'th entry, so break out in failure - } - } - if (i == bsize) { - // success... fill out map - if (bsize <= 16 && size <= 256) { - p->large_bmap = NULL; - for (i=0; i < bsize; ++i) - p->small_bmap[bcount[i].b] = (stb_uint8) bcount[i].map; - } else { - p->large_bmap = (unsigned short *) malloc(sizeof(*p->large_bmap) * bsize); - for (i=0; i < bsize; ++i) - p->large_bmap[bcount[i].b] = bcount[i].map; - } - - // initialize table to v[0], so empty slots will fail - for (i=0; i < size; ++i) - p->table[i] = v[0]; - - for (i=0; i < n; ++i) - if (p->large_bmap) - p->table[as[i] ^ p->large_bmap[bs[i]]] = v[i]; - else - p->table[as[i] ^ p->small_bmap[bs[i]]] = v[i]; - - // and now validate that none of them collided - for (i=0; i < n; ++i) - assert(stb_perfect_hash(p, v[i]) >= 0); - - stb_tempfree(buffer3, bcount); - break; - } - } - free(p->table); - p->table = NULL; - stb_tempfree(buffer3, bcount); - - ++failure; - if (failure >= 4 && bsize < size) bsize *= 2; - if (failure >= 8 && (failure & 3) == 0 && size < 4*n) { - size *= 2; - bsize *= 2; - } - if (failure == 6) { - // make sure the input data is unique, so we don't infinite loop - unsigned int *data = (unsigned int *) stb_temp(buffer3, n * sizeof(*data)); - memcpy(data, v, sizeof(*data) * n); - qsort(data, n, sizeof(*data), stb_intcmp(0)); - for (i=1; i < n; ++i) { - if (data[i] == data[i-1]) - size = 0; // size is return value, so 0 it - } - stb_tempfree(buffer3, data); - if (!size) break; - } - } - - if (failure > stb_perfect_hash_max_failures) - stb_perfect_hash_max_failures = failure; - - stb_tempfree(buffer1, as); - stb_tempfree(buffer2, bs); - stb_tempfree(buffer4, entries); - - return size; -} - -void stb_perfect_destroy(stb_perfect *p) -{ - if (p->large_bmap) free(p->large_bmap); - if (p->table ) free(p->table); - p->large_bmap = NULL; - p->table = NULL; - p->b_mask = 0; - p->table_mask = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Perfect hash clients - -STB_EXTERN int stb_ischar(char s, char *set); - -#ifdef STB_DEFINE - -int stb_ischar(char c, char *set) -{ - static unsigned char bit[8] = { 1,2,4,8,16,32,64,128 }; - static stb_perfect p; - static unsigned char (*tables)[256]; - static char ** sets = NULL; - - int z = stb_perfect_hash(&p, (int)(size_t) set); - if (z < 0) { - int i,k,n,j,f; - // special code that means free all existing data - if (set == NULL) { - stb_arr_free(sets); - free(tables); - tables = NULL; - stb_perfect_destroy(&p); - return 0; - } - stb_arr_push(sets, set); - stb_perfect_destroy(&p); - n = stb_perfect_create(&p, (unsigned int *) (char **) sets, stb_arr_len(sets)); - assert(n != 0); - k = (n+7) >> 3; - tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k); - memset(tables, 0, sizeof(*tables) * k); - for (i=0; i < stb_arr_len(sets); ++i) { - k = stb_perfect_hash(&p, (int)(size_t) sets[i]); - assert(k >= 0); - n = k >> 3; - f = bit[k&7]; - for (j=0; !j || sets[i][j]; ++j) { - tables[n][(unsigned char) sets[i][j]] |= f; - } - } - z = stb_perfect_hash(&p, (int)(size_t) set); - } - return tables[z >> 3][(unsigned char) c] & bit[z & 7]; -} - -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Instantiated data structures -// -// This is an attempt to implement a templated data structure. -// -// Hash table: call stb_define_hash(TYPE,N,KEY,K1,K2,HASH,VALUE) -// TYPE -- will define a structure type containing the hash table -// N -- the name, will prefix functions named: -// N create -// N destroy -// N get -// N set, N add, N update, -// N remove -// KEY -- the type of the key. 'x == y' must be valid -// K1,K2 -- keys never used by the app, used as flags in the hashtable -// HASH -- a piece of code ending with 'return' that hashes key 'k' -// VALUE -- the type of the value. 'x = y' must be valid -// -// Note that stb_define_hash_base can be used to define more sophisticated -// hash tables, e.g. those that make copies of the key or use special -// comparisons (e.g. strcmp). - -#define STB_(prefix,name) stb__##prefix##name -#define STB__(prefix,name) prefix##name -#define STB__use(x) x -#define STB__skip(x) - -#define stb_declare_hash(PREFIX,TYPE,N,KEY,VALUE) \ - typedef struct stb__st_##TYPE TYPE;\ - PREFIX int STB__(N, init)(TYPE *h, int count);\ - PREFIX int STB__(N, memory_usage)(TYPE *h);\ - PREFIX TYPE * STB__(N, create)(void);\ - PREFIX TYPE * STB__(N, copy)(TYPE *h);\ - PREFIX void STB__(N, destroy)(TYPE *h);\ - PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v);\ - PREFIX VALUE STB__(N,get)(TYPE *a, KEY k);\ - PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v);\ - PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v);\ - PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v);\ - PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v); - -#define STB_nocopy(x) (x) -#define STB_nodelete(x) 0 -#define STB_nofields -#define STB_nonullvalue(x) -#define STB_nullvalue(x) x -#define STB_safecompare(x) x -#define STB_nosafe(x) -#define STB_noprefix - -#ifdef __GNUC__ -#define STB__nogcc(x) -#else -#define STB__nogcc(x) x -#endif - -#define stb_define_hash_base(PREFIX,TYPE,FIELDS,N,NC,LOAD_FACTOR, \ - KEY,EMPTY,DEL,COPY,DISPOSE,SAFE, \ - VCOMPARE,CCOMPARE,HASH, \ - VALUE,HASVNULL,VNULL) \ - \ -typedef struct \ -{ \ - KEY k; \ - VALUE v; \ -} STB_(N,_hashpair); \ - \ -STB__nogcc( typedef struct stb__st_##TYPE TYPE; ) \ -struct stb__st_##TYPE { \ - FIELDS \ - STB_(N,_hashpair) *table; \ - unsigned int mask; \ - int count, limit; \ - int deleted; \ - \ - int delete_threshhold; \ - int grow_threshhold; \ - int shrink_threshhold; \ - unsigned char alloced, has_empty, has_del; \ - VALUE ev; VALUE dv; \ -}; \ - \ -static unsigned int STB_(N, hash)(KEY k) \ -{ \ - HASH \ -} \ - \ -PREFIX int STB__(N, init)(TYPE *h, int count) \ -{ \ - int i; \ - if (count < 4) count = 4; \ - h->limit = count; \ - h->count = 0; \ - h->mask = count-1; \ - h->deleted = 0; \ - h->grow_threshhold = (int) (count * LOAD_FACTOR); \ - h->has_empty = h->has_del = 0; \ - h->alloced = 0; \ - if (count <= 64) \ - h->shrink_threshhold = 0; \ - else \ - h->shrink_threshhold = (int) (count * (LOAD_FACTOR/2.25)); \ - h->delete_threshhold = (int) (count * (1-LOAD_FACTOR)/2); \ - h->table = (STB_(N,_hashpair)*) malloc(sizeof(h->table[0]) * count); \ - if (h->table == NULL) return 0; \ - /* ideally this gets turned into a memset32 automatically */ \ - for (i=0; i < count; ++i) \ - h->table[i].k = EMPTY; \ - return 1; \ -} \ - \ -PREFIX int STB__(N, memory_usage)(TYPE *h) \ -{ \ - return sizeof(*h) + h->limit * sizeof(h->table[0]); \ -} \ - \ -PREFIX TYPE * STB__(N, create)(void) \ -{ \ - TYPE *h = (TYPE *) malloc(sizeof(*h)); \ - if (h) { \ - if (STB__(N, init)(h, 16)) \ - h->alloced = 1; \ - else { free(h); h=NULL; } \ - } \ - return h; \ -} \ - \ -PREFIX void STB__(N, destroy)(TYPE *a) \ -{ \ - int i; \ - for (i=0; i < a->limit; ++i) \ - if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k, DEL)) \ - DISPOSE(a->table[i].k); \ - free(a->table); \ - if (a->alloced) \ - free(a); \ -} \ - \ -static void STB_(N, rehash)(TYPE *a, int count); \ - \ -PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask, s; \ - if (CCOMPARE(k,EMPTY)){ if (a->has_empty) *v = a->ev; return a->has_empty;}\ - if (CCOMPARE(k,DEL)) { if (a->has_del ) *v = a->dv; return a->has_del; }\ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ - if (VCOMPARE(a->table[n].k,k)) { *v = a->table[n].v; return 1; } \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ - if (VCOMPARE(a->table[n].k,k)) \ - { *v = a->table[n].v; return 1; } \ - } \ -} \ - \ -HASVNULL( \ - PREFIX VALUE STB__(N,get)(TYPE *a, KEY k) \ - { \ - VALUE v; \ - if (STB__(N,get_flag)(a,k,&v)) return v; \ - else return VNULL; \ - } \ -) \ - \ -PREFIX int STB__(N,getkey)(TYPE *a, KEY k, KEY *kout) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask, s; \ - if (CCOMPARE(k,EMPTY)||CCOMPARE(k,DEL)) return 0; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ - if (VCOMPARE(a->table[n].k,k)) { *kout = a->table[n].k; return 1; } \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ - if (VCOMPARE(a->table[n].k,k)) \ - { *kout = a->table[n].k; return 1; } \ - } \ -} \ - \ -static int STB_(N,addset)(TYPE *a, KEY k, VALUE v, \ - int allow_new, int allow_old, int copy) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask; \ - int b = -1; \ - if (CCOMPARE(k,EMPTY)) { \ - if (a->has_empty ? allow_old : allow_new) { \ - n=a->has_empty; a->ev = v; a->has_empty = 1; return !n; \ - } else return 0; \ - } \ - if (CCOMPARE(k,DEL)) { \ - if (a->has_del ? allow_old : allow_new) { \ - n=a->has_del; a->dv = v; a->has_del = 1; return !n; \ - } else return 0; \ - } \ - if (!CCOMPARE(a->table[n].k, EMPTY)) { \ - unsigned int s; \ - if (CCOMPARE(a->table[n].k, DEL)) \ - b = n; \ - else if (VCOMPARE(a->table[n].k,k)) { \ - if (allow_old) \ - a->table[n].v = v; \ - return !allow_new; \ - } \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k, EMPTY)) break; \ - if (CCOMPARE(a->table[n].k, DEL)) { \ - if (b < 0) b = n; \ - } else if (VCOMPARE(a->table[n].k,k)) { \ - if (allow_old) \ - a->table[n].v = v; \ - return !allow_new; \ - } \ - } \ - } \ - if (!allow_new) return 0; \ - if (b < 0) b = n; else --a->deleted; \ - a->table[b].k = copy ? COPY(k) : k; \ - a->table[b].v = v; \ - ++a->count; \ - if (a->count > a->grow_threshhold) \ - STB_(N,rehash)(a, a->limit*2); \ - return 1; \ -} \ - \ -PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,1,1);}\ -PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,0,1);}\ -PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v){return STB_(N,addset)(a,k,v,0,1,1);}\ - \ -PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask, s; \ - if (CCOMPARE(k,EMPTY)) { if (a->has_empty) { if(v)*v = a->ev; a->has_empty=0; return 1; } return 0; } \ - if (CCOMPARE(k,DEL)) { if (a->has_del ) { if(v)*v = a->dv; a->has_del =0; return 1; } return 0; } \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - if (SAFE(CCOMPARE(a->table[n].k,DEL) || ) !VCOMPARE(a->table[n].k,k)) { \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (CCOMPARE(a->table[n].k, DEL)) continue;) \ - if (VCOMPARE(a->table[n].k,k)) break; \ - } \ - } \ - DISPOSE(a->table[n].k); \ - a->table[n].k = DEL; \ - --a->count; \ - ++a->deleted; \ - if (v != NULL) \ - *v = a->table[n].v; \ - if (a->count < a->shrink_threshhold) \ - STB_(N, rehash)(a, a->limit >> 1); \ - else if (a->deleted > a->delete_threshhold) \ - STB_(N, rehash)(a, a->limit); \ - return 1; \ -} \ - \ -PREFIX TYPE * STB__(NC, copy)(TYPE *a) \ -{ \ - int i; \ - TYPE *h = (TYPE *) malloc(sizeof(*h)); \ - if (!h) return NULL; \ - if (!STB__(N, init)(h, a->limit)) { free(h); return NULL; } \ - h->count = a->count; \ - h->deleted = a->deleted; \ - h->alloced = 1; \ - h->ev = a->ev; h->dv = a->dv; \ - h->has_empty = a->has_empty; h->has_del = a->has_del; \ - memcpy(h->table, a->table, h->limit * sizeof(h->table[0])); \ - for (i=0; i < a->limit; ++i) \ - if (!CCOMPARE(h->table[i].k,EMPTY) && !CCOMPARE(h->table[i].k,DEL)) \ - h->table[i].k = COPY(h->table[i].k); \ - return h; \ -} \ - \ -static void STB_(N, rehash)(TYPE *a, int count) \ -{ \ - int i; \ - TYPE b; \ - STB__(N, init)(&b, count); \ - for (i=0; i < a->limit; ++i) \ - if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k,DEL)) \ - STB_(N,addset)(&b, a->table[i].k, a->table[i].v,1,1,0); \ - free(a->table); \ - a->table = b.table; \ - a->mask = b.mask; \ - a->count = b.count; \ - a->limit = b.limit; \ - a->deleted = b.deleted; \ - a->delete_threshhold = b.delete_threshhold; \ - a->grow_threshhold = b.grow_threshhold; \ - a->shrink_threshhold = b.shrink_threshhold; \ -} - -#define STB_equal(a,b) ((a) == (b)) - -#define stb_define_hash(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE) \ - stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ - KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ - STB_equal,STB_equal,HASH, \ - VALUE,STB_nonullvalue,0) - -#define stb_define_hash_vnull(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE,VNULL) \ - stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ - KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ - STB_equal,STB_equal,HASH, \ - VALUE,STB_nullvalue,VNULL) - -////////////////////////////////////////////////////////////////////////////// -// -// stb_ptrmap -// -// An stb_ptrmap data structure is an O(1) hash table between pointers. One -// application is to let you store "extra" data associated with pointers, -// which is why it was originally called stb_extra. - -stb_declare_hash(STB_EXTERN, stb_ptrmap, stb_ptrmap_, void *, void *) -stb_declare_hash(STB_EXTERN, stb_idict, stb_idict_, stb_int32, stb_int32) -stb_declare_hash(STB_EXTERN, stb_uidict, stbi_uidict_, stb_uint32, stb_uint32) - -STB_EXTERN void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *)); -STB_EXTERN stb_ptrmap *stb_ptrmap_new(void); - -STB_EXTERN stb_idict * stb_idict_new_size(int size); -STB_EXTERN void stb_idict_remove_all(stb_idict *e); -STB_EXTERN void stb_uidict_reset(stb_uidict *e); - -#ifdef STB_DEFINE - -#define STB_EMPTY ((void *) 2) -#define STB_EDEL ((void *) 6) - -stb_define_hash_base(STB_noprefix,stb_ptrmap, STB_nofields, stb_ptrmap_,stb_ptrmap_,0.85f, - void *,STB_EMPTY,STB_EDEL,STB_nocopy,STB_nodelete,STB_nosafe, - STB_equal,STB_equal,return stb_hashptr(k);, - void *,STB_nullvalue,NULL) - -stb_ptrmap *stb_ptrmap_new(void) -{ - return stb_ptrmap_create(); -} - -void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *)) -{ - int i; - if (free_func) - for (i=0; i < e->limit; ++i) - if (e->table[i].k != STB_EMPTY && e->table[i].k != STB_EDEL) { - if (free_func == free) - free(e->table[i].v); // allow STB_MALLOC_WRAPPER to operate - else - free_func(e->table[i].v); - } - stb_ptrmap_destroy(e); -} - -// extra fields needed for stua_dict -#define STB_IEMPTY ((int) 1) -#define STB_IDEL ((int) 3) -stb_define_hash_base(STB_noprefix, stb_idict, short type; short gc; STB_nofields, stb_idict_,stb_idict_,0.95f, - stb_int32,STB_IEMPTY,STB_IDEL,STB_nocopy,STB_nodelete,STB_nosafe, - STB_equal,STB_equal, - return stb_rehash_improved(k);,stb_int32,STB_nonullvalue,0) - -stb_idict * stb_idict_new_size(int size) -{ - stb_idict *e = (stb_idict *) malloc(sizeof(*e)); - if (e) { - if (!stb_is_pow2(size)) - size = 1 << stb_log2_ceil(size); - stb_idict_init(e, size); - e->alloced = 1; - } - return e; -} - -void stb_idict_remove_all(stb_idict *e) -{ - int n; - for (n=0; n < e->limit; ++n) - e->table[n].k = STB_IEMPTY; - e->has_empty = e->has_del = 0; - e->count = 0; - e->deleted = 0; -} - -stb_define_hash_base(STB_noprefix, stb_uidict, STB_nofields, stb_uidict_,stb_uidict_,0.85f, - stb_int32,0xffffffff,0xfffffffe,STB_nocopy,STB_nodelete,STB_nosafe, - STB_equal,STB_equal, - return stb_rehash_improved(k);,stb_uint32,STB_nonullvalue,0) - -void stb_uidict_reset(stb_uidict *e) -{ - int n; - for (n=0; n < e->limit; ++n) - e->table[n].k = 0xffffffff; - e->has_empty = e->has_del = 0; - e->count = 0; - e->deleted = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// stb_sparse_ptr_matrix -// -// An stb_ptrmap data structure is an O(1) hash table storing an arbitrary -// block of data for a given pair of pointers. -// -// If create=0, returns - -typedef struct stb__st_stb_spmatrix stb_spmatrix; - -STB_EXTERN stb_spmatrix * stb_sparse_ptr_matrix_new(int val_size); -STB_EXTERN void stb_sparse_ptr_matrix_free(stb_spmatrix *z); -STB_EXTERN void * stb_sparse_ptr_matrix_get(stb_spmatrix *z, void *a, void *b, int create); - -#ifdef STB_DEFINE -typedef struct -{ - void *a; - void *b; -} stb__ptrpair; - -static stb__ptrpair stb__ptrpair_empty = { (void *) 1, (void *) 1 }; -static stb__ptrpair stb__ptrpair_del = { (void *) 2, (void *) 2 }; - -#define STB__equal_ptrpair(x,y) ((x).a == (y).a && (x).b == (y).b) - -stb_define_hash_base(STB_noprefix, stb_spmatrix, int val_size; void *arena;, stb__spmatrix_,stb__spmatrix_, 0.85, - stb__ptrpair, stb__ptrpair_empty, stb__ptrpair_del, - STB_nocopy, STB_nodelete, STB_nosafe, - STB__equal_ptrpair, STB__equal_ptrpair, return stb_rehash(stb_hashptr(k.a))+stb_hashptr(k.b);, - void *, STB_nullvalue, 0) - -stb_spmatrix *stb_sparse_ptr_matrix_new(int val_size) -{ - stb_spmatrix *m = stb__spmatrix_create(); - if (m) m->val_size = val_size; - if (m) m->arena = stb_malloc_global(1); - return m; -} - -void stb_sparse_ptr_matrix_free(stb_spmatrix *z) -{ - if (z->arena) stb_free(z->arena); - stb__spmatrix_destroy(z); -} - -void *stb_sparse_ptr_matrix_get(stb_spmatrix *z, void *a, void *b, int create) -{ - stb__ptrpair t = { a,b }; - void *data = stb__spmatrix_get(z, t); - if (!data && create) { - data = stb_malloc_raw(z->arena, z->val_size); - if (!data) return NULL; - memset(data, 0, z->val_size); - stb__spmatrix_add(z, t, data); - } - return data; -} -#endif - - - -////////////////////////////////////////////////////////////////////////////// -// -// SDICT: Hash Table for Strings (symbol table) -// -// if "use_arena=1", then strings will be copied -// into blocks and never freed until the sdict is freed; -// otherwise they're malloc()ed and free()d on the fly. -// (specify use_arena=1 if you never stb_sdict_remove) - -stb_declare_hash(STB_EXTERN, stb_sdict, stb_sdict_, char *, void *) - -STB_EXTERN stb_sdict * stb_sdict_new(int use_arena); -STB_EXTERN stb_sdict * stb_sdict_copy(stb_sdict*); -STB_EXTERN void stb_sdict_delete(stb_sdict *); -STB_EXTERN void * stb_sdict_change(stb_sdict *, char *str, void *p); -STB_EXTERN int stb_sdict_count(stb_sdict *d); - -STB_EXTERN int stb_sdict_internal_limit(stb_sdict *d); -STB_EXTERN char * stb_sdict_internal_key(stb_sdict *d, int n); -STB_EXTERN void * stb_sdict_internal_value(stb_sdict *d, int n); - -#define stb_sdict_for(d,i,q,z) \ - for(i=0; i < stb_sdict_internal_limit(d) ? (q=stb_sdict_internal_key(d,i),z=stb_sdict_internal_value(d,i),1) : 0; ++i) \ - if (q==NULL||q==(void *) 1);else // reversed makes macro friendly - -#ifdef STB_DEFINE - -// if in same translation unit, for speed, don't call accessors -#undef stb_sdict_for -#define stb_sdict_for(d,i,q,z) \ - for(i=0; i < (d)->limit ? (q=(d)->table[i].k,z=(d)->table[i].v,1) : 0; ++i) \ - if (q==NULL||q==(void *) 1);else // reversed makes macro friendly - -#define STB_DEL ((void *) 1) -#define STB_SDEL ((char *) 1) - -#define stb_sdict__copy(x) \ - stb_p_strcpy_s(a->arena ? stb_malloc_string(a->arena, strlen(x)+1) \ - : (char *) malloc(strlen(x)+1), strlen(x)+1, x) - -#define stb_sdict__dispose(x) if (!a->arena) free(x) - -stb_define_hash_base(STB_noprefix, stb_sdict, void*arena;, stb_sdict_,stb_sdictinternal_, 0.85f, - char *, NULL, STB_SDEL, stb_sdict__copy, stb_sdict__dispose, - STB_safecompare, !strcmp, STB_equal, return stb_hash(k);, - void *, STB_nullvalue, NULL) - -int stb_sdict_count(stb_sdict *a) -{ - return a->count; -} - -int stb_sdict_internal_limit(stb_sdict *a) -{ - return a->limit; -} -char* stb_sdict_internal_key(stb_sdict *a, int n) -{ - return a->table[n].k; -} -void* stb_sdict_internal_value(stb_sdict *a, int n) -{ - return a->table[n].v; -} - -stb_sdict * stb_sdict_new(int use_arena) -{ - stb_sdict *d = stb_sdict_create(); - if (d == NULL) return NULL; - d->arena = use_arena ? stb_malloc_global(1) : NULL; - return d; -} - -stb_sdict* stb_sdict_copy(stb_sdict *old) -{ - stb_sdict *n; - void *old_arena = old->arena; - void *new_arena = old_arena ? stb_malloc_global(1) : NULL; - old->arena = new_arena; - n = stb_sdictinternal_copy(old); - old->arena = old_arena; - if (n) - n->arena = new_arena; - else if (new_arena) - stb_free(new_arena); - return n; -} - - -void stb_sdict_delete(stb_sdict *d) -{ - if (d->arena) - stb_free(d->arena); - stb_sdict_destroy(d); -} - -void * stb_sdict_change(stb_sdict *d, char *str, void *p) -{ - void *q = stb_sdict_get(d, str); - stb_sdict_set(d, str, p); - return q; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Instantiated data structures -// -// This is an attempt to implement a templated data structure. -// What you do is define a struct foo, and then include several -// pointer fields to struct foo in your struct. Then you call -// the instantiator, which creates the functions that implement -// the data structure. This requires massive undebuggable #defines, -// so we limit the cases where we do this. -// -// AA tree is an encoding of a 2-3 tree whereas RB trees encode a 2-3-4 tree; -// much simpler code due to fewer cases. - -#define stb__bst_parent(x) x -#define stb__bst_noparent(x) - -#define stb_bst_fields(N) \ - *STB_(N,left), *STB_(N,right); \ - unsigned char STB_(N,level) - -#define stb_bst_fields_parent(N) \ - *STB_(N,left), *STB_(N,right), *STB_(N,parent); \ - unsigned char STB_(N,level) - -#define STB__level(N,x) ((x) ? (x)->STB_(N,level) : 0) - -#define stb_bst_base(TYPE, N, TREE, M, compare, PAR) \ - \ -static int STB_(N,_compare)(TYPE *p, TYPE *q) \ -{ \ - compare \ -} \ - \ -static void STB_(N,setleft)(TYPE *q, TYPE *v) \ -{ \ - q->STB_(N,left) = v; \ - PAR(if (v) v->STB_(N,parent) = q;) \ -} \ - \ -static void STB_(N,setright)(TYPE *q, TYPE *v) \ -{ \ - q->STB_(N,right) = v; \ - PAR(if (v) v->STB_(N,parent) = q;) \ -} \ - \ -static TYPE *STB_(N,skew)(TYPE *q) \ -{ \ - if (q == NULL) return q; \ - if (q->STB_(N,left) \ - && q->STB_(N,left)->STB_(N,level) == q->STB_(N,level)) { \ - TYPE *p = q->STB_(N,left); \ - STB_(N,setleft)(q, p->STB_(N,right)); \ - STB_(N,setright)(p, q); \ - return p; \ - } \ - return q; \ -} \ - \ -static TYPE *STB_(N,split)(TYPE *p) \ -{ \ - TYPE *q = p->STB_(N,right); \ - if (q && q->STB_(N,right) \ - && q->STB_(N,right)->STB_(N,level) == p->STB_(N,level)) { \ - STB_(N,setright)(p, q->STB_(N,left)); \ - STB_(N,setleft)(q,p); \ - ++q->STB_(N,level); \ - return q; \ - } \ - return p; \ -} \ - \ -TYPE *STB__(N,insert)(TYPE *tree, TYPE *item) \ -{ \ - int c; \ - if (tree == NULL) { \ - item->STB_(N,left) = NULL; \ - item->STB_(N,right) = NULL; \ - item->STB_(N,level) = 1; \ - PAR(item->STB_(N,parent) = NULL;) \ - return item; \ - } \ - c = STB_(N,_compare)(item,tree); \ - if (c == 0) { \ - if (item != tree) { \ - STB_(N,setleft)(item, tree->STB_(N,left)); \ - STB_(N,setright)(item, tree->STB_(N,right)); \ - item->STB_(N,level) = tree->STB_(N,level); \ - PAR(item->STB_(N,parent) = NULL;) \ - } \ - return item; \ - } \ - if (c < 0) \ - STB_(N,setleft )(tree, STB__(N,insert)(tree->STB_(N,left), item)); \ - else \ - STB_(N,setright)(tree, STB__(N,insert)(tree->STB_(N,right), item)); \ - tree = STB_(N,skew)(tree); \ - tree = STB_(N,split)(tree); \ - PAR(tree->STB_(N,parent) = NULL;) \ - return tree; \ -} \ - \ -TYPE *STB__(N,remove)(TYPE *tree, TYPE *item) \ -{ \ - static TYPE *delnode, *leaf, *restore; \ - if (tree == NULL) return NULL; \ - leaf = tree; \ - if (STB_(N,_compare)(item, tree) < 0) { \ - STB_(N,setleft)(tree, STB__(N,remove)(tree->STB_(N,left), item)); \ - } else { \ - TYPE *r; \ - delnode = tree; \ - r = STB__(N,remove)(tree->STB_(N,right), item); \ - /* maybe move 'leaf' up to this location */ \ - if (restore == tree) { tree = leaf; leaf = restore = NULL; } \ - STB_(N,setright)(tree,r); \ - assert(tree->STB_(N,right) != tree); \ - } \ - if (tree == leaf) { \ - if (delnode == item) { \ - tree = tree->STB_(N,right); \ - assert(leaf->STB_(N,left) == NULL); \ - /* move leaf (the right sibling) up to delnode */ \ - STB_(N,setleft )(leaf, item->STB_(N,left )); \ - STB_(N,setright)(leaf, item->STB_(N,right)); \ - leaf->STB_(N,level) = item->STB_(N,level); \ - if (leaf != item) \ - restore = delnode; \ - } \ - delnode = NULL; \ - } else { \ - if (STB__level(N,tree->STB_(N,left) ) < tree->STB_(N,level)-1 || \ - STB__level(N,tree->STB_(N,right)) < tree->STB_(N,level)-1) { \ - --tree->STB_(N,level); \ - if (STB__level(N,tree->STB_(N,right)) > tree->STB_(N,level)) \ - tree->STB_(N,right)->STB_(N,level) = tree->STB_(N,level); \ - tree = STB_(N,skew)(tree); \ - STB_(N,setright)(tree, STB_(N,skew)(tree->STB_(N,right))); \ - if (tree->STB_(N,right)) \ - STB_(N,setright)(tree->STB_(N,right), \ - STB_(N,skew)(tree->STB_(N,right)->STB_(N,right))); \ - tree = STB_(N,split)(tree); \ - if (tree->STB_(N,right)) \ - STB_(N,setright)(tree, STB_(N,split)(tree->STB_(N,right))); \ - } \ - } \ - PAR(if (tree) tree->STB_(N,parent) = NULL;) \ - return tree; \ -} \ - \ -TYPE *STB__(N,last)(TYPE *tree) \ -{ \ - if (tree) \ - while (tree->STB_(N,right)) tree = tree->STB_(N,right); \ - return tree; \ -} \ - \ -TYPE *STB__(N,first)(TYPE *tree) \ -{ \ - if (tree) \ - while (tree->STB_(N,left)) tree = tree->STB_(N,left); \ - return tree; \ -} \ - \ -TYPE *STB__(N,next)(TYPE *tree, TYPE *item) \ -{ \ - TYPE *next = NULL; \ - if (item->STB_(N,right)) \ - return STB__(N,first)(item->STB_(N,right)); \ - PAR( \ - while(item->STB_(N,parent)) { \ - TYPE *up = item->STB_(N,parent); \ - if (up->STB_(N,left) == item) return up; \ - item = up; \ - } \ - return NULL; \ - ) \ - while (tree != item) { \ - if (STB_(N,_compare)(item, tree) < 0) { \ - next = tree; \ - tree = tree->STB_(N,left); \ - } else { \ - tree = tree->STB_(N,right); \ - } \ - } \ - return next; \ -} \ - \ -TYPE *STB__(N,prev)(TYPE *tree, TYPE *item) \ -{ \ - TYPE *next = NULL; \ - if (item->STB_(N,left)) \ - return STB__(N,last)(item->STB_(N,left)); \ - PAR( \ - while(item->STB_(N,parent)) { \ - TYPE *up = item->STB_(N,parent); \ - if (up->STB_(N,right) == item) return up; \ - item = up; \ - } \ - return NULL; \ - ) \ - while (tree != item) { \ - if (STB_(N,_compare)(item, tree) < 0) { \ - tree = tree->STB_(N,left); \ - } else { \ - next = tree; \ - tree = tree->STB_(N,right); \ - } \ - } \ - return next; \ -} \ - \ -STB__DEBUG( \ - void STB__(N,_validate)(TYPE *tree, int root) \ - { \ - if (tree == NULL) return; \ - PAR(if(root) assert(tree->STB_(N,parent) == NULL);) \ - assert(STB__level(N,tree->STB_(N,left) ) == tree->STB_(N,level)-1); \ - assert(STB__level(N,tree->STB_(N,right)) <= tree->STB_(N,level)); \ - assert(STB__level(N,tree->STB_(N,right)) >= tree->STB_(N,level)-1); \ - if (tree->STB_(N,right)) { \ - assert(STB__level(N,tree->STB_(N,right)->STB_(N,right)) \ - != tree->STB_(N,level)); \ - PAR(assert(tree->STB_(N,right)->STB_(N,parent) == tree);) \ - } \ - PAR(if(tree->STB_(N,left)) assert(tree->STB_(N,left)->STB_(N,parent) == tree);) \ - STB__(N,_validate)(tree->STB_(N,left) ,0); \ - STB__(N,_validate)(tree->STB_(N,right),0); \ - } \ -) \ - \ -typedef struct \ -{ \ - TYPE *root; \ -} TREE; \ - \ -void STB__(M,Insert)(TREE *tree, TYPE *item) \ -{ tree->root = STB__(N,insert)(tree->root, item); } \ -void STB__(M,Remove)(TREE *tree, TYPE *item) \ -{ tree->root = STB__(N,remove)(tree->root, item); } \ -TYPE *STB__(M,Next)(TREE *tree, TYPE *item) \ -{ return STB__(N,next)(tree->root, item); } \ -TYPE *STB__(M,Prev)(TREE *tree, TYPE *item) \ -{ return STB__(N,prev)(tree->root, item); } \ -TYPE *STB__(M,First)(TREE *tree) { return STB__(N,first)(tree->root); } \ -TYPE *STB__(M,Last) (TREE *tree) { return STB__(N,last) (tree->root); } \ -void STB__(M,Init)(TREE *tree) { tree->root = NULL; } - - -#define stb_bst_find(N,tree,fcompare) \ -{ \ - int c; \ - while (tree != NULL) { \ - fcompare \ - if (c == 0) return tree; \ - if (c < 0) tree = tree->STB_(N,left); \ - else tree = tree->STB_(N,right); \ - } \ - return NULL; \ -} - -#define stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,PAR) \ - stb_bst_base(TYPE,N,TREE,M, \ - VTYPE a = p->vfield; VTYPE b = q->vfield; return (compare);, PAR ) \ - \ -TYPE *STB__(N,find)(TYPE *tree, VTYPE a) \ - stb_bst_find(N,tree,VTYPE b = tree->vfield; c = (compare);) \ -TYPE *STB__(M,Find)(TREE *tree, VTYPE a) \ -{ return STB__(N,find)(tree->root, a); } - -#define stb_bst(TYPE,N,TREE,M,vfield,VTYPE,compare) \ - stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,stb__bst_noparent) -#define stb_bst_parent(TYPE,N,TREE,M,vfield,VTYPE,compare) \ - stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,stb__bst_parent) - - - -////////////////////////////////////////////////////////////////////////////// -// -// Pointer Nulling -// -// This lets you automatically NULL dangling pointers to "registered" -// objects. Note that you have to make sure you call the appropriate -// functions when you free or realloc blocks of memory that contain -// pointers or pointer targets. stb.h can automatically do this for -// stb_arr, or for all frees/reallocs if it's wrapping them. -// - -#ifdef STB_NPTR - -STB_EXTERN void stb_nptr_set(void *address_of_pointer, void *value_to_write); -STB_EXTERN void stb_nptr_didset(void *address_of_pointer); - -STB_EXTERN void stb_nptr_didfree(void *address_being_freed, int len); -STB_EXTERN void stb_nptr_free(void *address_being_freed, int len); - -STB_EXTERN void stb_nptr_didrealloc(void *new_address, void *old_address, int len); -STB_EXTERN void stb_nptr_recache(void); // recache all known pointers - // do this after pointer sets outside your control, slow - -#ifdef STB_DEFINE -// for fast updating on free/realloc, we need to be able to find -// all the objects (pointers and targets) within a given block; -// this precludes hashing - -// we use a three-level hierarchy of memory to minimize storage: -// level 1: 65536 pointers to stb__memory_node (always uses 256 KB) -// level 2: each stb__memory_node represents a 64K block of memory -// with 256 stb__memory_leafs (worst case 64MB) -// level 3: each stb__memory_leaf represents 256 bytes of memory -// using a list of target locations and a list of pointers -// (which are hopefully fairly short normally!) - -// this approach won't work in 64-bit, which has a much larger address -// space. need to redesign - -#define STB__NPTR_ROOT_LOG2 16 -#define STB__NPTR_ROOT_NUM (1 << STB__NPTR_ROOT_LOG2) -#define STB__NPTR_ROOT_SHIFT (32 - STB__NPTR_ROOT_LOG2) - -#define STB__NPTR_NODE_LOG2 5 -#define STB__NPTR_NODE_NUM (1 << STB__NPTR_NODE_LOG2) -#define STB__NPTR_NODE_MASK (STB__NPTR_NODE_NUM-1) -#define STB__NPTR_NODE_SHIFT (STB__NPTR_ROOT_SHIFT - STB__NPTR_NODE_LOG2) -#define STB__NPTR_NODE_OFFSET(x) (((x) >> STB__NPTR_NODE_SHIFT) & STB__NPTR_NODE_MASK) - -typedef struct stb__st_nptr -{ - void *ptr; // address of actual pointer - struct stb__st_nptr *next; // next pointer with same target - struct stb__st_nptr **prev; // prev pointer with same target, address of 'next' field (or first) - struct stb__st_nptr *next_in_block; -} stb__nptr; - -typedef struct stb__st_nptr_target -{ - void *ptr; // address of target - stb__nptr *first; // address of first nptr pointing to this - struct stb__st_nptr_target *next_in_block; -} stb__nptr_target; - -typedef struct -{ - stb__nptr *pointers; - stb__nptr_target *targets; -} stb__memory_leaf; - -typedef struct -{ - stb__memory_leaf *children[STB__NPTR_NODE_NUM]; -} stb__memory_node; - -stb__memory_node *stb__memtab_root[STB__NPTR_ROOT_NUM]; - -static stb__memory_leaf *stb__nptr_find_leaf(void *mem) -{ - stb_uint32 address = (stb_uint32) mem; - stb__memory_node *z = stb__memtab_root[address >> STB__NPTR_ROOT_SHIFT]; - if (z) - return z->children[STB__NPTR_NODE_OFFSET(address)]; - else - return NULL; -} - -static void * stb__nptr_alloc(int size) -{ - return stb__realloc_raw(0,size); -} - -static void stb__nptr_free(void *p) -{ - stb__realloc_raw(p,0); -} - -static stb__memory_leaf *stb__nptr_make_leaf(void *mem) -{ - stb_uint32 address = (stb_uint32) mem; - stb__memory_node *z = stb__memtab_root[address >> STB__NPTR_ROOT_SHIFT]; - stb__memory_leaf *f; - if (!z) { - int i; - z = (stb__memory_node *) stb__nptr_alloc(sizeof(*stb__memtab_root[0])); - stb__memtab_root[address >> STB__NPTR_ROOT_SHIFT] = z; - for (i=0; i < 256; ++i) - z->children[i] = 0; - } - f = (stb__memory_leaf *) stb__nptr_alloc(sizeof(*f)); - z->children[STB__NPTR_NODE_OFFSET(address)] = f; - f->pointers = NULL; - f->targets = NULL; - return f; -} - -static stb__nptr_target *stb__nptr_find_target(void *target, int force) -{ - stb__memory_leaf *p = stb__nptr_find_leaf(target); - if (p) { - stb__nptr_target *t = p->targets; - while (t) { - if (t->ptr == target) - return t; - t = t->next_in_block; - } - } - if (force) { - stb__nptr_target *t = (stb__nptr_target*) stb__nptr_alloc(sizeof(*t)); - if (!p) p = stb__nptr_make_leaf(target); - t->ptr = target; - t->first = NULL; - t->next_in_block = p->targets; - p->targets = t; - return t; - } else - return NULL; -} - -static stb__nptr *stb__nptr_find_pointer(void *ptr, int force) -{ - stb__memory_leaf *p = stb__nptr_find_leaf(ptr); - if (p) { - stb__nptr *t = p->pointers; - while (t) { - if (t->ptr == ptr) - return t; - t = t->next_in_block; - } - } - if (force) { - stb__nptr *t = (stb__nptr *) stb__nptr_alloc(sizeof(*t)); - if (!p) p = stb__nptr_make_leaf(ptr); - t->ptr = ptr; - t->next = NULL; - t->prev = NULL; - t->next_in_block = p->pointers; - p->pointers = t; - return t; - } else - return NULL; -} - -void stb_nptr_set(void *address_of_pointer, void *value_to_write) -{ - if (*(void **)address_of_pointer != value_to_write) { - *(void **) address_of_pointer = value_to_write; - stb_nptr_didset(address_of_pointer); - } -} - -void stb_nptr_didset(void *address_of_pointer) -{ - // first unlink from old chain - void *new_address; - stb__nptr *p = stb__nptr_find_pointer(address_of_pointer, 1); // force building if doesn't exist - if (p->prev) { // if p->prev is NULL, we just built it, or it was NULL - *(p->prev) = p->next; - if (p->next) p->next->prev = p->prev; - } - // now add to new chain - new_address = *(void **)address_of_pointer; - if (new_address != NULL) { - stb__nptr_target *t = stb__nptr_find_target(new_address, 1); - p->next = t->first; - if (p->next) p->next->prev = &p->next; - p->prev = &t->first; - t->first = p; - } else { - p->prev = NULL; - p->next = NULL; - } -} - -void stb__nptr_block(void *address, int len, void (*function)(stb__memory_leaf *f, int datum, void *start, void *end), int datum) -{ - void *end_address = (void *) ((char *) address + len - 1); - stb__memory_node *n; - stb_uint32 start = (stb_uint32) address; - stb_uint32 end = start + len - 1; - - int b0 = start >> STB__NPTR_ROOT_SHIFT; - int b1 = end >> STB__NPTR_ROOT_SHIFT; - int b=b0,i,e0,e1; - - e0 = STB__NPTR_NODE_OFFSET(start); - - if (datum <= 0) { - // first block - n = stb__memtab_root[b0]; - if (n) { - if (b0 != b1) - e1 = STB__NPTR_NODE_NUM-1; - else - e1 = STB__NPTR_NODE_OFFSET(end); - for (i=e0; i <= e1; ++i) - if (n->children[i]) - function(n->children[i], datum, address, end_address); - } - if (b1 > b0) { - // blocks other than the first and last block - for (b=b0+1; b < b1; ++b) { - n = stb__memtab_root[b]; - if (n) - for (i=0; i <= STB__NPTR_NODE_NUM-1; ++i) - if (n->children[i]) - function(n->children[i], datum, address, end_address); - } - // last block - n = stb__memtab_root[b1]; - if (n) { - e1 = STB__NPTR_NODE_OFFSET(end); - for (i=0; i <= e1; ++i) - if (n->children[i]) - function(n->children[i], datum, address, end_address); - } - } - } else { - if (b1 > b0) { - // last block - n = stb__memtab_root[b1]; - if (n) { - e1 = STB__NPTR_NODE_OFFSET(end); - for (i=e1; i >= 0; --i) - if (n->children[i]) - function(n->children[i], datum, address, end_address); - } - // blocks other than the first and last block - for (b=b1-1; b > b0; --b) { - n = stb__memtab_root[b]; - if (n) - for (i=STB__NPTR_NODE_NUM-1; i >= 0; --i) - if (n->children[i]) - function(n->children[i], datum, address, end_address); - } - } - // first block - n = stb__memtab_root[b0]; - if (n) { - if (b0 != b1) - e1 = STB__NPTR_NODE_NUM-1; - else - e1 = STB__NPTR_NODE_OFFSET(end); - for (i=e1; i >= e0; --i) - if (n->children[i]) - function(n->children[i], datum, address, end_address); - } - } -} - -static void stb__nptr_delete_pointers(stb__memory_leaf *f, int offset, void *start, void *end) -{ - stb__nptr **p = &f->pointers; - while (*p) { - stb__nptr *n = *p; - if (n->ptr >= start && n->ptr <= end) { - // unlink - if (n->prev) { - *(n->prev) = n->next; - if (n->next) n->next->prev = n->prev; - } - *p = n->next_in_block; - stb__nptr_free(n); - } else - p = &(n->next_in_block); - } -} - -static void stb__nptr_delete_targets(stb__memory_leaf *f, int offset, void *start, void *end) -{ - stb__nptr_target **p = &f->targets; - while (*p) { - stb__nptr_target *n = *p; - if (n->ptr >= start && n->ptr <= end) { - // null pointers - stb__nptr *z = n->first; - while (z) { - stb__nptr *y = z->next; - z->prev = NULL; - z->next = NULL; - *(void **) z->ptr = NULL; - z = y; - } - // unlink this target - *p = n->next_in_block; - stb__nptr_free(n); - } else - p = &(n->next_in_block); - } -} - -void stb_nptr_didfree(void *address_being_freed, int len) -{ - // step one: delete all pointers in this block - stb__nptr_block(address_being_freed, len, stb__nptr_delete_pointers, 0); - // step two: NULL all pointers to this block; do this second to avoid NULLing deleted pointers - stb__nptr_block(address_being_freed, len, stb__nptr_delete_targets, 0); -} - -void stb_nptr_free(void *address_being_freed, int len) -{ - free(address_being_freed); - stb_nptr_didfree(address_being_freed, len); -} - -static void stb__nptr_move_targets(stb__memory_leaf *f, int offset, void *start, void *end) -{ - stb__nptr_target **t = &f->targets; - while (*t) { - stb__nptr_target *n = *t; - if (n->ptr >= start && n->ptr <= end) { - stb__nptr *z; - stb__memory_leaf *f; - // unlink n - *t = n->next_in_block; - // update n to new address - n->ptr = (void *) ((char *) n->ptr + offset); - f = stb__nptr_find_leaf(n->ptr); - if (!f) f = stb__nptr_make_leaf(n->ptr); - n->next_in_block = f->targets; - f->targets = n; - // now go through all pointers and make them point here - z = n->first; - while (z) { - *(void**) z->ptr = n->ptr; - z = z->next; - } - } else - t = &(n->next_in_block); - } -} - -static void stb__nptr_move_pointers(stb__memory_leaf *f, int offset, void *start, void *end) -{ - stb__nptr **p = &f->pointers; - while (*p) { - stb__nptr *n = *p; - if (n->ptr >= start && n->ptr <= end) { - // unlink - *p = n->next_in_block; - n->ptr = (void *) ((int) n->ptr + offset); - // move to new block - f = stb__nptr_find_leaf(n->ptr); - if (!f) f = stb__nptr_make_leaf(n->ptr); - n->next_in_block = f->pointers; - f->pointers = n; - } else - p = &(n->next_in_block); - } -} - -void stb_nptr_realloc(void *new_address, void *old_address, int len) -{ - if (new_address == old_address) return; - - // have to move the pointers first, because moving the targets - // requires writing to the pointers-to-the-targets, and if some of those moved too, - // we need to make sure we don't write to the old memory - - // step one: move all pointers within the block - stb__nptr_block(old_address, len, stb__nptr_move_pointers, (char *) new_address - (char *) old_address); - // step two: move all targets within the block - stb__nptr_block(old_address, len, stb__nptr_move_targets, (char *) new_address - (char *) old_address); -} - -void stb_nptr_move(void *new_address, void *old_address) -{ - stb_nptr_realloc(new_address, old_address, 1); -} - -void stb_nptr_recache(void) -{ - int i,j; - for (i=0; i < STB__NPTR_ROOT_NUM; ++i) - if (stb__memtab_root[i]) - for (j=0; j < STB__NPTR_NODE_NUM; ++j) - if (stb__memtab_root[i]->children[j]) { - stb__nptr *p = stb__memtab_root[i]->children[j]->pointers; - while (p) { - stb_nptr_didset(p->ptr); - p = p->next_in_block; - } - } -} - -#endif // STB_DEFINE -#endif // STB_NPTR - - -////////////////////////////////////////////////////////////////////////////// -// -// File Processing -// - - -#ifdef _WIN32 - #define stb_rename(x,y) _wrename((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y)) -#else - #define stb_rename rename -#endif - -STB_EXTERN void stb_fput_varlen64(FILE *f, stb_uint64 v); -STB_EXTERN stb_uint64 stb_fget_varlen64(FILE *f); -STB_EXTERN int stb_size_varlen64(stb_uint64 v); - - -#define stb_filec (char *) stb_file -#define stb_fileu (unsigned char *) stb_file -STB_EXTERN void * stb_file(char *filename, size_t *length); -STB_EXTERN void * stb_file_max(char *filename, size_t *length); -STB_EXTERN size_t stb_filelen(FILE *f); -STB_EXTERN int stb_filewrite(char *filename, void *data, size_t length); -STB_EXTERN int stb_filewritestr(char *filename, char *data); -STB_EXTERN char ** stb_stringfile(char *filename, int *len); -STB_EXTERN char ** stb_stringfile_trimmed(char *name, int *len, char comm); -STB_EXTERN char * stb_fgets(char *buffer, int buflen, FILE *f); -STB_EXTERN char * stb_fgets_malloc(FILE *f); -STB_EXTERN int stb_fexists(char *filename); -STB_EXTERN int stb_fcmp(char *s1, char *s2); -STB_EXTERN int stb_feq(char *s1, char *s2); -STB_EXTERN time_t stb_ftimestamp(char *filename); - -STB_EXTERN int stb_fullpath(char *abs, int abs_size, char *rel); -STB_EXTERN FILE * stb_fopen(char *filename, const char *mode); -STB_EXTERN int stb_fclose(FILE *f, int keep); - -enum -{ - stb_keep_no = 0, - stb_keep_yes = 1, - stb_keep_if_different = 2, -}; - -STB_EXTERN int stb_copyfile(char *src, char *dest); - -STB_EXTERN void stb_fput_varlen64(FILE *f, stb_uint64 v); -STB_EXTERN stb_uint64 stb_fget_varlen64(FILE *f); -STB_EXTERN int stb_size_varlen64(stb_uint64 v); - -STB_EXTERN void stb_fwrite32(FILE *f, stb_uint32 datum); -STB_EXTERN void stb_fput_varlen (FILE *f, int v); -STB_EXTERN void stb_fput_varlenu(FILE *f, unsigned int v); -STB_EXTERN int stb_fget_varlen (FILE *f); -STB_EXTERN stb_uint stb_fget_varlenu(FILE *f); -STB_EXTERN void stb_fput_ranged (FILE *f, int v, int b, stb_uint n); -STB_EXTERN int stb_fget_ranged (FILE *f, int b, stb_uint n); -STB_EXTERN int stb_size_varlen (int v); -STB_EXTERN int stb_size_varlenu(unsigned int v); -STB_EXTERN int stb_size_ranged (int b, stb_uint n); - -STB_EXTERN int stb_fread(void *data, size_t len, size_t count, void *f); -STB_EXTERN int stb_fwrite(void *data, size_t len, size_t count, void *f); - -#if 0 -typedef struct -{ - FILE *base_file; - char *buffer; - int buffer_size; - int buffer_off; - int buffer_left; -} STBF; - -STB_EXTERN STBF *stb_tfopen(char *filename, char *mode); -STB_EXTERN int stb_tfread(void *data, size_t len, size_t count, STBF *f); -STB_EXTERN int stb_tfwrite(void *data, size_t len, size_t count, STBF *f); -#endif - -#ifdef STB_DEFINE - -#if 0 -STBF *stb_tfopen(char *filename, char *mode) -{ - STBF *z; - FILE *f = stb_p_fopen(filename, mode); - if (!f) return NULL; - z = (STBF *) malloc(sizeof(*z)); - if (!z) { fclose(f); return NULL; } - z->base_file = f; - if (!strcmp(mode, "rb") || !strcmp(mode, "wb")) { - z->buffer_size = 4096; - z->buffer_off = z->buffer_size; - z->buffer_left = 0; - z->buffer = malloc(z->buffer_size); - if (!z->buffer) { free(z); fclose(f); return NULL; } - } else { - z->buffer = 0; - z->buffer_size = 0; - z->buffer_left = 0; - } - return z; -} - -int stb_tfread(void *data, size_t len, size_t count, STBF *f) -{ - int total = len*count, done=0; - if (!total) return 0; - if (total <= z->buffer_left) { - memcpy(data, z->buffer + z->buffer_off, total); - z->buffer_off += total; - z->buffer_left -= total; - return count; - } else { - char *out = (char *) data; - - // consume all buffered data - memcpy(data, z->buffer + z->buffer_off, z->buffer_left); - done = z->buffer_left; - out += z->buffer_left; - z->buffer_left=0; - - if (total-done > (z->buffer_size >> 1)) { - done += fread(out - } - } -} -#endif - -void stb_fwrite32(FILE *f, stb_uint32 x) -{ - fwrite(&x, 4, 1, f); -} - -#if defined(_WIN32) - #define stb__stat _stat -#else - #define stb__stat stat -#endif - -int stb_fexists(char *filename) -{ - struct stb__stat buf; - return stb__windows( - _wstat((const wchar_t *)stb__from_utf8(filename), &buf), - stat(filename,&buf) - ) == 0; -} - -time_t stb_ftimestamp(char *filename) -{ - struct stb__stat buf; - if (stb__windows( - _wstat((const wchar_t *)stb__from_utf8(filename), &buf), - stat(filename,&buf) - ) == 0) - { - return buf.st_mtime; - } else { - return 0; - } -} - -size_t stb_filelen(FILE *f) -{ - long len, pos; - pos = ftell(f); - fseek(f, 0, SEEK_END); - len = ftell(f); - fseek(f, pos, SEEK_SET); - return (size_t) len; -} - -void *stb_file(char *filename, size_t *length) -{ - FILE *f = stb__fopen(filename, "rb"); - char *buffer; - size_t len, len2; - if (!f) return NULL; - len = stb_filelen(f); - buffer = (char *) malloc(len+2); // nul + extra - len2 = fread(buffer, 1, len, f); - if (len2 == len) { - if (length) *length = len; - buffer[len] = 0; - } else { - free(buffer); - buffer = NULL; - } - fclose(f); - return buffer; -} - -int stb_filewrite(char *filename, void *data, size_t length) -{ - FILE *f = stb_fopen(filename, "wb"); - if (f) { - unsigned char *data_ptr = (unsigned char *) data; - size_t remaining = length; - while (remaining > 0) { - size_t len2 = remaining > 65536 ? 65536 : remaining; - size_t len3 = fwrite(data_ptr, 1, len2, f); - if (len2 != len3) { - fprintf(stderr, "Failed while writing %s\n", filename); - break; - } - remaining -= len2; - data_ptr += len2; - } - stb_fclose(f, stb_keep_if_different); - } - return f != NULL; -} - -int stb_filewritestr(char *filename, char *data) -{ - return stb_filewrite(filename, data, strlen(data)); -} - -void * stb_file_max(char *filename, size_t *length) -{ - FILE *f = stb__fopen(filename, "rb"); - char *buffer; - size_t len, maxlen; - if (!f) return NULL; - maxlen = *length; - buffer = (char *) malloc(maxlen+1); - len = fread(buffer, 1, maxlen, f); - buffer[len] = 0; - fclose(f); - *length = len; - return buffer; -} - -char ** stb_stringfile(char *filename, int *plen) -{ - FILE *f = stb__fopen(filename, "rb"); - char *buffer, **list=NULL, *s; - size_t len, count, i; - - if (!f) return NULL; - len = stb_filelen(f); - buffer = (char *) malloc(len+1); - len = fread(buffer, 1, len, f); - buffer[len] = 0; - fclose(f); - - // two passes through: first time count lines, second time set them - for (i=0; i < 2; ++i) { - s = buffer; - if (i == 1) - list[0] = s; - count = 1; - while (*s) { - if (*s == '\n' || *s == '\r') { - // detect if both cr & lf are together - int crlf = (s[0] + s[1]) == ('\n' + '\r'); - if (i == 1) *s = 0; - if (crlf) ++s; - if (s[1]) { // it's not over yet - if (i == 1) list[count] = s+1; - ++count; - } - } - ++s; - } - if (i == 0) { - list = (char **) malloc(sizeof(*list) * (count+1) + len+1); - if (!list) return NULL; - list[count] = 0; - // recopy the file so there's just a single allocation to free - memcpy(&list[count+1], buffer, len+1); - free(buffer); - buffer = (char *) &list[count+1]; - if (plen) *plen = (int) count; - } - } - return list; -} - -char ** stb_stringfile_trimmed(char *name, int *len, char comment) -{ - int i,n,o=0; - char **s = stb_stringfile(name, &n); - if (s == NULL) return NULL; - for (i=0; i < n; ++i) { - char *p = stb_skipwhite(s[i]); - if (*p && *p != comment) - s[o++] = p; - } - s[o] = NULL; - if (len) *len = o; - return s; -} - -char * stb_fgets(char *buffer, int buflen, FILE *f) -{ - char *p; - buffer[0] = 0; - p = fgets(buffer, buflen, f); - if (p) { - int n = (int) (strlen(p)-1); - if (n >= 0) - if (p[n] == '\n') - p[n] = 0; - } - return p; -} - -char * stb_fgets_malloc(FILE *f) -{ - // avoid reallocing for small strings - char quick_buffer[800]; - quick_buffer[sizeof(quick_buffer)-2] = 0; - if (!fgets(quick_buffer, sizeof(quick_buffer), f)) - return NULL; - - if (quick_buffer[sizeof(quick_buffer)-2] == 0) { - size_t n = strlen(quick_buffer); - if (n > 0 && quick_buffer[n-1] == '\n') - quick_buffer[n-1] = 0; - return stb_p_strdup(quick_buffer); - } else { - char *p; - char *a = stb_p_strdup(quick_buffer); - size_t len = sizeof(quick_buffer)-1; - - while (!feof(f)) { - if (a[len-1] == '\n') break; - a = (char *) realloc(a, len*2); - p = &a[len]; - p[len-2] = 0; - if (!fgets(p, (int) len, f)) - break; - if (p[len-2] == 0) { - len += strlen(p); - break; - } - len = len + (len-1); - } - if (a[len-1] == '\n') - a[len-1] = 0; - return a; - } -} - -int stb_fullpath(char *abs, int abs_size, char *rel) -{ - #ifdef _WIN32 - return _fullpath(abs, rel, abs_size) != NULL; - #else - if (rel[0] == '/' || rel[0] == '~') { - if ((int) strlen(rel) >= abs_size) - return 0; - stb_p_strcpy_s(abs,65536,rel); - return STB_TRUE; - } else { - int n; - getcwd(abs, abs_size); - n = strlen(abs); - if (n+(int) strlen(rel)+2 <= abs_size) { - abs[n] = '/'; - stb_p_strcpy_s(abs+n+1, 65536,rel); - return STB_TRUE; - } else { - return STB_FALSE; - } - } - #endif -} - -static int stb_fcmp_core(FILE *f, FILE *g) -{ - char buf1[1024],buf2[1024]; - int n1,n2, res=0; - - while (1) { - n1 = (int) fread(buf1, 1, sizeof(buf1), f); - n2 = (int) fread(buf2, 1, sizeof(buf2), g); - res = memcmp(buf1,buf2,stb_min(n1,n2)); - if (res) - break; - if (n1 != n2) { - res = n1 < n2 ? -1 : 1; - break; - } - if (n1 == 0) - break; - } - - fclose(f); - fclose(g); - return res; -} - -int stb_fcmp(char *s1, char *s2) -{ - FILE *f = stb__fopen(s1, "rb"); - FILE *g = stb__fopen(s2, "rb"); - - if (f == NULL || g == NULL) { - if (f) fclose(f); - if (g) { - fclose(g); - return STB_TRUE; - } - return f != NULL; - } - - return stb_fcmp_core(f,g); -} - -int stb_feq(char *s1, char *s2) -{ - FILE *f = stb__fopen(s1, "rb"); - FILE *g = stb__fopen(s2, "rb"); - - if (f == NULL || g == NULL) { - if (f) fclose(f); - if (g) fclose(g); - return f == g; - } - - // feq is faster because it shortcuts if they're different length - if (stb_filelen(f) != stb_filelen(g)) { - fclose(f); - fclose(g); - return 0; - } - - return !stb_fcmp_core(f,g); -} - -static stb_ptrmap *stb__files; - -typedef struct -{ - char *temp_name; - char *name; - int errors; -} stb__file_data; - -static FILE *stb__open_temp_file(char *temp_name, char *src_name, const char *mode) -{ - size_t p; -#ifdef _MSC_VER - int j; -#endif - FILE *f; - // try to generate a temporary file in the same directory - p = strlen(src_name)-1; - while (p > 0 && src_name[p] != '/' && src_name[p] != '\\' - && src_name[p] != ':' && src_name[p] != '~') - --p; - ++p; - - memcpy(temp_name, src_name, p); - - #ifdef _MSC_VER - // try multiple times to make a temp file... just in - // case some other process makes the name first - for (j=0; j < 32; ++j) { - stb_p_strcpy_s(temp_name+p, 65536, "stmpXXXXXX"); - if (!stb_p_mktemp(temp_name)) - return 0; - - f = stb_p_fopen(temp_name, mode); - if (f != NULL) - break; - } - #else - { - stb_p_strcpy_s(temp_name+p, 65536, "stmpXXXXXX"); - #ifdef __MINGW32__ - int fd = open(stb_p_mktemp(temp_name), O_RDWR); - #else - int fd = mkstemp(temp_name); - #endif - if (fd == -1) return NULL; - f = fdopen(fd, mode); - if (f == NULL) { - unlink(temp_name); - close(fd); - return NULL; - } - } - #endif - return f; -} - - -FILE * stb_fopen(char *filename, const char *mode) -{ - FILE *f; - char name_full[4096]; - char temp_full[sizeof(name_full) + 12]; - - // @TODO: if the file doesn't exist, we can also use the fastpath here - if (mode[0] != 'w' && !strchr(mode, '+')) - return stb__fopen(filename, mode); - - // save away the full path to the file so if the program - // changes the cwd everything still works right! unix has - // better ways to do this, but we have to work in windows - name_full[0] = '\0'; // stb_fullpath reads name_full[0] - if (stb_fullpath(name_full, sizeof(name_full), filename)==0) - return 0; - - f = stb__open_temp_file(temp_full, name_full, mode); - if (f != NULL) { - stb__file_data *d = (stb__file_data *) malloc(sizeof(*d)); - if (!d) { assert(0); /* NOTREACHED */fclose(f); return NULL; } - if (stb__files == NULL) stb__files = stb_ptrmap_create(); - d->temp_name = stb_p_strdup(temp_full); - d->name = stb_p_strdup(name_full); - d->errors = 0; - stb_ptrmap_add(stb__files, f, d); - return f; - } - - return NULL; -} - -int stb_fclose(FILE *f, int keep) -{ - stb__file_data *d; - - int ok = STB_FALSE; - if (f == NULL) return 0; - - if (ferror(f)) - keep = stb_keep_no; - - fclose(f); - - if (stb__files && stb_ptrmap_remove(stb__files, f, (void **) &d)) { - if (stb__files->count == 0) { - stb_ptrmap_destroy(stb__files); - stb__files = NULL; - } - } else - return STB_TRUE; // not special - - if (keep == stb_keep_if_different) { - // check if the files are identical - if (stb_feq(d->name, d->temp_name)) { - keep = stb_keep_no; - ok = STB_TRUE; // report success if no change - } - } - - if (keep == stb_keep_no) { - remove(d->temp_name); - } else { - if (!stb_fexists(d->name)) { - // old file doesn't exist, so just move the new file over it - stb_rename(d->temp_name, d->name); - } else { - // don't delete the old file yet in case there are troubles! First rename it! - char preserved_old_file[4096]; - - // generate a temp filename in the same directory (also creates it, which we don't need) - FILE *dummy = stb__open_temp_file(preserved_old_file, d->name, "wb"); - if (dummy != NULL) { - // we don't actually want the open file - fclose(dummy); - - // discard what we just created - remove(preserved_old_file); // if this fails, there's nothing we can do, and following logic handles it as best as possible anyway - - // move the existing file to the preserved name - if (0 != stb_rename(d->name, preserved_old_file)) { // 0 on success - // failed, state is: - // filename -> old file - // tempname -> new file - // keep tempname around so we don't lose data - } else { - // state is: - // preserved -> old file - // tempname -> new file - // move the new file to the old name - if (0 == stb_rename(d->temp_name, d->name)) { - // state is: - // preserved -> old file - // filename -> new file - ok = STB_TRUE; - - // 'filename -> new file' has always been the goal, so clean up - remove(preserved_old_file); // nothing to be done if it fails - } else { - // couldn't rename, so try renaming preserved file back - - // state is: - // preserved -> old file - // tempname -> new file - stb_rename(preserved_old_file, d->name); - // if the rename failed, there's nothing more we can do - } - } - } else { - // we couldn't get a temp filename. do this the naive way; the worst case failure here - // leaves the filename pointing to nothing and the new file as a tempfile - remove(d->name); - stb_rename(d->temp_name, d->name); - } - } - } - - free(d->temp_name); - free(d->name); - free(d); - - return ok; -} - -int stb_copyfile(char *src, char *dest) -{ - char raw_buffer[1024]; - char *buffer; - int buf_size = 65536; - - FILE *f, *g; - - // if file already exists at destination, do nothing - if (stb_feq(src, dest)) return STB_TRUE; - - // open file - f = stb__fopen(src, "rb"); - if (f == NULL) return STB_FALSE; - - // open file for writing - g = stb__fopen(dest, "wb"); - if (g == NULL) { - fclose(f); - return STB_FALSE; - } - - buffer = (char *) malloc(buf_size); - if (buffer == NULL) { - buffer = raw_buffer; - buf_size = sizeof(raw_buffer); - } - - while (!feof(f)) { - size_t n = fread(buffer, 1, buf_size, f); - if (n != 0) - fwrite(buffer, 1, n, g); - } - - fclose(f); - if (buffer != raw_buffer) - free(buffer); - - fclose(g); - return STB_TRUE; -} - -// varlen: -// v' = (v >> 31) + (v < 0 ? ~v : v)<<1; // small abs(v) => small v' -// output v as big endian v'+k for v' <= k: -// 1 byte : v' <= 0x00000080 ( -64 <= v < 64) 7 bits -// 2 bytes: v' <= 0x00004000 (-8192 <= v < 8192) 14 bits -// 3 bytes: v' <= 0x00200000 21 bits -// 4 bytes: v' <= 0x10000000 28 bits -// the number of most significant 1-bits in the first byte -// equals the number of bytes after the first - -#define stb__varlen_xform(v) (v<0 ? (~v << 1)+1 : (v << 1)) - -int stb_size_varlen(int v) { return stb_size_varlenu(stb__varlen_xform(v)); } -int stb_size_varlenu(unsigned int v) -{ - if (v < 0x00000080) return 1; - if (v < 0x00004000) return 2; - if (v < 0x00200000) return 3; - if (v < 0x10000000) return 4; - return 5; -} - -void stb_fput_varlen(FILE *f, int v) { stb_fput_varlenu(f, stb__varlen_xform(v)); } - -void stb_fput_varlenu(FILE *f, unsigned int z) -{ - if (z >= 0x10000000) fputc(0xF0,f); - if (z >= 0x00200000) fputc((z < 0x10000000 ? 0xE0 : 0)+(z>>24),f); - if (z >= 0x00004000) fputc((z < 0x00200000 ? 0xC0 : 0)+(z>>16),f); - if (z >= 0x00000080) fputc((z < 0x00004000 ? 0x80 : 0)+(z>> 8),f); - fputc(z,f); -} - -#define stb_fgetc(f) ((unsigned char) fgetc(f)) - -int stb_fget_varlen(FILE *f) -{ - unsigned int z = stb_fget_varlenu(f); - return (z & 1) ? ~(z>>1) : (z>>1); -} - -unsigned int stb_fget_varlenu(FILE *f) -{ - unsigned int z; - unsigned char d; - d = stb_fgetc(f); - - if (d >= 0x80) { - if (d >= 0xc0) { - if (d >= 0xe0) { - if (d == 0xf0) z = stb_fgetc(f) << 24; - else z = (d - 0xe0) << 24; - z += stb_fgetc(f) << 16; - } - else - z = (d - 0xc0) << 16; - z += stb_fgetc(f) << 8; - } else - z = (d - 0x80) << 8; - z += stb_fgetc(f); - } else - z = d; - return z; -} - -stb_uint64 stb_fget_varlen64(FILE *f) -{ - stb_uint64 z; - unsigned char d; - d = stb_fgetc(f); - - if (d >= 0x80) { - if (d >= 0xc0) { - if (d >= 0xe0) { - if (d >= 0xf0) { - if (d >= 0xf8) { - if (d >= 0xfc) { - if (d >= 0xfe) { - if (d >= 0xff) - z = (stb_uint64) stb_fgetc(f) << 56; - else - z = (stb_uint64) (d - 0xfe) << 56; - z |= (stb_uint64) stb_fgetc(f) << 48; - } else z = (stb_uint64) (d - 0xfc) << 48; - z |= (stb_uint64) stb_fgetc(f) << 40; - } else z = (stb_uint64) (d - 0xf8) << 40; - z |= (stb_uint64) stb_fgetc(f) << 32; - } else z = (stb_uint64) (d - 0xf0) << 32; - z |= (stb_uint) stb_fgetc(f) << 24; - } else z = (stb_uint) (d - 0xe0) << 24; - z |= (stb_uint) stb_fgetc(f) << 16; - } else z = (stb_uint) (d - 0xc0) << 16; - z |= (stb_uint) stb_fgetc(f) << 8; - } else z = (stb_uint) (d - 0x80) << 8; - z |= stb_fgetc(f); - } else - z = d; - - return (z & 1) ? ~(z >> 1) : (z >> 1); -} - -int stb_size_varlen64(stb_uint64 v) -{ - if (v < 0x00000080) return 1; - if (v < 0x00004000) return 2; - if (v < 0x00200000) return 3; - if (v < 0x10000000) return 4; - if (v < STB_IMM_UINT64(0x0000000800000000)) return 5; - if (v < STB_IMM_UINT64(0x0000040000000000)) return 6; - if (v < STB_IMM_UINT64(0x0002000000000000)) return 7; - if (v < STB_IMM_UINT64(0x0100000000000000)) return 8; - return 9; -} - -void stb_fput_varlen64(FILE *f, stb_uint64 v) -{ - stb_uint64 z = stb__varlen_xform(v); - int first=1; - if (z >= STB_IMM_UINT64(0x100000000000000)) { - fputc(0xff,f); - first=0; - } - if (z >= STB_IMM_UINT64(0x02000000000000)) fputc((first ? 0xFE : 0)+(char)(z>>56),f), first=0; - if (z >= STB_IMM_UINT64(0x00040000000000)) fputc((first ? 0xFC : 0)+(char)(z>>48),f), first=0; - if (z >= STB_IMM_UINT64(0x00000800000000)) fputc((first ? 0xF8 : 0)+(char)(z>>40),f), first=0; - if (z >= STB_IMM_UINT64(0x00000010000000)) fputc((first ? 0xF0 : 0)+(char)(z>>32),f), first=0; - if (z >= STB_IMM_UINT64(0x00000000200000)) fputc((first ? 0xE0 : 0)+(char)(z>>24),f), first=0; - if (z >= STB_IMM_UINT64(0x00000000004000)) fputc((first ? 0xC0 : 0)+(char)(z>>16),f), first=0; - if (z >= STB_IMM_UINT64(0x00000000000080)) fputc((first ? 0x80 : 0)+(char)(z>> 8),f), first=0; - fputc((char)z,f); -} - -void stb_fput_ranged(FILE *f, int v, int b, stb_uint n) -{ - v -= b; - if (n <= (1 << 31)) - assert((stb_uint) v < n); - if (n > (1 << 24)) fputc(v >> 24, f); - if (n > (1 << 16)) fputc(v >> 16, f); - if (n > (1 << 8)) fputc(v >> 8, f); - fputc(v,f); -} - -int stb_fget_ranged(FILE *f, int b, stb_uint n) -{ - unsigned int v=0; - if (n > (1 << 24)) v += stb_fgetc(f) << 24; - if (n > (1 << 16)) v += stb_fgetc(f) << 16; - if (n > (1 << 8)) v += stb_fgetc(f) << 8; - v += stb_fgetc(f); - return b+v; -} - -int stb_size_ranged(int b, stb_uint n) -{ - if (n > (1 << 24)) return 4; - if (n > (1 << 16)) return 3; - if (n > (1 << 8)) return 2; - return 1; -} - -void stb_fput_string(FILE *f, char *s) -{ - size_t len = strlen(s); - stb_fput_varlenu(f, (unsigned int) len); - fwrite(s, 1, len, f); -} - -// inverse of the above algorithm -char *stb_fget_string(FILE *f, void *p) -{ - char *s; - int len = stb_fget_varlenu(f); - if (len > 4096) return NULL; - s = p ? stb_malloc_string(p, len+1) : (char *) malloc(len+1); - fread(s, 1, len, f); - s[len] = 0; - return s; -} - -char *stb_strdup(char *str, void *pool) -{ - size_t len = strlen(str); - char *p = stb_malloc_string(pool, len+1); - stb_p_strcpy_s(p, len+1, str); - return p; -} - -// strip the trailing '/' or '\\' from a directory so we can refer to it -// as a file for _stat() -char *stb_strip_final_slash(char *t) -{ - if (t[0]) { - char *z = t + strlen(t) - 1; - // *z is the last character - if (*z == '\\' || *z == '/') - if (z != t+2 || t[1] != ':') // but don't strip it if it's e.g. "c:/" - *z = 0; - if (*z == '\\') - *z = '/'; // canonicalize to make sure it matches db - } - return t; -} - -char *stb_strip_final_slash_regardless(char *t) -{ - if (t[0]) { - char *z = t + strlen(t) - 1; - // *z is the last character - if (*z == '\\' || *z == '/') - *z = 0; - if (*z == '\\') - *z = '/'; // canonicalize to make sure it matches db - } - return t; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Options parsing -// - -STB_EXTERN char **stb_getopt_param(int *argc, char **argv, char *param); -STB_EXTERN char **stb_getopt(int *argc, char **argv); -STB_EXTERN void stb_getopt_free(char **opts); - -#ifdef STB_DEFINE - -void stb_getopt_free(char **opts) -{ - int i; - char ** o2 = opts; - for (i=0; i < stb_arr_len(o2); ++i) - free(o2[i]); - stb_arr_free(o2); -} - -char **stb_getopt(int *argc, char **argv) -{ - return stb_getopt_param(argc, argv, (char*) ""); -} - -char **stb_getopt_param(int *argc, char **argv, char *param) -{ - char ** opts=NULL; - int i,j=1; - for (i=1; i < *argc; ++i) { - if (argv[i][0] != '-') { - argv[j++] = argv[i]; - } else { - if (argv[i][1] == 0) { // plain - == don't parse further options - ++i; - while (i < *argc) - argv[j++] = argv[i++]; - break; - } else if (argv[i][1] == '-') { - // copy argument through including initial '-' for clarity - stb_arr_push(opts, stb_p_strdup(argv[i])); - } else { - int k; - char *q = argv[i]; // traverse options list - for (k=1; q[k]; ++k) { - char *s; - if (strchr(param, q[k])) { // does it take a parameter? - char *t = &q[k+1], z = q[k]; - size_t len=0; - if (*t == 0) { - if (i == *argc-1) { // takes a parameter, but none found - *argc = 0; - stb_getopt_free(opts); - return NULL; - } - t = argv[++i]; - } else - k += (int) strlen(t); - len = strlen(t); - s = (char *) malloc(len+2); - if (!s) return NULL; - s[0] = z; - stb_p_strcpy_s(s+1, len+2, t); - } else { - // no parameter - s = (char *) malloc(2); - if (!s) return NULL; - s[0] = q[k]; - s[1] = 0; - } - stb_arr_push(opts, s); - } - } - } - } - stb_arr_push(opts, NULL); - *argc = j; - return opts; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// Portable directory reading -// - -STB_EXTERN char **stb_readdir_files (char *dir); -STB_EXTERN char **stb_readdir_files_mask(char *dir, char *wild); -STB_EXTERN char **stb_readdir_subdirs(char *dir); -STB_EXTERN char **stb_readdir_subdirs_mask(char *dir, char *wild); -STB_EXTERN void stb_readdir_free (char **files); -STB_EXTERN char **stb_readdir_recursive(char *dir, char *filespec); -STB_EXTERN void stb_delete_directory_recursive(char *dir); - -#ifdef STB_DEFINE - -#ifdef _MSC_VER -#include -#else -#include -#include -#endif - -void stb_readdir_free(char **files) -{ - char **f2 = files; - int i; - for (i=0; i < stb_arr_len(f2); ++i) - free(f2[i]); - stb_arr_free(f2); -} - -static int isdotdirname(char *name) -{ - if (name[0] == '.') - return (name[1] == '.') ? !name[2] : !name[1]; - return 0; -} - -STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); -static char **readdir_raw(char *dir, int return_subdirs, char *mask) -{ - char **results = NULL; - char buffer[4096], with_slash[4096]; - size_t n; - - #ifdef WIN32 - stb__wchar *ws; - struct _wfinddata_t data; - #ifdef _WIN64 - const intptr_t none = -1; - intptr_t z; - #else - const long none = -1; - long z; - #endif - #else // !WIN32 - const DIR *none = NULL; - DIR *z; - #endif - - n = stb_strscpy(buffer,dir,sizeof(buffer)); - if (!n || n >= sizeof(buffer)) - return NULL; - stb_fixpath(buffer); - - if (n > 0 && (buffer[n-1] != '/')) { - buffer[n++] = '/'; - } - buffer[n] = 0; - if (!stb_strscpy(with_slash,buffer,sizeof(with_slash))) - return NULL; - - #ifdef WIN32 - if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n)) - return NULL; - ws = stb__from_utf8(buffer); - z = _wfindfirst((wchar_t *)ws, &data); - #else - z = opendir(dir); - #endif - - if (z != none) { - int nonempty = STB_TRUE; - #ifndef WIN32 - struct dirent *data = readdir(z); - nonempty = (data != NULL); - #endif - - if (nonempty) { - - do { - int is_subdir; - #ifdef WIN32 - char *name = stb__to_utf8((stb__wchar *)data.name); - if (name == NULL) { - fprintf(stderr, "%s to convert '%S' to %s!\n", "Unable", data.name, "utf8"); - continue; - } - is_subdir = !!(data.attrib & _A_SUBDIR); - #else - char *name = data->d_name; - if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n)) - break; - // Could follow DT_LNK, but would need to check for recursive links. - is_subdir = !!(data->d_type & DT_DIR); - #endif - - if (is_subdir == return_subdirs) { - if (!is_subdir || !isdotdirname(name)) { - if (!mask || stb_wildmatchi(mask, name)) { - char buffer[4096],*p=buffer; - if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 ) - break; - if (buffer[0] == '.' && buffer[1] == '/') - p = buffer+2; - stb_arr_push(results, stb_p_strdup(p)); - } - } - } - } - #ifdef WIN32 - while (0 == _wfindnext(z, &data)); - #else - while ((data = readdir(z)) != NULL); - #endif - } - #ifdef WIN32 - _findclose(z); - #else - closedir(z); - #endif - } - return results; -} - -char **stb_readdir_files (char *dir) { return readdir_raw(dir, 0, NULL); } -char **stb_readdir_subdirs(char *dir) { return readdir_raw(dir, 1, NULL); } -char **stb_readdir_files_mask(char *dir, char *wild) { return readdir_raw(dir, 0, wild); } -char **stb_readdir_subdirs_mask(char *dir, char *wild) { return readdir_raw(dir, 1, wild); } - -int stb__rec_max=0x7fffffff; -static char **stb_readdir_rec(char **sofar, char *dir, char *filespec) -{ - char **files; - char ** dirs; - char **p; - - if (stb_arr_len(sofar) >= stb__rec_max) return sofar; - - files = stb_readdir_files_mask(dir, filespec); - stb_arr_for(p, files) { - stb_arr_push(sofar, stb_p_strdup(*p)); - if (stb_arr_len(sofar) >= stb__rec_max) break; - } - stb_readdir_free(files); - if (stb_arr_len(sofar) >= stb__rec_max) return sofar; - - dirs = stb_readdir_subdirs(dir); - stb_arr_for(p, dirs) - sofar = stb_readdir_rec(sofar, *p, filespec); - stb_readdir_free(dirs); - return sofar; -} - -char **stb_readdir_recursive(char *dir, char *filespec) -{ - return stb_readdir_rec(NULL, dir, filespec); -} - -void stb_delete_directory_recursive(char *dir) -{ - char **list = stb_readdir_subdirs(dir); - int i; - for (i=0; i < stb_arr_len(list); ++i) - stb_delete_directory_recursive(list[i]); - stb_arr_free(list); - list = stb_readdir_files(dir); - for (i=0; i < stb_arr_len(list); ++i) - if (!remove(list[i])) { - // on windows, try again after making it writeable; don't ALWAYS - // do this first since that would be slow in the normal case - #ifdef _MSC_VER - _chmod(list[i], _S_IWRITE); - remove(list[i]); - #endif - } - stb_arr_free(list); - stb__windows(_rmdir,rmdir)(dir); -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// construct trees from filenames; useful for cmirror summaries - -typedef struct stb_dirtree2 stb_dirtree2; - -struct stb_dirtree2 -{ - stb_dirtree2 **subdirs; - - // make convenient for stb_summarize_tree - int num_subdir; - float weight; - - // actual data - char *fullpath; - char *relpath; - char **files; -}; - -STB_EXTERN stb_dirtree2 *stb_dirtree2_from_files_relative(char *src, char **filelist, int count); -STB_EXTERN stb_dirtree2 *stb_dirtree2_from_files(char **filelist, int count); -STB_EXTERN int stb_dir_is_prefix(char *dir, int dirlen, char *file); - -#ifdef STB_DEFINE - -int stb_dir_is_prefix(char *dir, int dirlen, char *file) -{ - if (dirlen == 0) return STB_TRUE; - if (stb_strnicmp(dir, file, dirlen)) return STB_FALSE; - if (file[dirlen] == '/' || file[dirlen] == '\\') return STB_TRUE; - return STB_FALSE; -} - -stb_dirtree2 *stb_dirtree2_from_files_relative(char *src, char **filelist, int count) -{ - char buffer1[1024]; - int i; - int dlen = (int) strlen(src), elen; - stb_dirtree2 *d; - char ** descendents = NULL; - char ** files = NULL; - char *s; - if (!count) return NULL; - // first find all the ones that belong here... note this is will take O(NM) with N files and M subdirs - for (i=0; i < count; ++i) { - if (stb_dir_is_prefix(src, dlen, filelist[i])) { - stb_arr_push(descendents, filelist[i]); - } - } - if (descendents == NULL) - return NULL; - elen = dlen; - // skip a leading slash - if (elen == 0 && (descendents[0][0] == '/' || descendents[0][0] == '\\')) - ++elen; - else if (elen) - ++elen; - // now extract all the ones that have their root here - for (i=0; i < stb_arr_len(descendents);) { - if (!stb_strchr2(descendents[i]+elen, '/', '\\')) { - stb_arr_push(files, descendents[i]); - descendents[i] = descendents[stb_arr_len(descendents)-1]; - stb_arr_pop(descendents); - } else - ++i; - } - // now create a record - d = (stb_dirtree2 *) malloc(sizeof(*d)); - d->files = files; - d->subdirs = NULL; - d->fullpath = stb_p_strdup(src); - s = stb_strrchr2(d->fullpath, '/', '\\'); - if (s) - ++s; - else - s = d->fullpath; - d->relpath = s; - // now create the children - qsort(descendents, stb_arr_len(descendents), sizeof(char *), stb_qsort_stricmp(0)); - buffer1[0] = 0; - for (i=0; i < stb_arr_len(descendents); ++i) { - char buffer2[1024]; - char *s = descendents[i] + elen, *t; - t = stb_strchr2(s, '/', '\\'); - assert(t); - stb_strncpy(buffer2, descendents[i], (int) (t-descendents[i]+1)); - if (stb_stricmp(buffer1, buffer2)) { - stb_dirtree2 *t = stb_dirtree2_from_files_relative(buffer2, descendents, stb_arr_len(descendents)); - assert(t != NULL); - stb_p_strcpy_s(buffer1, sizeof(buffer1), buffer2); - stb_arr_push(d->subdirs, t); - } - } - d->num_subdir = stb_arr_len(d->subdirs); - d->weight = 0; - return d; -} - -stb_dirtree2 *stb_dirtree2_from_files(char **filelist, int count) -{ - return stb_dirtree2_from_files_relative((char*) "", filelist, count); -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Checksums: CRC-32, ADLER32, SHA-1 -// -// CRC-32 and ADLER32 allow streaming blocks -// SHA-1 requires either a complete buffer, max size 2^32 - 73 -// or it can checksum directly from a file, max 2^61 - -#define STB_ADLER32_SEED 1 -#define STB_CRC32_SEED 0 // note that we logical NOT this in the code - -STB_EXTERN stb_uint - stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen); -STB_EXTERN stb_uint - stb_crc32_block(stb_uint crc32, stb_uchar *buffer, stb_uint len); -STB_EXTERN stb_uint stb_crc32(unsigned char *buffer, stb_uint len); - -STB_EXTERN void stb_sha1( - unsigned char output[20], unsigned char *buffer, unsigned int len); -STB_EXTERN int stb_sha1_file(unsigned char output[20], char *file); - -STB_EXTERN void stb_sha1_readable(char display[27], unsigned char sha[20]); - -#ifdef STB_DEFINE -stb_uint stb_crc32_block(stb_uint crc, unsigned char *buffer, stb_uint len) -{ - static stb_uint crc_table[256]; - stb_uint i,j,s; - crc = ~crc; - - if (crc_table[1] == 0) - for(i=0; i < 256; i++) { - for (s=i, j=0; j < 8; ++j) - s = (s >> 1) ^ (s & 1 ? 0xedb88320 : 0); - crc_table[i] = s; - } - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; -} - -stb_uint stb_crc32(unsigned char *buffer, stb_uint len) -{ - return stb_crc32_block(0, buffer, len); -} - -stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen) -{ - const unsigned long ADLER_MOD = 65521; - unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; - unsigned long blocklen, i; - - blocklen = buflen % 5552; - while (buflen) { - for (i=0; i + 7 < blocklen; i += 8) { - s1 += buffer[0], s2 += s1; - s1 += buffer[1], s2 += s1; - s1 += buffer[2], s2 += s1; - s1 += buffer[3], s2 += s1; - s1 += buffer[4], s2 += s1; - s1 += buffer[5], s2 += s1; - s1 += buffer[6], s2 += s1; - s1 += buffer[7], s2 += s1; - - buffer += 8; - } - - for (; i < blocklen; ++i) - s1 += *buffer++, s2 += s1; - - s1 %= ADLER_MOD, s2 %= ADLER_MOD; - buflen -= blocklen; - blocklen = 5552; - } - return (s2 << 16) + s1; -} - -static void stb__sha1(stb_uchar *chunk, stb_uint h[5]) -{ - int i; - stb_uint a,b,c,d,e; - stb_uint w[80]; - - for (i=0; i < 16; ++i) - w[i] = stb_big32(&chunk[i*4]); - for (i=16; i < 80; ++i) { - stb_uint t; - t = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; - w[i] = (t + t) | (t >> 31); - } - - a = h[0]; - b = h[1]; - c = h[2]; - d = h[3]; - e = h[4]; - - #define STB__SHA1(k,f) \ - { \ - stb_uint temp = (a << 5) + (a >> 27) + (f) + e + (k) + w[i]; \ - e = d; \ - d = c; \ - c = (b << 30) + (b >> 2); \ - b = a; \ - a = temp; \ - } - - i=0; - for (; i < 20; ++i) STB__SHA1(0x5a827999, d ^ (b & (c ^ d)) ); - for (; i < 40; ++i) STB__SHA1(0x6ed9eba1, b ^ c ^ d ); - for (; i < 60; ++i) STB__SHA1(0x8f1bbcdc, (b & c) + (d & (b ^ c)) ); - for (; i < 80; ++i) STB__SHA1(0xca62c1d6, b ^ c ^ d ); - - #undef STB__SHA1 - - h[0] += a; - h[1] += b; - h[2] += c; - h[3] += d; - h[4] += e; -} - -void stb_sha1(stb_uchar output[20], stb_uchar *buffer, stb_uint len) -{ - unsigned char final_block[128]; - stb_uint end_start, final_len, j; - int i; - - stb_uint h[5]; - - h[0] = 0x67452301; - h[1] = 0xefcdab89; - h[2] = 0x98badcfe; - h[3] = 0x10325476; - h[4] = 0xc3d2e1f0; - - // we need to write padding to the last one or two - // blocks, so build those first into 'final_block' - - // we have to write one special byte, plus the 8-byte length - - // compute the block where the data runs out - end_start = len & ~63; - - // compute the earliest we can encode the length - if (((len+9) & ~63) == end_start) { - // it all fits in one block, so fill a second-to-last block - end_start -= 64; - } - - final_len = end_start + 128; - - // now we need to copy the data in - assert(end_start + 128 >= len+9); - assert(end_start < len || len < 64-9); - - j = 0; - if (end_start > len) - j = (stb_uint) - (int) end_start; - - for (; end_start + j < len; ++j) - final_block[j] = buffer[end_start + j]; - final_block[j++] = 0x80; - while (j < 128-5) // 5 byte length, so write 4 extra padding bytes - final_block[j++] = 0; - // big-endian size - final_block[j++] = len >> 29; - final_block[j++] = len >> 21; - final_block[j++] = len >> 13; - final_block[j++] = len >> 5; - final_block[j++] = len << 3; - assert(j == 128 && end_start + j == final_len); - - for (j=0; j < final_len; j += 64) { // 512-bit chunks - if (j+64 >= end_start+64) - stb__sha1(&final_block[j - end_start], h); - else - stb__sha1(&buffer[j], h); - } - - for (i=0; i < 5; ++i) { - output[i*4 + 0] = h[i] >> 24; - output[i*4 + 1] = h[i] >> 16; - output[i*4 + 2] = h[i] >> 8; - output[i*4 + 3] = h[i] >> 0; - } -} - -#ifdef _MSC_VER -int stb_sha1_file(stb_uchar output[20], char *file) -{ - int i; - stb_uint64 length=0; - unsigned char buffer[128]; - - FILE *f = stb__fopen(file, "rb"); - stb_uint h[5]; - - if (f == NULL) return 0; // file not found - - h[0] = 0x67452301; - h[1] = 0xefcdab89; - h[2] = 0x98badcfe; - h[3] = 0x10325476; - h[4] = 0xc3d2e1f0; - - for(;;) { - size_t n = fread(buffer, 1, 64, f); - if (n == 64) { - stb__sha1(buffer, h); - length += n; - } else { - int block = 64; - - length += n; - - buffer[n++] = 0x80; - - // if there isn't enough room for the length, double the block - if (n + 8 > 64) - block = 128; - - // pad to end - memset(buffer+n, 0, block-8-n); - - i = block - 8; - buffer[i++] = (stb_uchar) (length >> 53); - buffer[i++] = (stb_uchar) (length >> 45); - buffer[i++] = (stb_uchar) (length >> 37); - buffer[i++] = (stb_uchar) (length >> 29); - buffer[i++] = (stb_uchar) (length >> 21); - buffer[i++] = (stb_uchar) (length >> 13); - buffer[i++] = (stb_uchar) (length >> 5); - buffer[i++] = (stb_uchar) (length << 3); - assert(i == block); - stb__sha1(buffer, h); - if (block == 128) - stb__sha1(buffer+64, h); - else - assert(block == 64); - break; - } - } - fclose(f); - - for (i=0; i < 5; ++i) { - output[i*4 + 0] = h[i] >> 24; - output[i*4 + 1] = h[i] >> 16; - output[i*4 + 2] = h[i] >> 8; - output[i*4 + 3] = h[i] >> 0; - } - - return 1; -} -#endif // _MSC_VER - -// client can truncate this wherever they like -void stb_sha1_readable(char display[27], unsigned char sha[20]) -{ - char encoding[65] = "0123456789abcdefghijklmnopqrstuv" - "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%$"; - int num_bits = 0, acc=0; - int i=0,o=0; - while (o < 26) { - int v; - // expand the accumulator - if (num_bits < 6) { - assert(i != 20); - acc += sha[i++] << num_bits; - num_bits += 8; - } - v = acc & ((1 << 6) - 1); - display[o++] = encoding[v]; - acc >>= 6; - num_bits -= 6; - } - assert(num_bits == 20*8 - 26*6); - display[o++] = encoding[acc]; -} - -#endif // STB_DEFINE - -/////////////////////////////////////////////////////////// -// -// simplified WINDOWS registry interface... hopefully -// we'll never actually use this? - -#if defined(_WIN32) - -STB_EXTERN void * stb_reg_open(const char *mode, const char *where); // mode: "rHKLM" or "rHKCU" or "w.." -STB_EXTERN void stb_reg_close(void *reg); -STB_EXTERN int stb_reg_read(void *zreg, const char *str, void *data, unsigned long len); -STB_EXTERN int stb_reg_read_string(void *zreg, const char *str, char *data, int len); -STB_EXTERN void stb_reg_write(void *zreg, const char *str, const void *data, unsigned long len); -STB_EXTERN void stb_reg_write_string(void *zreg, const char *str, const char *data); - -#if defined(STB_DEFINE) && !defined(STB_NO_REGISTRY) - -#define STB_HAS_REGISTRY - -#ifndef _WINDOWS_ - -#define HKEY void * - -STB_EXTERN __declspec(dllimport) long __stdcall RegCloseKey ( HKEY hKey ); -STB_EXTERN __declspec(dllimport) long __stdcall RegCreateKeyExA ( HKEY hKey, const char * lpSubKey, - int Reserved, char * lpClass, int dwOptions, - int samDesired, void *lpSecurityAttributes, HKEY * phkResult, int * lpdwDisposition ); -STB_EXTERN __declspec(dllimport) long __stdcall RegDeleteKeyA ( HKEY hKey, const char * lpSubKey ); -STB_EXTERN __declspec(dllimport) long __stdcall RegQueryValueExA ( HKEY hKey, const char * lpValueName, - int * lpReserved, unsigned long * lpType, unsigned char * lpData, unsigned long * lpcbData ); -STB_EXTERN __declspec(dllimport) long __stdcall RegSetValueExA ( HKEY hKey, const char * lpValueName, - int Reserved, int dwType, const unsigned char* lpData, int cbData ); -STB_EXTERN __declspec(dllimport) long __stdcall RegOpenKeyExA ( HKEY hKey, const char * lpSubKey, - int ulOptions, int samDesired, HKEY * phkResult ); - -#endif // _WINDOWS_ - -#define STB__REG_OPTION_NON_VOLATILE 0 -#define STB__REG_KEY_ALL_ACCESS 0x000f003f -#define STB__REG_KEY_READ 0x00020019 - -#ifdef _M_AMD64 -#define STB__HKEY_CURRENT_USER 0x80000001ull -#define STB__HKEY_LOCAL_MACHINE 0x80000002ull -#else -#define STB__HKEY_CURRENT_USER 0x80000001 -#define STB__HKEY_LOCAL_MACHINE 0x80000002 -#endif - -void *stb_reg_open(const char *mode, const char *where) -{ - long res; - HKEY base; - HKEY zreg; - if (!stb_stricmp(mode+1, "cu") || !stb_stricmp(mode+1, "hkcu")) - base = (HKEY) STB__HKEY_CURRENT_USER; - else if (!stb_stricmp(mode+1, "lm") || !stb_stricmp(mode+1, "hklm")) - base = (HKEY) STB__HKEY_LOCAL_MACHINE; - else - return NULL; - - if (mode[0] == 'r') - res = RegOpenKeyExA(base, where, 0, STB__REG_KEY_READ, &zreg); - else if (mode[0] == 'w') - res = RegCreateKeyExA(base, where, 0, NULL, STB__REG_OPTION_NON_VOLATILE, STB__REG_KEY_ALL_ACCESS, NULL, &zreg, NULL); - else - return NULL; - - return res ? NULL : zreg; -} - -void stb_reg_close(void *reg) -{ - RegCloseKey((HKEY) reg); -} - -#define STB__REG_SZ 1 -#define STB__REG_BINARY 3 -#define STB__REG_DWORD 4 - -int stb_reg_read(void *zreg, const char *str, void *data, unsigned long len) -{ - unsigned long type; - unsigned long alen = len; - if (0 == RegQueryValueExA((HKEY) zreg, str, 0, &type, (unsigned char *) data, &len)) - if (type == STB__REG_BINARY || type == STB__REG_SZ || type == STB__REG_DWORD) { - if (len < alen) - *((char *) data + len) = 0; - return 1; - } - return 0; -} - -void stb_reg_write(void *zreg, const char *str, const void *data, unsigned long len) -{ - if (zreg) - RegSetValueExA((HKEY) zreg, str, 0, STB__REG_BINARY, (const unsigned char *) data, len); -} - -int stb_reg_read_string(void *zreg, const char *str, char *data, int len) -{ - if (!stb_reg_read(zreg, str, data, len)) return 0; - data[len-1] = 0; // force a 0 at the end of the string no matter what - return 1; -} - -void stb_reg_write_string(void *zreg, const char *str, const char *data) -{ - if (zreg) - RegSetValueExA((HKEY) zreg, str, 0, STB__REG_SZ, (const unsigned char *) data, (int) strlen(data)+1); -} -#endif // STB_DEFINE -#endif // _WIN32 - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_cfg - This is like the registry, but the config info -// is all stored in plain old files where we can -// backup and restore them easily. The LOCATION of -// the config files is gotten from... the registry! - -#ifndef STB_NO_STB_STRINGS -typedef struct stb_cfg_st stb_cfg; - -STB_EXTERN stb_cfg * stb_cfg_open(char *config, const char *mode); // mode = "r", "w" -STB_EXTERN void stb_cfg_close(stb_cfg *cfg); -STB_EXTERN int stb_cfg_read(stb_cfg *cfg, char *key, void *value, int len); -STB_EXTERN void stb_cfg_write(stb_cfg *cfg, char *key, void *value, int len); -STB_EXTERN int stb_cfg_read_string(stb_cfg *cfg, char *key, char *value, int len); -STB_EXTERN void stb_cfg_write_string(stb_cfg *cfg, char *key, char *value); -STB_EXTERN int stb_cfg_delete(stb_cfg *cfg, char *key); -STB_EXTERN void stb_cfg_set_directory(char *dir); - -#ifdef STB_DEFINE - -typedef struct -{ - char *key; - void *value; - int value_len; -} stb__cfg_item; - -struct stb_cfg_st -{ - stb__cfg_item *data; - char *loaded_file; // this needs to be freed - FILE *f; // write the data to this file on close -}; - -static const char *stb__cfg_sig = "sTbCoNfIg!\0\0"; -static char stb__cfg_dir[512]; -STB_EXTERN void stb_cfg_set_directory(char *dir) -{ - stb_p_strcpy_s(stb__cfg_dir, sizeof(stb__cfg_dir), dir); -} - -STB_EXTERN stb_cfg * stb_cfg_open(char *config, const char *mode) -{ - size_t len; - stb_cfg *z; - char file[512]; - if (mode[0] != 'r' && mode[0] != 'w') return NULL; - - if (!stb__cfg_dir[0]) { - #ifdef _WIN32 - stb_p_strcpy_s(stb__cfg_dir, sizeof(stb__cfg_dir), "c:/stb"); - #else - strcpy(stb__cfg_dir, "~/.stbconfig"); - #endif - - #ifdef STB_HAS_REGISTRY - { - void *reg = stb_reg_open("rHKLM", "Software\\SilverSpaceship\\stb"); - if (reg) { - stb_reg_read_string(reg, "config_dir", stb__cfg_dir, sizeof(stb__cfg_dir)); - stb_reg_close(reg); - } - } - #endif - } - - stb_p_sprintf(file stb_p_size(sizeof(file)), "%s/%s.cfg", stb__cfg_dir, config); - - z = (stb_cfg *) stb_malloc(0, sizeof(*z)); - z->data = NULL; - - z->loaded_file = stb_filec(file, &len); - if (z->loaded_file) { - char *s = z->loaded_file; - if (!memcmp(s, stb__cfg_sig, 12)) { - char *s = z->loaded_file + 12; - while (s < z->loaded_file + len) { - stb__cfg_item a; - int n = *(stb_int16 *) s; - a.key = s+2; - s = s+2 + n; - a.value_len = *(int *) s; - s += 4; - a.value = s; - s += a.value_len; - stb_arr_push(z->data, a); - } - assert(s == z->loaded_file + len); - } - } - - if (mode[0] == 'w') - z->f = stb_p_fopen(file, "wb"); - else - z->f = NULL; - - return z; -} - -void stb_cfg_close(stb_cfg *z) -{ - if (z->f) { - int i; - // write the file out - fwrite(stb__cfg_sig, 12, 1, z->f); - for (i=0; i < stb_arr_len(z->data); ++i) { - stb_int16 n = (stb_int16) strlen(z->data[i].key)+1; - fwrite(&n, 2, 1, z->f); - fwrite(z->data[i].key, n, 1, z->f); - fwrite(&z->data[i].value_len, 4, 1, z->f); - fwrite(z->data[i].value, z->data[i].value_len, 1, z->f); - } - fclose(z->f); - } - stb_arr_free(z->data); - stb_free(z); -} - -int stb_cfg_read(stb_cfg *z, char *key, void *value, int len) -{ - int i; - for (i=0; i < stb_arr_len(z->data); ++i) { - if (!stb_stricmp(z->data[i].key, key)) { - int n = stb_min(len, z->data[i].value_len); - memcpy(value, z->data[i].value, n); - if (n < len) - *((char *) value + n) = 0; - return 1; - } - } - return 0; -} - -void stb_cfg_write(stb_cfg *z, char *key, void *value, int len) -{ - int i; - for (i=0; i < stb_arr_len(z->data); ++i) - if (!stb_stricmp(z->data[i].key, key)) - break; - if (i == stb_arr_len(z->data)) { - stb__cfg_item p; - p.key = stb_strdup(key, z); - p.value = NULL; - p.value_len = 0; - stb_arr_push(z->data, p); - } - z->data[i].value = stb_malloc(z, len); - z->data[i].value_len = len; - memcpy(z->data[i].value, value, len); -} - -int stb_cfg_delete(stb_cfg *z, char *key) -{ - int i; - for (i=0; i < stb_arr_len(z->data); ++i) - if (!stb_stricmp(z->data[i].key, key)) { - stb_arr_fastdelete(z->data, i); - return 1; - } - return 0; -} - -int stb_cfg_read_string(stb_cfg *z, char *key, char *value, int len) -{ - if (!stb_cfg_read(z, key, value, len)) return 0; - value[len-1] = 0; - return 1; -} - -void stb_cfg_write_string(stb_cfg *z, char *key, char *value) -{ - stb_cfg_write(z, key, value, (int) strlen(value)+1); -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// stb_dirtree - load a description of a directory tree -// uses a cache and stat()s the directories for changes -// MUCH faster on NTFS, _wrong_ on FAT32, so should -// ignore the db on FAT32 - -#ifdef _WIN32 - -typedef struct -{ - char * path; // full path from passed-in root - time_t last_modified; - int num_files; - int flag; -} stb_dirtree_dir; - -typedef struct -{ - char *name; // name relative to path - int dir; // index into dirs[] array - stb_int64 size; // size, max 4GB - time_t last_modified; - int flag; -} stb_dirtree_file; - -typedef struct -{ - stb_dirtree_dir *dirs; - stb_dirtree_file *files; - - // internal use - void * string_pool; // used to free data en masse -} stb_dirtree; - -extern void stb_dirtree_free ( stb_dirtree *d ); -extern stb_dirtree *stb_dirtree_get ( char *dir); -extern stb_dirtree *stb_dirtree_get_dir ( char *dir, char *cache_dir); -extern stb_dirtree *stb_dirtree_get_with_file ( char *dir, char *cache_file); - -// get a list of all the files recursively underneath 'dir' -// -// cache_file is used to store a copy of the directory tree to speed up -// later calls. It must be unique to 'dir' and the current working -// directory! Otherwise who knows what will happen (a good solution -// is to put it _in_ dir, but this API doesn't force that). -// -// Also, it might be possible to break this if you have two different processes -// do a call to stb_dirtree_get() with the same cache file at about the same -// time, but I _think_ it might just work. - -// i needed to build an identical data structure representing the state of -// a mirrored copy WITHOUT bothering to rescan it (i.e. we're mirroring to -// it WITHOUT scanning it, e.g. it's over the net), so this requires access -// to all of the innards. -extern void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last); -extern void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last); -extern void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir); -extern void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir); - -#ifdef STB_DEFINE -static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active) -{ - stb_dirtree_dir d; - d.last_modified = last; - d.num_files = 0; - d.path = stb_strdup(path, active->string_pool); - stb_arr_push(active->dirs, d); -} - -static void stb__dirtree_add_file(char *name, int dir, stb_int64 size, time_t last, stb_dirtree *active) -{ - stb_dirtree_file f; - f.dir = dir; - f.size = size; - f.last_modified = last; - f.name = stb_strdup(name, active->string_pool); - ++active->dirs[dir].num_files; - stb_arr_push(active->files, f); -} - -// version 02 supports > 4GB files -static char stb__signature[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '2' }; - -static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root) -{ - int i, num_dirs_final=0, num_files_final; - char *info = root ? root : (char*)""; - int *remap; - FILE *f = stb_p_fopen(filename, "wb"); - if (!f) return; - - fwrite(stb__signature, sizeof(stb__signature), 1, f); - fwrite(info, strlen(info)+1, 1, f); - // need to be slightly tricky and not write out NULLed directories, nor the root - - // build remapping table of all dirs we'll be writing out - remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(data->dirs)); - for (i=0; i < stb_arr_len(data->dirs); ++i) { - if (data->dirs[i].path == NULL || (root && 0==stb_stricmp(data->dirs[i].path, root))) { - remap[i] = -1; - } else { - remap[i] = num_dirs_final++; - } - } - - fwrite(&num_dirs_final, 4, 1, f); - for (i=0; i < stb_arr_len(data->dirs); ++i) { - if (remap[i] >= 0) { - fwrite(&data->dirs[i].last_modified, 4, 1, f); - stb_fput_string(f, data->dirs[i].path); - } - } - - num_files_final = 0; - for (i=0; i < stb_arr_len(data->files); ++i) - if (remap[data->files[i].dir] >= 0 && data->files[i].name) - ++num_files_final; - - fwrite(&num_files_final, 4, 1, f); - for (i=0; i < stb_arr_len(data->files); ++i) { - if (remap[data->files[i].dir] >= 0 && data->files[i].name) { - stb_fput_ranged(f, remap[data->files[i].dir], 0, num_dirs_final); - stb_fput_varlen64(f, data->files[i].size); - fwrite(&data->files[i].last_modified, 4, 1, f); - stb_fput_string(f, data->files[i].name); - } - } - - fclose(f); -} - -// note: stomps any existing data, rather than appending -static void stb__dirtree_load_db(char *filename, stb_dirtree *data, char *dir) -{ - char sig[2048]; - int i,n; - FILE *f = stb_p_fopen(filename, "rb"); - - if (!f) return; - - data->string_pool = stb_malloc(0,1); - - fread(sig, sizeof(stb__signature), 1, f); - if (memcmp(stb__signature, sig, sizeof(stb__signature))) { fclose(f); return; } - if (!fread(sig, strlen(dir)+1, 1, f)) { fclose(f); return; } - if (stb_stricmp(sig,dir)) { fclose(f); return; } - - // we can just read them straight in, because they're guaranteed to be valid - fread(&n, 4, 1, f); - stb_arr_setlen(data->dirs, n); - for(i=0; i < stb_arr_len(data->dirs); ++i) { - fread(&data->dirs[i].last_modified, 4, 1, f); - data->dirs[i].path = stb_fget_string(f, data->string_pool); - if (data->dirs[i].path == NULL) goto bail; - } - fread(&n, 4, 1, f); - stb_arr_setlen(data->files, n); - for (i=0; i < stb_arr_len(data->files); ++i) { - data->files[i].dir = stb_fget_ranged(f, 0, stb_arr_len(data->dirs)); - data->files[i].size = stb_fget_varlen64(f); - fread(&data->files[i].last_modified, 4, 1, f); - data->files[i].name = stb_fget_string(f, data->string_pool); - if (data->files[i].name == NULL) goto bail; - } - - if (0) { - bail: - stb_arr_free(data->dirs); - stb_arr_free(data->files); - } - fclose(f); -} - -FILE *hlog; - -static int stb__dircount, stb__dircount_mask, stb__showfile; -static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *active) -{ - // this is dumb depth first; theoretically it might be faster - // to fully traverse each directory before visiting its children, - // but it's complicated and didn't seem like a gain in the test app - - int n; - - struct _wfinddatai64_t c_file; - long hFile; - stb__wchar full_path[1024]; - int has_slash; - if (stb__showfile) printf("<"); - - has_slash = (path[0] && path[strlen(path)-1] == '/'); - - // @TODO: do this concatenation without using swprintf to avoid this mess: -#if (defined(_MSC_VER) && _MSC_VER < 1400) // || (defined(__clang__)) - // confusingly, Windows Kits\10 needs to go down this path?!? - // except now it doesn't, I don't know what changed - if (has_slash) - swprintf(full_path, L"%s*", stb__from_utf8(path)); - else - swprintf(full_path, L"%s/*", stb__from_utf8(path)); -#else - if (has_slash) - swprintf((wchar_t *) full_path, (size_t) 1024, L"%s*", (wchar_t *) stb__from_utf8(path)); - else - swprintf((wchar_t *) full_path, (size_t) 1024, L"%s/*", (wchar_t *) stb__from_utf8(path)); -#endif - - // it's possible this directory is already present: that means it was in the - // cache, but its parent wasn't... in that case, we're done with it - if (stb__showfile) printf("C[%d]", stb_arr_len(active->dirs)); - for (n=0; n < stb_arr_len(active->dirs); ++n) - if (0 == stb_stricmp(active->dirs[n].path, path)) { - if (stb__showfile) printf("D"); - return; - } - if (stb__showfile) printf("E"); - - // otherwise, we need to add it - stb__dirtree_add_dir(path, last_time, active); - n = stb_arr_lastn(active->dirs); - - if (stb__showfile) printf("["); - if( (hFile = (long) _wfindfirsti64( (wchar_t *) full_path, &c_file )) != -1L ) { - do { - if (stb__showfile) printf(")"); - if (c_file.attrib & _A_SUBDIR) { - // ignore subdirectories starting with '.', e.g. "." and ".." - if (c_file.name[0] != '.') { - char *new_path = (char *) full_path; - char *temp = stb__to_utf8((stb__wchar *) c_file.name); - - if (has_slash) - stb_p_sprintf(new_path stb_p_size(sizeof(full_path)), "%s%s", path, temp); - else - stb_p_sprintf(new_path stb_p_size(sizeof(full_path)), "%s/%s", path, temp); - - if (stb__dircount_mask) { - ++stb__dircount; - if (!(stb__dircount & stb__dircount_mask)) { - char dummy_path[128], *pad; - stb_strncpy(dummy_path, new_path, sizeof(dummy_path)-1); - if (strlen(dummy_path) > 96) { - stb_p_strcpy_s(dummy_path+96/2-1,128, "..."); - stb_p_strcpy_s(dummy_path+96/2+2,128, new_path + strlen(new_path)-96/2+2); - } - pad = dummy_path + strlen(dummy_path); - while (pad < dummy_path+98) - *pad++ = ' '; - *pad = 0; - printf("%s\r", dummy_path); - #if 0 - if (hlog == 0) { - hlog = stb_p_fopen("c:/x/temp.log", "w"); - fprintf(hlog, "%s\n", dummy_path); - } - #endif - } - } - - stb__dirtree_scandir(new_path, c_file.time_write, active); - } - } else { - char *temp = stb__to_utf8((stb__wchar *) c_file.name); - stb__dirtree_add_file(temp, n, c_file.size, c_file.time_write, active); - } - if (stb__showfile) printf("("); - } while( _wfindnexti64( hFile, &c_file ) == 0 ); - if (stb__showfile) printf("]"); - _findclose( hFile ); - } - if (stb__showfile) printf(">\n"); -} - -// scan the database and see if it's all valid -static int stb__dirtree_update_db(stb_dirtree *db, stb_dirtree *active) -{ - int changes_detected = STB_FALSE; - int i; - int *remap; - int *rescan=NULL; - remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(db->dirs)); - memset(remap, 0, sizeof(remap[0]) * stb_arr_len(db->dirs)); - rescan = NULL; - - for (i=0; i < stb_arr_len(db->dirs); ++i) { - struct _stat info; - if (stb__dircount_mask) { - ++stb__dircount; - if (!(stb__dircount & stb__dircount_mask)) { - printf("."); - } - } - if (0 == _stat(db->dirs[i].path, &info)) { - if (info.st_mode & _S_IFDIR) { - // it's still a directory, as expected - int n = abs((int) (info.st_mtime - db->dirs[i].last_modified)); - if (n > 1 && n != 3600) { // the 3600 is a hack because sometimes this jumps for no apparent reason, even when no time zone or DST issues are at play - // it's changed! force a rescan - // we don't want to scan it until we've stat()d its - // subdirs, though, so we queue it - if (stb__showfile) printf("Changed: %s - %08x:%08x\n", db->dirs[i].path, (unsigned int) db->dirs[i].last_modified, (unsigned int) info.st_mtime); - stb_arr_push(rescan, i); - // update the last_mod time - db->dirs[i].last_modified = info.st_mtime; - // ignore existing files in this dir - remap[i] = -1; - changes_detected = STB_TRUE; - } else { - // it hasn't changed, just copy it through unchanged - stb__dirtree_add_dir(db->dirs[i].path, db->dirs[i].last_modified, active); - remap[i] = stb_arr_lastn(active->dirs); - } - } else { - // this path used to refer to a directory, but now it's a file! - // assume that the parent directory is going to be forced to rescan anyway - goto delete_entry; - } - } else { - delete_entry: - // directory no longer exists, so don't copy it - // we don't free it because it's in the string pool now - db->dirs[i].path = NULL; - remap[i] = -1; - changes_detected = STB_TRUE; - } - } - - // at this point, we have: - // - // holds a list of directory indices that need to be scanned due to being out of date - // holds the directory index in for each dir in , if it exists; -1 if not - // directories in are not in yet - - // so we can go ahead and remap all the known files right now - for (i=0; i < stb_arr_len(db->files); ++i) { - int dir = db->files[i].dir; - if (remap[dir] >= 0) { - stb__dirtree_add_file(db->files[i].name, remap[dir], db->files[i].size, db->files[i].last_modified, active); - } - } - - // at this point we're done with db->files, and done with remap - free(remap); - - // now scan those directories using the standard scan - for (i=0; i < stb_arr_len(rescan); ++i) { - int z = rescan[i]; - stb__dirtree_scandir(db->dirs[z].path, db->dirs[z].last_modified, active); - } - stb_arr_free(rescan); - - return changes_detected; -} - -static void stb__dirtree_free_raw(stb_dirtree *d) -{ - stb_free(d->string_pool); - stb_arr_free(d->dirs); - stb_arr_free(d->files); -} - -stb_dirtree *stb_dirtree_get_with_file(char *dir, char *cache_file) -{ - stb_dirtree *output = (stb_dirtree *) malloc(sizeof(*output)); - stb_dirtree db,active; - int prev_dir_count, cache_mismatch; - - char *stripped_dir; // store the directory name without a trailing '/' or '\\' - - // load the database of last-known state on disk - db.string_pool = NULL; - db.files = NULL; - db.dirs = NULL; - - stripped_dir = stb_strip_final_slash(stb_p_strdup(dir)); - - if (cache_file != NULL) - stb__dirtree_load_db(cache_file, &db, stripped_dir); - else if (stb__showfile) - printf("No cache file\n"); - - active.files = NULL; - active.dirs = NULL; - active.string_pool = stb_malloc(0,1); // @TODO: share string pools between both? - - // check all the directories in the database; make note if - // anything we scanned had changed, and rescan those things - cache_mismatch = stb__dirtree_update_db(&db, &active); - - // check the root tree - prev_dir_count = stb_arr_len(active.dirs); // record how many directories we've seen - - stb__dirtree_scandir(stripped_dir, 0, &active); // no last_modified time available for root - - if (stb__dircount_mask) - printf(" \r"); - - // done with the DB; write it back out if any changes, i.e. either - // 1. any inconsistency found between cached information and actual disk - // or 2. if scanning the root found any new directories--which we detect because - // more than one directory got added to the active db during that scan - if (cache_mismatch || stb_arr_len(active.dirs) > prev_dir_count+1) - stb__dirtree_save_db(cache_file, &active, stripped_dir); - - free(stripped_dir); - - stb__dirtree_free_raw(&db); - - *output = active; - return output; -} - -stb_dirtree *stb_dirtree_get_dir(char *dir, char *cache_dir) -{ - int i; - stb_uint8 sha[20]; - char dir_lower[1024]; - char cache_file[1024],*s; - if (cache_dir == NULL) - return stb_dirtree_get_with_file(dir, NULL); - stb_p_strcpy_s(dir_lower, sizeof(dir_lower), dir); - stb_tolower(dir_lower); - stb_sha1(sha, (unsigned char *) dir_lower, (unsigned int) strlen(dir_lower)); - stb_p_strcpy_s(cache_file, sizeof(cache_file), cache_dir); - s = cache_file + strlen(cache_file); - if (s[-1] != '/' && s[-1] != '\\') *s++ = '/'; - stb_p_strcpy_s(s, sizeof(cache_file), "dirtree_"); - s += strlen(s); - for (i=0; i < 8; ++i) { - char *hex = (char*)"0123456789abcdef"; - stb_uint z = sha[i]; - *s++ = hex[z >> 4]; - *s++ = hex[z & 15]; - } - stb_p_strcpy_s(s, sizeof(cache_file), ".bin"); - return stb_dirtree_get_with_file(dir, cache_file); -} - -stb_dirtree *stb_dirtree_get(char *dir) -{ - char cache_dir[256]; - stb_p_strcpy_s(cache_dir, sizeof(cache_dir), "c:/bindata"); - #ifdef STB_HAS_REGISTRY - { - void *reg = stb_reg_open("rHKLM", "Software\\SilverSpaceship\\stb"); - if (reg) { - stb_reg_read(reg, "dirtree", cache_dir, sizeof(cache_dir)); - stb_reg_close(reg); - } - } - #endif - return stb_dirtree_get_dir(dir, cache_dir); -} - -void stb_dirtree_free(stb_dirtree *d) -{ - stb__dirtree_free_raw(d); - free(d); -} - -void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last) -{ - stb__dirtree_add_dir(path, last, active); -} - -void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last) -{ - stb__dirtree_add_file(name, dir, size, last, active); -} - -void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir) -{ - char *s = stb_strip_final_slash(stb_p_strdup(dir)); - target->dirs = 0; - target->files = 0; - target->string_pool = 0; - stb__dirtree_load_db(filename, target, s); - free(s); -} - -void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir) -{ - stb__dirtree_save_db(filename, target, 0); // don't strip out any directories -} - -#endif // STB_DEFINE - -#endif // _WIN32 -#endif // STB_NO_STB_STRINGS - -////////////////////////////////////////////////////////////////////////////// -// -// STB_MALLOC_WRAPPER -// -// you can use the wrapper functions with your own malloc wrapper, -// or define STB_MALLOC_WRAPPER project-wide to have -// malloc/free/realloc/strdup all get vectored to it - -// this has too many very specific error messages you could google for and find in stb.h, -// so don't use it if they don't want any stb.h-identifiable strings -#if defined(STB_DEFINE) && !defined(STB_NO_STB_STRINGS) - -typedef struct -{ - void *p; - char *file; - int line; - size_t size; -} stb_malloc_record; - -#ifndef STB_MALLOC_HISTORY_COUNT -#define STB_MALLOC_HISTORY_COUNT 50 // 800 bytes -#endif - -stb_malloc_record *stb__allocations; -static int stb__alloc_size, stb__alloc_limit, stb__alloc_mask; -int stb__alloc_count; - -stb_malloc_record stb__alloc_history[STB_MALLOC_HISTORY_COUNT]; -int stb__history_pos; - -static int stb__hashfind(void *p) -{ - stb_uint32 h = stb_hashptr(p); - int s,n = h & stb__alloc_mask; - if (stb__allocations[n].p == p) - return n; - s = stb_rehash(h)|1; - for(;;) { - if (stb__allocations[n].p == NULL) - return -1; - n = (n+s) & stb__alloc_mask; - if (stb__allocations[n].p == p) - return n; - } -} - -size_t stb_wrapper_allocsize(void *p) -{ - int n = stb__hashfind(p); - if (n < 0) return 0; - return stb__allocations[n].size; -} - -static int stb__historyfind(void *p) -{ - int n = stb__history_pos; - int i; - for (i=0; i < STB_MALLOC_HISTORY_COUNT; ++i) { - if (--n < 0) n = STB_MALLOC_HISTORY_COUNT-1; - if (stb__alloc_history[n].p == p) - return n; - } - return -1; -} - -static void stb__add_alloc(void *p, size_t sz, char *file, int line); -static void stb__grow_alloc(void) -{ - int i,old_num = stb__alloc_size; - stb_malloc_record *old = stb__allocations; - if (stb__alloc_size == 0) - stb__alloc_size = 64; - else - stb__alloc_size *= 2; - - stb__allocations = (stb_malloc_record *) stb__realloc_raw(NULL, stb__alloc_size * sizeof(stb__allocations[0])); - if (stb__allocations == NULL) - stb_fatal("Internal error: couldn't grow malloc wrapper table"); - memset(stb__allocations, 0, stb__alloc_size * sizeof(stb__allocations[0])); - stb__alloc_limit = (stb__alloc_size*3)>>2; - stb__alloc_mask = stb__alloc_size-1; - - stb__alloc_count = 0; - - for (i=0; i < old_num; ++i) - if (old[i].p > STB_DEL) { - stb__add_alloc(old[i].p, old[i].size, old[i].file, old[i].line); - assert(stb__hashfind(old[i].p) >= 0); - } - for (i=0; i < old_num; ++i) - if (old[i].p > STB_DEL) - assert(stb__hashfind(old[i].p) >= 0); - stb__realloc_raw(old, 0); -} - -static void stb__add_alloc(void *p, size_t sz, char *file, int line) -{ - stb_uint32 h; - int n; - if (stb__alloc_count >= stb__alloc_limit) - stb__grow_alloc(); - h = stb_hashptr(p); - n = h & stb__alloc_mask; - if (stb__allocations[n].p > STB_DEL) { - int s = stb_rehash(h)|1; - do { - n = (n+s) & stb__alloc_mask; - } while (stb__allocations[n].p > STB_DEL); - } - assert(stb__allocations[n].p == NULL || stb__allocations[n].p == STB_DEL); - stb__allocations[n].p = p; - stb__allocations[n].size = sz; - stb__allocations[n].line = line; - stb__allocations[n].file = file; - ++stb__alloc_count; -} - -static void stb__remove_alloc(int n, char *file, int line) -{ - stb__alloc_history[stb__history_pos] = stb__allocations[n]; - stb__alloc_history[stb__history_pos].file = file; - stb__alloc_history[stb__history_pos].line = line; - if (++stb__history_pos == STB_MALLOC_HISTORY_COUNT) - stb__history_pos = 0; - stb__allocations[n].p = STB_DEL; - --stb__alloc_count; -} - -void stb_wrapper_malloc(void *p, size_t sz, char *file, int line) -{ - if (!p) return; - stb__add_alloc(p,sz,file,line); -} - -void stb_wrapper_free(void *p, char *file, int line) -{ - int n; - - if (p == NULL) return; - - n = stb__hashfind(p); - - if (n >= 0) - stb__remove_alloc(n, file, line); - else { - // tried to free something we hadn't allocated! - n = stb__historyfind(p); - assert(0); /* NOTREACHED */ - if (n >= 0) - stb_fatal("Attempted to free %d-byte block %p at %s:%d previously freed/realloced at %s:%d", - stb__alloc_history[n].size, p, - file, line, - stb__alloc_history[n].file, stb__alloc_history[n].line); - else - stb_fatal("Attempted to free unknown block %p at %s:%d", p, file,line); - } -} - -void stb_wrapper_check(void *p) -{ - int n; - - if (p == NULL) return; - - n = stb__hashfind(p); - - if (n >= 0) return; - - for (n=0; n < stb__alloc_size; ++n) - if (stb__allocations[n].p == p) - stb_fatal("Internal error: pointer %p was allocated, but hash search failed", p); - - // tried to free something that wasn't allocated! - n = stb__historyfind(p); - if (n >= 0) - stb_fatal("Checked %d-byte block %p previously freed/realloced at %s:%d", - stb__alloc_history[n].size, p, - stb__alloc_history[n].file, stb__alloc_history[n].line); - stb_fatal("Checked unknown block %p"); -} - -void stb_wrapper_realloc(void *p, void *q, size_t sz, char *file, int line) -{ - int n; - if (p == NULL) { stb_wrapper_malloc(q, sz, file, line); return; } - if (q == NULL) return; // nothing happened - - n = stb__hashfind(p); - if (n == -1) { - // tried to free something we hadn't allocated! - // this is weird, though, because we got past the realloc! - n = stb__historyfind(p); - assert(0); /* NOTREACHED */ - if (n >= 0) - stb_fatal("Attempted to realloc %d-byte block %p at %s:%d previously freed/realloced at %s:%d", - stb__alloc_history[n].size, p, - file, line, - stb__alloc_history[n].file, stb__alloc_history[n].line); - else - stb_fatal("Attempted to realloc unknown block %p at %s:%d", p, file,line); - } else { - if (q == p) { - stb__allocations[n].size = sz; - stb__allocations[n].file = file; - stb__allocations[n].line = line; - } else { - stb__remove_alloc(n, file, line); - stb__add_alloc(q,sz,file,line); - } - } -} - -void stb_wrapper_listall(void (*func)(void *ptr, size_t sz, char *file, int line)) -{ - int i; - for (i=0; i < stb__alloc_size; ++i) - if (stb__allocations[i].p > STB_DEL) - func(stb__allocations[i].p , stb__allocations[i].size, - stb__allocations[i].file, stb__allocations[i].line); -} - -void stb_wrapper_dump(char *filename) -{ - int i; - FILE *f = stb_p_fopen(filename, "w"); - if (!f) return; - for (i=0; i < stb__alloc_size; ++i) - if (stb__allocations[i].p > STB_DEL) - fprintf(f, "%p %7d - %4d %s\n", - stb__allocations[i].p , (int) stb__allocations[i].size, - stb__allocations[i].line, stb__allocations[i].file); -} -#endif // STB_DEFINE - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_pointer_set -// -// -// For data structures that support querying by key, data structure -// classes always hand-wave away the issue of what to do if two entries -// have the same key: basically, store a linked list of all the nodes -// which have the same key (a LISP-style list). -// -// The thing is, it's not that trivial. If you have an O(log n) -// lookup data structure, but then n/4 items have the same value, -// you don't want to spend O(n) time scanning that list when -// deleting an item if you already have a pointer to the item. -// (You have to spend O(n) time enumerating all the items with -// a given key, sure, and you can't accelerate deleting a particular -// item if you only have the key, not a pointer to the item.) -// -// I'm going to call this data structure, whatever it turns out to -// be, a "pointer set", because we don't store any associated data for -// items in this data structure, we just answer the question of -// whether an item is in it or not (it's effectively one bit per pointer). -// Technically they don't have to be pointers; you could cast ints -// to (void *) if you want, but you can't store 0 or 1 because of the -// hash table. -// -// Since the fastest data structure we might want to add support for -// identical-keys to is a hash table with O(1)-ish lookup time, -// that means that the conceptual "linked list of all items with -// the same indexed value" that we build needs to have the same -// performance; that way when we index a table we think is arbitrary -// ints, but in fact half of them are 0, we don't get screwed. -// -// Therefore, it needs to be a hash table, at least when it gets -// large. On the other hand, when the data has totally arbitrary ints -// or floats, there won't be many collisions, and we'll have tons of -// 1-item bitmaps. That will be grossly inefficient as hash tables; -// trade-off; the hash table is reasonably efficient per-item when -// it's large, but not when it's small. So we need to do something -// Judy-like and use different strategies depending on the size. -// -// Like Judy, we'll use the bottom bit to encode the strategy: -// -// bottom bits: -// 00 - direct pointer -// 01 - 4-item bucket (16 bytes, no length, NULLs) -// 10 - N-item array -// 11 - hash table - -typedef struct stb_ps stb_ps; - -STB_EXTERN int stb_ps_find (stb_ps *ps, void *value); -STB_EXTERN stb_ps * stb_ps_add (stb_ps *ps, void *value); -STB_EXTERN stb_ps * stb_ps_remove(stb_ps *ps, void *value); -STB_EXTERN stb_ps * stb_ps_remove_any(stb_ps *ps, void **value); -STB_EXTERN void stb_ps_delete(stb_ps *ps); -STB_EXTERN int stb_ps_count (stb_ps *ps); - -STB_EXTERN stb_ps * stb_ps_copy (stb_ps *ps); -STB_EXTERN int stb_ps_subset(stb_ps *bigger, stb_ps *smaller); -STB_EXTERN int stb_ps_eq (stb_ps *p0, stb_ps *p1); - -STB_EXTERN void ** stb_ps_getlist (stb_ps *ps, int *count); -STB_EXTERN int stb_ps_writelist(stb_ps *ps, void **list, int size ); - -// enum and fastlist don't allocate storage, but you must consume the -// list before there's any chance the data structure gets screwed up; -STB_EXTERN int stb_ps_enum (stb_ps *ps, void *data, - int (*func)(void *value, void*data) ); -STB_EXTERN void ** stb_ps_fastlist(stb_ps *ps, int *count); -// result: -// returns a list, *count is the length of that list, -// but some entries of the list may be invalid; -// test with 'stb_ps_fastlist_valid(x)' - -#define stb_ps_fastlist_valid(x) ((stb_uinta) (x) > 1) - -#ifdef STB_DEFINE - -enum -{ - STB_ps_direct = 0, - STB_ps_bucket = 1, - STB_ps_array = 2, - STB_ps_hash = 3, -}; - -#define STB_BUCKET_SIZE 4 - -typedef struct -{ - void *p[STB_BUCKET_SIZE]; -} stb_ps_bucket; -#define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket)) -#define EncodeBucket(p) ((stb_ps *) ((char *) (p) + STB_ps_bucket)) - -static void stb_bucket_free(stb_ps_bucket *b) -{ - free(b); -} - -static stb_ps_bucket *stb_bucket_create2(void *v0, void *v1) -{ - stb_ps_bucket *b = (stb_ps_bucket*) malloc(sizeof(*b)); - b->p[0] = v0; - b->p[1] = v1; - b->p[2] = NULL; - b->p[3] = NULL; - return b; -} - -static stb_ps_bucket * stb_bucket_create3(void **v) -{ - stb_ps_bucket *b = (stb_ps_bucket*) malloc(sizeof(*b)); - b->p[0] = v[0]; - b->p[1] = v[1]; - b->p[2] = v[2]; - b->p[3] = NULL; - return b; -} - - -// could use stb_arr, but this will save us memory -typedef struct -{ - int count; - void *p[1]; -} stb_ps_array; -#define GetArray(p) ((stb_ps_array *) ((char *) (p) - STB_ps_array)) -#define EncodeArray(p) ((stb_ps *) ((char *) (p) + STB_ps_array)) - -static int stb_ps_array_max = 13; - -typedef struct -{ - int size, mask; - int count, count_deletes; - int grow_threshhold; - int shrink_threshhold; - int rehash_threshhold; - int any_offset; - void *table[1]; -} stb_ps_hash; -#define GetHash(p) ((stb_ps_hash *) ((char *) (p) - STB_ps_hash)) -#define EncodeHash(p) ((stb_ps *) ((char *) (p) + STB_ps_hash)) - -#define stb_ps_empty(v) (((stb_uint32) v) <= 1) - -static stb_ps_hash *stb_ps_makehash(int size, int old_size, void **old_data) -{ - int i; - stb_ps_hash *h = (stb_ps_hash *) malloc(sizeof(*h) + (size-1) * sizeof(h->table[0])); - assert(stb_is_pow2(size)); - h->size = size; - h->mask = size-1; - h->shrink_threshhold = (int) (0.3f * size); - h-> grow_threshhold = (int) (0.8f * size); - h->rehash_threshhold = (int) (0.9f * size); - h->count = 0; - h->count_deletes = 0; - h->any_offset = 0; - memset(h->table, 0, size * sizeof(h->table[0])); - for (i=0; i < old_size; ++i) - if (!stb_ps_empty((size_t)old_data[i])) - stb_ps_add(EncodeHash(h), old_data[i]); - return h; -} - -void stb_ps_delete(stb_ps *ps) -{ - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: break; - case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break; - case STB_ps_array : free(GetArray(ps)); break; - case STB_ps_hash : free(GetHash(ps)); break; - } -} - -stb_ps *stb_ps_copy(stb_ps *ps) -{ - int i; - // not a switch: order based on expected performance/power-law distribution - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: return ps; - case STB_ps_bucket: { - stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n)); - *n = *GetBucket(ps); - return EncodeBucket(n); - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - stb_ps_array *n = (stb_ps_array *) malloc(sizeof(*n) + stb_ps_array_max * sizeof(n->p[0])); - n->count = a->count; - for (i=0; i < a->count; ++i) - n->p[i] = a->p[i]; - return EncodeArray(n); - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - stb_ps_hash *n = stb_ps_makehash(h->size, h->size, h->table); - return EncodeHash(n); - } - } - assert(0); /* NOTREACHED */ - return NULL; -} - -int stb_ps_find(stb_ps *ps, void *value) -{ - int i, code = 3 & (int)(size_t) ps; - assert((3 & (int)(size_t) value) == STB_ps_direct); - assert(stb_ps_fastlist_valid(value)); - // not a switch: order based on expected performance/power-law distribution - if (code == STB_ps_direct) - return value == ps; - if (code == STB_ps_bucket) { - stb_ps_bucket *b = GetBucket(ps); - assert(STB_BUCKET_SIZE == 4); - if (b->p[0] == value || b->p[1] == value || - b->p[2] == value || b->p[3] == value) - return STB_TRUE; - return STB_FALSE; - } - if (code == STB_ps_array) { - stb_ps_array *a = GetArray(ps); - for (i=0; i < a->count; ++i) - if (a->p[i] == value) - return STB_TRUE; - return STB_FALSE; - } else { - stb_ps_hash *h = GetHash(ps); - stb_uint32 hash = stb_hashptr(value); - stb_uint32 s, n = hash & h->mask; - void **t = h->table; - if (t[n] == value) return STB_TRUE; - if (t[n] == NULL) return STB_FALSE; - s = stb_rehash(hash) | 1; - do { - n = (n + s) & h->mask; - if (t[n] == value) return STB_TRUE; - } while (t[n] != NULL); - return STB_FALSE; - } -} - -stb_ps * stb_ps_add (stb_ps *ps, void *value) -{ - #ifdef STB_DEBUG - assert(!stb_ps_find(ps,value)); - #endif - if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage - assert((3 & (int)(size_t) value) == STB_ps_direct); - assert(stb_ps_fastlist_valid(value)); - assert(value != STB_DEL); // STB_DEL is less likely - - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - if (ps == NULL) return (stb_ps *) value; - return EncodeBucket(stb_bucket_create2(ps,value)); - - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - stb_ps_array *a; - assert(STB_BUCKET_SIZE == 4); - if (b->p[0] == NULL) { b->p[0] = value; return ps; } - if (b->p[1] == NULL) { b->p[1] = value; return ps; } - if (b->p[2] == NULL) { b->p[2] = value; return ps; } - if (b->p[3] == NULL) { b->p[3] = value; return ps; } - a = (stb_ps_array *) malloc(sizeof(*a) + 7 * sizeof(a->p[0])); // 8 slots, must be 2^k - memcpy(a->p, b, sizeof(*b)); - a->p[4] = value; - a->count = 5; - stb_bucket_free(b); - return EncodeArray(a); - } - - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - if (a->count == stb_ps_array_max) { - // promote from array to hash - stb_ps_hash *h = stb_ps_makehash(2 << stb_log2_ceil(a->count), a->count, a->p); - free(a); - return stb_ps_add(EncodeHash(h), value); - } - // do we need to resize the array? the array doubles in size when it - // crosses a power-of-two - if ((a->count & (a->count-1))==0) { - int newsize = a->count*2; - // clamp newsize to max if: - // 1. it's larger than max - // 2. newsize*1.5 is larger than max (to avoid extra resizing) - if (newsize + a->count > stb_ps_array_max) - newsize = stb_ps_array_max; - a = (stb_ps_array *) realloc(a, sizeof(*a) + (newsize-1) * sizeof(a->p[0])); - } - a->p[a->count++] = value; - return EncodeArray(a); - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - stb_uint32 hash = stb_hashptr(value); - stb_uint32 n = hash & h->mask; - void **t = h->table; - // find first NULL or STB_DEL entry - if (!stb_ps_empty((size_t)t[n])) { - stb_uint32 s = stb_rehash(hash) | 1; - do { - n = (n + s) & h->mask; - } while (!stb_ps_empty((size_t)t[n])); - } - if (t[n] == STB_DEL) - -- h->count_deletes; - t[n] = value; - ++ h->count; - if (h->count == h->grow_threshhold) { - stb_ps_hash *h2 = stb_ps_makehash(h->size*2, h->size, t); - free(h); - return EncodeHash(h2); - } - if (h->count + h->count_deletes == h->rehash_threshhold) { - stb_ps_hash *h2 = stb_ps_makehash(h->size, h->size, t); - free(h); - return EncodeHash(h2); - } - return ps; - } - } - return NULL; /* NOTREACHED */ -} - -stb_ps *stb_ps_remove(stb_ps *ps, void *value) -{ - #ifdef STB_DEBUG - assert(stb_ps_find(ps, value)); - #endif - assert((3 & (int)(size_t) value) == STB_ps_direct); - if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - return ps == value ? NULL : ps; - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - int count=0; - assert(STB_BUCKET_SIZE == 4); - if (b->p[0] == value) b->p[0] = NULL; else count += (b->p[0] != NULL); - if (b->p[1] == value) b->p[1] = NULL; else count += (b->p[1] != NULL); - if (b->p[2] == value) b->p[2] = NULL; else count += (b->p[2] != NULL); - if (b->p[3] == value) b->p[3] = NULL; else count += (b->p[3] != NULL); - if (count == 1) { // shrink bucket at size 1 - value = b->p[0]; - if (value == NULL) value = b->p[1]; - if (value == NULL) value = b->p[2]; - if (value == NULL) value = b->p[3]; - assert(value != NULL); - stb_bucket_free(b); - return (stb_ps *) value; // return STB_ps_direct of value - } - return ps; - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - int i; - for (i=0; i < a->count; ++i) { - if (a->p[i] == value) { - a->p[i] = a->p[--a->count]; - if (a->count == 3) { // shrink to bucket! - stb_ps_bucket *b = stb_bucket_create3(a->p); - free(a); - return EncodeBucket(b); - } - return ps; - } - } - return ps; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - stb_uint32 hash = stb_hashptr(value); - stb_uint32 s, n = hash & h->mask; - void **t = h->table; - if (t[n] != value) { - s = stb_rehash(hash) | 1; - do { - n = (n + s) & h->mask; - } while (t[n] != value); - } - t[n] = STB_DEL; - -- h->count; - ++ h->count_deletes; - // should we shrink down to an array? - if (h->count < stb_ps_array_max) { - int n = 1 << stb_log2_floor(stb_ps_array_max); - if (h->count < n) { - stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0])); - int i,j=0; - for (i=0; i < h->size; ++i) - if (!stb_ps_empty((size_t)t[i])) - a->p[j++] = t[i]; - assert(j == h->count); - a->count = j; - free(h); - return EncodeArray(a); - } - } - if (h->count == h->shrink_threshhold) { - stb_ps_hash *h2 = stb_ps_makehash(h->size >> 1, h->size, t); - free(h); - return EncodeHash(h2); - } - return ps; - } - } - return ps; /* NOTREACHED */ -} - -stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) -{ - assert(ps != NULL); - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - *value = ps; - return NULL; - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - int count=0, slast=0, last=0; - assert(STB_BUCKET_SIZE == 4); - if (b->p[0]) { ++count; last = 0; } - if (b->p[1]) { ++count; slast = last; last = 1; } - if (b->p[2]) { ++count; slast = last; last = 2; } - if (b->p[3]) { ++count; slast = last; last = 3; } - *value = b->p[last]; - b->p[last] = 0; - if (count == 2) { - void *leftover = b->p[slast]; // second to last - stb_bucket_free(b); - return (stb_ps *) leftover; - } - return ps; - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - *value = a->p[a->count-1]; - if (a->count == 4) - return stb_ps_remove(ps, *value); - --a->count; - return ps; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - void **t = h->table; - stb_uint32 n = h->any_offset; - while (stb_ps_empty((size_t)t[n])) - n = (n + 1) & h->mask; - *value = t[n]; - h->any_offset = (n+1) & h->mask; - // check if we need to skip down to the previous type - if (h->count-1 < stb_ps_array_max || h->count-1 == h->shrink_threshhold) - return stb_ps_remove(ps, *value); - t[n] = STB_DEL; - -- h->count; - ++ h->count_deletes; - return ps; - } - } - return ps; /* NOTREACHED */ -} - - -void ** stb_ps_getlist(stb_ps *ps, int *count) -{ - int i,n=0; - void **p = NULL; - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - if (ps == NULL) { *count = 0; return NULL; } - p = (void **) malloc(sizeof(*p) * 1); - p[0] = ps; - *count = 1; - return p; - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - p = (void **) malloc(sizeof(*p) * STB_BUCKET_SIZE); - for (i=0; i < STB_BUCKET_SIZE; ++i) - if (b->p[i] != NULL) - p[n++] = b->p[i]; - break; - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - p = (void **) malloc(sizeof(*p) * a->count); - memcpy(p, a->p, sizeof(*p) * a->count); - *count = a->count; - return p; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - p = (void **) malloc(sizeof(*p) * h->count); - for (i=0; i < h->size; ++i) - if (!stb_ps_empty((size_t)h->table[i])) - p[n++] = h->table[i]; - break; - } - } - *count = n; - return p; -} - -int stb_ps_writelist(stb_ps *ps, void **list, int size ) -{ - int i,n=0; - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - if (ps == NULL || size <= 0) return 0; - list[0] = ps; - return 1; - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - for (i=0; i < STB_BUCKET_SIZE; ++i) - if (b->p[i] != NULL && n < size) - list[n++] = b->p[i]; - return n; - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - n = stb_min(size, a->count); - memcpy(list, a->p, sizeof(*list) * n); - return n; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - if (size <= 0) return 0; - for (i=0; i < h->count; ++i) { - if (!stb_ps_empty((size_t)h->table[i])) { - list[n++] = h->table[i]; - if (n == size) break; - } - } - return n; - } - } - return 0; /* NOTREACHED */ -} - -int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) -{ - int i; - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - if (ps == NULL) return STB_TRUE; - return func(ps, data); - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - for (i=0; i < STB_BUCKET_SIZE; ++i) - if (b->p[i] != NULL) - if (!func(b->p[i], data)) - return STB_FALSE; - return STB_TRUE; - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - for (i=0; i < a->count; ++i) - if (!func(a->p[i], data)) - return STB_FALSE; - return STB_TRUE; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - for (i=0; i < h->count; ++i) - if (!stb_ps_empty((size_t)h->table[i])) - if (!func(h->table[i], data)) - return STB_FALSE; - return STB_TRUE; - } - } - return STB_TRUE; /* NOTREACHED */ -} - -int stb_ps_count (stb_ps *ps) -{ - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - return ps != NULL; - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - return (b->p[0] != NULL) + (b->p[1] != NULL) + - (b->p[2] != NULL) + (b->p[3] != NULL); - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - return a->count; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - return h->count; - } - } - return 0; -} - -void ** stb_ps_fastlist(stb_ps *ps, int *count) -{ - static void *storage; - - switch (3 & (int)(size_t) ps) { - case STB_ps_direct: - if (ps == NULL) { *count = 0; return NULL; } - storage = ps; - *count = 1; - return &storage; - case STB_ps_bucket: { - stb_ps_bucket *b = GetBucket(ps); - *count = STB_BUCKET_SIZE; - return b->p; - } - case STB_ps_array: { - stb_ps_array *a = GetArray(ps); - *count = a->count; - return a->p; - } - case STB_ps_hash: { - stb_ps_hash *h = GetHash(ps); - *count = h->size; - return h->table; - } - } - return NULL; /* NOTREACHED */ -} - -int stb_ps_subset(stb_ps *bigger, stb_ps *smaller) -{ - int i, listlen; - void **list = stb_ps_fastlist(smaller, &listlen); - for(i=0; i < listlen; ++i) - if (stb_ps_fastlist_valid(list[i])) - if (!stb_ps_find(bigger, list[i])) - return 0; - return 1; -} - -int stb_ps_eq(stb_ps *p0, stb_ps *p1) -{ - if (stb_ps_count(p0) != stb_ps_count(p1)) - return 0; - return stb_ps_subset(p0, p1); -} - -#undef GetBucket -#undef GetArray -#undef GetHash - -#undef EncodeBucket -#undef EncodeArray -#undef EncodeHash - -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// Random Numbers via Meresenne Twister or LCG -// - -STB_EXTERN unsigned int stb_srandLCG(unsigned int seed); -STB_EXTERN unsigned int stb_randLCG(void); -STB_EXTERN double stb_frandLCG(void); - -STB_EXTERN void stb_srand(unsigned int seed); -STB_EXTERN unsigned int stb_rand(void); -STB_EXTERN double stb_frand(void); -STB_EXTERN void stb_shuffle(void *p, size_t n, size_t sz, - unsigned int seed); -STB_EXTERN void stb_reverse(void *p, size_t n, size_t sz); - -STB_EXTERN unsigned int stb_randLCG_explicit(unsigned int seed); - -#define stb_rand_define(x,y) \ - \ - unsigned int x(void) \ - { \ - static unsigned int stb__rand = y; \ - stb__rand = stb__rand * 2147001325 + 715136305; /* BCPL */ \ - return 0x31415926 ^ ((stb__rand >> 16) + (stb__rand << 16)); \ - } - -#ifdef STB_DEFINE -unsigned int stb_randLCG_explicit(unsigned int seed) -{ - return seed * 2147001325 + 715136305; -} - -static unsigned int stb__rand_seed=0; - -unsigned int stb_srandLCG(unsigned int seed) -{ - unsigned int previous = stb__rand_seed; - stb__rand_seed = seed; - return previous; -} - -unsigned int stb_randLCG(void) -{ - stb__rand_seed = stb__rand_seed * 2147001325 + 715136305; // BCPL generator - // shuffle non-random bits to the middle, and xor to decorrelate with seed - return 0x31415926 ^ ((stb__rand_seed >> 16) + (stb__rand_seed << 16)); -} - -double stb_frandLCG(void) -{ - return stb_randLCG() / ((double) (1 << 16) * (1 << 16)); -} - -void stb_shuffle(void *p, size_t n, size_t sz, unsigned int seed) -{ - char *a; - unsigned int old_seed; - int i; - if (seed) - old_seed = stb_srandLCG(seed); - a = (char *) p + (n-1) * sz; - - for (i=(int) n; i > 1; --i) { - int j = stb_randLCG() % i; - stb_swap(a, (char *) p + j * sz, sz); - a -= sz; - } - if (seed) - stb_srandLCG(old_seed); -} - -void stb_reverse(void *p, size_t n, size_t sz) -{ - size_t i,j = n-1; - for (i=0; i < j; ++i,--j) { - stb_swap((char *) p + i * sz, (char *) p + j * sz, sz); - } -} - -// public domain Mersenne Twister by Michael Brundage -#define STB__MT_LEN 624 - -int stb__mt_index = STB__MT_LEN*sizeof(int)+1; -unsigned int stb__mt_buffer[STB__MT_LEN]; - -void stb_srand(unsigned int seed) -{ - int i; - stb__mt_buffer[0]= seed & 0xffffffffUL; - for (i=1 ; i < STB__MT_LEN; ++i) - stb__mt_buffer[i] = (1812433253UL * (stb__mt_buffer[i-1] ^ (stb__mt_buffer[i-1] >> 30)) + i); - stb__mt_index = STB__MT_LEN*sizeof(unsigned int); -} - -#define STB__MT_IA 397 -#define STB__MT_IB (STB__MT_LEN - STB__MT_IA) -#define STB__UPPER_MASK 0x80000000 -#define STB__LOWER_MASK 0x7FFFFFFF -#define STB__MATRIX_A 0x9908B0DF -#define STB__TWIST(b,i,j) ((b)[i] & STB__UPPER_MASK) | ((b)[j] & STB__LOWER_MASK) -#define STB__MAGIC(s) (((s)&1)*STB__MATRIX_A) - -unsigned int stb_rand() -{ - unsigned int * b = stb__mt_buffer; - int idx = stb__mt_index; - unsigned int s,r; - int i; - - if (idx >= STB__MT_LEN*sizeof(unsigned int)) { - if (idx > STB__MT_LEN*sizeof(unsigned int)) - stb_srand(0); - idx = 0; - i = 0; - for (; i < STB__MT_IB; i++) { - s = STB__TWIST(b, i, i+1); - b[i] = b[i + STB__MT_IA] ^ (s >> 1) ^ STB__MAGIC(s); - } - for (; i < STB__MT_LEN-1; i++) { - s = STB__TWIST(b, i, i+1); - b[i] = b[i - STB__MT_IB] ^ (s >> 1) ^ STB__MAGIC(s); - } - - s = STB__TWIST(b, STB__MT_LEN-1, 0); - b[STB__MT_LEN-1] = b[STB__MT_IA-1] ^ (s >> 1) ^ STB__MAGIC(s); - } - stb__mt_index = idx + sizeof(unsigned int); - - r = *(unsigned int *)((unsigned char *)b + idx); - - r ^= (r >> 11); - r ^= (r << 7) & 0x9D2C5680; - r ^= (r << 15) & 0xEFC60000; - r ^= (r >> 18); - - return r; -} - -double stb_frand(void) -{ - return stb_rand() / ((double) (1 << 16) * (1 << 16)); -} - -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_dupe -// -// stb_dupe is a duplicate-finding system for very, very large data -// structures--large enough that sorting is too slow, but not so large -// that we can't keep all the data in memory. using it works as follows: -// -// 1. create an stb_dupe: -// provide a hash function -// provide an equality function -// provide an estimate for the size -// optionally provide a comparison function -// -// 2. traverse your data, 'adding' pointers to the stb_dupe -// -// 3. finish and ask for duplicates -// -// the stb_dupe will discard its intermediate data and build -// a collection of sorted lists of duplicates, with non-duplicate -// entries omitted entirely -// -// -// Implementation strategy: -// -// while collecting the N items, we keep a hash table of approximate -// size sqrt(N). (if you tell use the N up front, the hash table is -// just that size exactly) -// -// each entry in the hash table is just an stb__arr of pointers (no need -// to use stb_ps, because we don't need to delete from these) -// -// for step 3, for each entry in the hash table, we apply stb_dupe to it -// recursively. once the size gets small enough (or doesn't decrease -// significantly), we switch to either using qsort() on the comparison -// function, or else we just do the icky N^2 gather - - -typedef struct stb_dupe stb_dupe; - -typedef int (*stb_compare_func)(void *a, void *b); -typedef int (*stb_hash_func)(void *a, unsigned int seed); - -STB_EXTERN void stb_dupe_free(stb_dupe *sd); -STB_EXTERN stb_dupe *stb_dupe_create(stb_hash_func hash, - stb_compare_func eq, int size, stb_compare_func ineq); -STB_EXTERN void stb_dupe_add(stb_dupe *sd, void *item); -STB_EXTERN void stb_dupe_finish(stb_dupe *sd); -STB_EXTERN int stb_dupe_numsets(stb_dupe *sd); -STB_EXTERN void **stb_dupe_set(stb_dupe *sd, int num); -STB_EXTERN int stb_dupe_set_count(stb_dupe *sd, int num); - -struct stb_dupe -{ - void ***hash_table; - int hash_size; - int size_log2; - int population; - - int hash_shift; - stb_hash_func hash; - - stb_compare_func eq; - stb_compare_func ineq; - - void ***dupes; -}; - -#ifdef STB_DEFINE - -int stb_dupe_numsets(stb_dupe *sd) -{ - assert(sd->hash_table == NULL); - return stb_arr_len(sd->dupes); -} - -void **stb_dupe_set(stb_dupe *sd, int num) -{ - assert(sd->hash_table == NULL); - return sd->dupes[num]; -} - -int stb_dupe_set_count(stb_dupe *sd, int num) -{ - assert(sd->hash_table == NULL); - return stb_arr_len(sd->dupes[num]); -} - -stb_dupe *stb_dupe_create(stb_hash_func hash, stb_compare_func eq, int size, - stb_compare_func ineq) -{ - int i, hsize; - stb_dupe *sd = (stb_dupe *) malloc(sizeof(*sd)); - - sd->size_log2 = 4; - hsize = 1 << sd->size_log2; - while (hsize * hsize < size) { - ++sd->size_log2; - hsize *= 2; - } - - sd->hash = hash; - sd->eq = eq; - sd->ineq = ineq; - sd->hash_shift = 0; - - sd->population = 0; - sd->hash_size = hsize; - sd->hash_table = (void ***) malloc(sizeof(*sd->hash_table) * hsize); - for (i=0; i < hsize; ++i) - sd->hash_table[i] = NULL; - - sd->dupes = NULL; - - return sd; -} - -void stb_dupe_add(stb_dupe *sd, void *item) -{ - stb_uint32 hash = sd->hash(item, sd->hash_shift); - int z = hash & (sd->hash_size-1); - stb_arr_push(sd->hash_table[z], item); - ++sd->population; -} - -void stb_dupe_free(stb_dupe *sd) -{ - int i; - for (i=0; i < stb_arr_len(sd->dupes); ++i) - if (sd->dupes[i]) - stb_arr_free(sd->dupes[i]); - stb_arr_free(sd->dupes); - free(sd); -} - -static stb_compare_func stb__compare; - -static int stb__dupe_compare(const void *a, const void *b) -{ - void *p = *(void **) a; - void *q = *(void **) b; - - return stb__compare(p,q); -} - -void stb_dupe_finish(stb_dupe *sd) -{ - int i,j,k; - assert(sd->dupes == NULL); - for (i=0; i < sd->hash_size; ++i) { - void ** list = sd->hash_table[i]; - if (list != NULL) { - int n = stb_arr_len(list); - // @TODO: measure to find good numbers instead of just making them up! - int thresh = (sd->ineq ? 200 : 20); - // if n is large enough to be worth it, and n is smaller than - // before (so we can guarantee we'll use a smaller hash table); - // and there are enough hash bits left, assuming full 32-bit hash - if (n > thresh && n < (sd->population >> 3) && sd->hash_shift + sd->size_log2*2 < 32) { - - // recursively process this row using stb_dupe, O(N log log N) - - stb_dupe *d = stb_dupe_create(sd->hash, sd->eq, n, sd->ineq); - d->hash_shift = stb_randLCG_explicit(sd->hash_shift); - for (j=0; j < n; ++j) - stb_dupe_add(d, list[j]); - stb_arr_free(sd->hash_table[i]); - stb_dupe_finish(d); - for (j=0; j < stb_arr_len(d->dupes); ++j) { - stb_arr_push(sd->dupes, d->dupes[j]); - d->dupes[j] = NULL; // take over ownership - } - stb_dupe_free(d); - - } else if (sd->ineq) { - - // process this row using qsort(), O(N log N) - stb__compare = sd->ineq; - qsort(list, n, sizeof(list[0]), stb__dupe_compare); - - // find equal subsequences of the list - for (j=0; j < n-1; ) { - // find a subsequence from j..k - for (k=j; k < n; ++k) - // only use ineq so eq can be left undefined - if (sd->ineq(list[j], list[k])) - break; - // k is the first one not in the subsequence - if (k-j > 1) { - void **mylist = NULL; - stb_arr_setlen(mylist, k-j); - memcpy(mylist, list+j, sizeof(list[j]) * (k-j)); - stb_arr_push(sd->dupes, mylist); - } - j = k; - } - stb_arr_free(sd->hash_table[i]); - } else { - - // process this row using eq(), O(N^2) - for (j=0; j < n; ++j) { - if (list[j] != NULL) { - void **output = NULL; - for (k=j+1; k < n; ++k) { - if (sd->eq(list[j], list[k])) { - if (output == NULL) - stb_arr_push(output, list[j]); - stb_arr_push(output, list[k]); - list[k] = NULL; - } - } - list[j] = NULL; - if (output) - stb_arr_push(sd->dupes, output); - } - } - stb_arr_free(sd->hash_table[i]); - } - } - } - free(sd->hash_table); - sd->hash_table = NULL; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// templatized Sort routine -// -// This is an attempt to implement a templated sorting algorithm. -// To use it, you have to explicitly instantiate it as a _function_, -// then you call that function. This allows the comparison to be inlined, -// giving the sort similar performance to C++ sorts. -// -// It implements quicksort with three-way-median partitioning (generally -// well-behaved), with a final insertion sort pass. -// -// When you define the compare expression, you should assume you have -// elements of your array pointed to by 'a' and 'b', and perform the comparison -// on those. OR you can use one or more statements; first say '0;', then -// write whatever code you want, and compute the result into a variable 'c'. - -#define stb_declare_sort(FUNCNAME, TYPE) \ - void FUNCNAME(TYPE *p, int n) -#define stb_define_sort(FUNCNAME,TYPE,COMPARE) \ - stb__define_sort( void, FUNCNAME,TYPE,COMPARE) -#define stb_define_sort_static(FUNCNAME,TYPE,COMPARE) \ - stb__define_sort(static void, FUNCNAME,TYPE,COMPARE) - -#define stb__define_sort(MODE, FUNCNAME, TYPE, COMPARE) \ - \ -static void STB_(FUNCNAME,_ins_sort)(TYPE *p, int n) \ -{ \ - int i,j; \ - for (i=1; i < n; ++i) { \ - TYPE t = p[i], *a = &t; \ - j = i; \ - while (j > 0) { \ - TYPE *b = &p[j-1]; \ - int c = COMPARE; \ - if (!c) break; \ - p[j] = p[j-1]; \ - --j; \ - } \ - if (i != j) \ - p[j] = t; \ - } \ -} \ - \ -static void STB_(FUNCNAME,_quicksort)(TYPE *p, int n) \ -{ \ - /* threshold for transitioning to insertion sort */ \ - while (n > 12) { \ - TYPE *a,*b,t; \ - int c01,c12,c,m,i,j; \ - \ - /* compute median of three */ \ - m = n >> 1; \ - a = &p[0]; \ - b = &p[m]; \ - c = COMPARE; \ - c01 = c; \ - a = &p[m]; \ - b = &p[n-1]; \ - c = COMPARE; \ - c12 = c; \ - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ \ - if (c01 != c12) { \ - /* otherwise, we'll need to swap something else to middle */ \ - int z; \ - a = &p[0]; \ - b = &p[n-1]; \ - c = COMPARE; \ - /* 0>mid && midn => n; 0 0 */ \ - /* 0n: 0>n => 0; 0 n */ \ - z = (c == c12) ? 0 : n-1; \ - t = p[z]; \ - p[z] = p[m]; \ - p[m] = t; \ - } \ - /* now p[m] is the median-of-three */ \ - /* swap it to the beginning so it won't move around */ \ - t = p[0]; \ - p[0] = p[m]; \ - p[m] = t; \ - \ - /* partition loop */ \ - i=1; \ - j=n-1; \ - for(;;) { \ - /* handling of equality is crucial here */ \ - /* for sentinels & efficiency with duplicates */ \ - b = &p[0]; \ - for (;;++i) { \ - a=&p[i]; \ - c = COMPARE; \ - if (!c) break; \ - } \ - a = &p[0]; \ - for (;;--j) { \ - b=&p[j]; \ - c = COMPARE; \ - if (!c) break; \ - } \ - /* make sure we haven't crossed */ \ - if (i >= j) break; \ - t = p[i]; \ - p[i] = p[j]; \ - p[j] = t; \ - \ - ++i; \ - --j; \ - } \ - /* recurse on smaller side, iterate on larger */ \ - if (j < (n-i)) { \ - STB_(FUNCNAME,_quicksort)(p,j); \ - p = p+i; \ - n = n-i; \ - } else { \ - STB_(FUNCNAME,_quicksort)(p+i, n-i); \ - n = j; \ - } \ - } \ -} \ - \ -MODE FUNCNAME(TYPE *p, int n) \ -{ \ - STB_(FUNCNAME, _quicksort)(p, n); \ - STB_(FUNCNAME, _ins_sort)(p, n); \ -} \ - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_bitset an array of booleans indexed by integers -// - -typedef stb_uint32 stb_bitset; - -STB_EXTERN stb_bitset *stb_bitset_new(int value, int len); - -#define stb_bitset_clearall(arr,len) (memset(arr, 0, 4 * (len))) -#define stb_bitset_setall(arr,len) (memset(arr, 255, 4 * (len))) - -#define stb_bitset_setbit(arr,n) ((arr)[(n) >> 5] |= (1 << (n & 31))) -#define stb_bitset_clearbit(arr,n) ((arr)[(n) >> 5] &= ~(1 << (n & 31))) -#define stb_bitset_testbit(arr,n) ((arr)[(n) >> 5] & (1 << (n & 31))) - -STB_EXTERN stb_bitset *stb_bitset_union(stb_bitset *p0, stb_bitset *p1, int len); - -STB_EXTERN int *stb_bitset_getlist(stb_bitset *out, int start, int end); - -STB_EXTERN int stb_bitset_eq(stb_bitset *p0, stb_bitset *p1, int len); -STB_EXTERN int stb_bitset_disjoint(stb_bitset *p0, stb_bitset *p1, int len); -STB_EXTERN int stb_bitset_disjoint_0(stb_bitset *p0, stb_bitset *p1, int len); -STB_EXTERN int stb_bitset_subset(stb_bitset *bigger, stb_bitset *smaller, int len); -STB_EXTERN int stb_bitset_unioneq_changed(stb_bitset *p0, stb_bitset *p1, int len); - -#ifdef STB_DEFINE -int stb_bitset_eq(stb_bitset *p0, stb_bitset *p1, int len) -{ - int i; - for (i=0; i < len; ++i) - if (p0[i] != p1[i]) return 0; - return 1; -} - -int stb_bitset_disjoint(stb_bitset *p0, stb_bitset *p1, int len) -{ - int i; - for (i=0; i < len; ++i) - if (p0[i] & p1[i]) return 0; - return 1; -} - -int stb_bitset_disjoint_0(stb_bitset *p0, stb_bitset *p1, int len) -{ - int i; - for (i=0; i < len; ++i) - if ((p0[i] | p1[i]) != 0xffffffff) return 0; - return 1; -} - -int stb_bitset_subset(stb_bitset *bigger, stb_bitset *smaller, int len) -{ - int i; - for (i=0; i < len; ++i) - if ((bigger[i] & smaller[i]) != smaller[i]) return 0; - return 1; -} - -stb_bitset *stb_bitset_union(stb_bitset *p0, stb_bitset *p1, int len) -{ - int i; - stb_bitset *d = (stb_bitset *) malloc(sizeof(*d) * len); - for (i=0; i < len; ++i) d[i] = p0[i] | p1[i]; - return d; -} - -int stb_bitset_unioneq_changed(stb_bitset *p0, stb_bitset *p1, int len) -{ - int i, changed=0; - for (i=0; i < len; ++i) { - stb_bitset d = p0[i] | p1[i]; - if (d != p0[i]) { - p0[i] = d; - changed = 1; - } - } - return changed; -} - -stb_bitset *stb_bitset_new(int value, int len) -{ - int i; - stb_bitset *d = (stb_bitset *) malloc(sizeof(*d) * len); - if (value) value = 0xffffffff; - for (i=0; i < len; ++i) d[i] = value; - return d; -} - -int *stb_bitset_getlist(stb_bitset *out, int start, int end) -{ - int *list = NULL; - int i; - for (i=start; i < end; ++i) - if (stb_bitset_testbit(out, i)) - stb_arr_push(list, i); - return list; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// stb_wordwrap quality word-wrapping for fixed-width fonts -// - -STB_EXTERN int stb_wordwrap(int *pairs, int pair_max, int count, char *str); -STB_EXTERN int *stb_wordwrapalloc(int count, char *str); - -#ifdef STB_DEFINE - -int stb_wordwrap(int *pairs, int pair_max, int count, char *str) -{ - int n=0,i=0, start=0,nonwhite=0; - if (pairs == NULL) pair_max = 0x7ffffff0; - else pair_max *= 2; - // parse - for(;;) { - int s=i; // first whitespace char; last nonwhite+1 - int w; // word start - // accept whitespace - while (isspace(str[i])) { - if (str[i] == '\n' || str[i] == '\r') { - if (str[i] + str[i+1] == '\n' + '\r') ++i; - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = s-start; - n += 2; - nonwhite=0; - start = i+1; - s = start; - } - ++i; - } - if (i >= start+count) { - // we've gone off the end using whitespace - if (nonwhite) { - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = s-start; - n += 2; - start = s = i; - nonwhite=0; - } else { - // output all the whitespace - while (i >= start+count) { - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = count; - n += 2; - start += count; - } - s = start; - } - } - - if (str[i] == 0) break; - // now scan out a word and see if it fits - w = i; - while (str[i] && !isspace(str[i])) { - ++i; - } - // wrapped? - if (i > start + count) { - // huge? - if (i-s <= count) { - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = s-start; - n += 2; - start = w; - } else { - // This word is longer than one line. If we wrap it onto N lines - // there are leftover chars. do those chars fit on the cur line? - // But if we have leading whitespace, we force it to start here. - if ((w-start) + ((i-w) % count) <= count || !nonwhite) { - // output a full line - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = count; - n += 2; - start += count; - w = start; - } else { - // output a partial line, trimming trailing whitespace - if (s != start) { - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = s-start; - n += 2; - start = w; - } - } - // now output full lines as needed - while (start + count <= i) { - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = count; - n += 2; - start += count; - } - } - } - nonwhite=1; - } - if (start < i) { - if (n >= pair_max) return -1; - if (pairs) pairs[n] = start, pairs[n+1] = i-start; - n += 2; - } - return n>>1; -} - -int *stb_wordwrapalloc(int count, char *str) -{ - int n = stb_wordwrap(NULL,0,count,str); - int *z = NULL; - stb_arr_setlen(z, n*2); - stb_wordwrap(z, n, count, str); - return z; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_match: wildcards and regexping -// - -STB_EXTERN int stb_wildmatch (char *expr, char *candidate); -STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); -STB_EXTERN int stb_wildfind (char *expr, char *candidate); -STB_EXTERN int stb_wildfindi (char *expr, char *candidate); - -STB_EXTERN int stb_regex(char *regex, char *candidate); - -typedef struct stb_matcher stb_matcher; - -STB_EXTERN stb_matcher *stb_regex_matcher(char *regex); -STB_EXTERN int stb_matcher_match(stb_matcher *m, char *str); -STB_EXTERN int stb_matcher_find(stb_matcher *m, char *str); -STB_EXTERN void stb_matcher_free(stb_matcher *f); - -STB_EXTERN stb_matcher *stb_lex_matcher(void); -STB_EXTERN int stb_lex_item(stb_matcher *m, const char *str, int result); -STB_EXTERN int stb_lex_item_wild(stb_matcher *matcher, const char *regex, int result); -STB_EXTERN int stb_lex(stb_matcher *m, char *str, int *len); - - - -#ifdef STB_DEFINE - -static int stb__match_qstring(char *candidate, char *qstring, int qlen, int insensitive) -{ - int i; - if (insensitive) { - for (i=0; i < qlen; ++i) - if (qstring[i] == '?') { - if (!candidate[i]) return 0; - } else - if (tolower(qstring[i]) != tolower(candidate[i])) - return 0; - } else { - for (i=0; i < qlen; ++i) - if (qstring[i] == '?') { - if (!candidate[i]) return 0; - } else - if (qstring[i] != candidate[i]) - return 0; - } - return 1; -} - -static int stb__find_qstring(char *candidate, char *qstring, int qlen, int insensitive) -{ - char c; - - int offset=0; - while (*qstring == '?') { - ++qstring; - --qlen; - ++candidate; - if (qlen == 0) return 0; - if (*candidate == 0) return -1; - } - - c = *qstring++; - --qlen; - if (insensitive) c = tolower(c); - - while (candidate[offset]) { - if (c == (insensitive ? tolower(candidate[offset]) : candidate[offset])) - if (stb__match_qstring(candidate+offset+1, qstring, qlen, insensitive)) - return offset; - ++offset; - } - - return -1; -} - -int stb__wildmatch_raw2(char *expr, char *candidate, int search, int insensitive) -{ - int where=0; - int start = -1; - - if (!search) { - // parse to first '*' - if (*expr != '*') - start = 0; - while (*expr != '*') { - if (!*expr) - return *candidate == 0 ? 0 : -1; - if (*expr == '?') { - if (!*candidate) return -1; - } else { - if (insensitive) { - if (tolower(*candidate) != tolower(*expr)) - return -1; - } else - if (*candidate != *expr) - return -1; - } - ++candidate, ++expr, ++where; - } - } else { - // 0-length search string - if (!*expr) - return 0; - } - - assert(search || *expr == '*'); - if (!search) - ++expr; - - // implicit '*' at this point - - while (*expr) { - int o=0; - // combine redundant * characters - while (expr[0] == '*') ++expr; - - // ok, at this point, expr[-1] == '*', - // and expr[0] != '*' - - if (!expr[0]) return start >= 0 ? start : 0; - - // now find next '*' - o = 0; - while (expr[o] != '*') { - if (expr[o] == 0) - break; - ++o; - } - // if no '*', scan to end, then match at end - if (expr[o] == 0 && !search) { - int z; - for (z=0; z < o; ++z) - if (candidate[z] == 0) - return -1; - while (candidate[z]) - ++z; - // ok, now check if they match - if (stb__match_qstring(candidate+z-o, expr, o, insensitive)) - return start >= 0 ? start : 0; - return -1; - } else { - // if yes '*', then do stb__find_qmatch on the intervening chars - int n = stb__find_qstring(candidate, expr, o, insensitive); - if (n < 0) - return -1; - if (start < 0) - start = where + n; - expr += o; - candidate += n+o; - } - - if (*expr == 0) { - assert(search); - return start; - } - - assert(*expr == '*'); - ++expr; - } - - return start >= 0 ? start : 0; -} - -int stb__wildmatch_raw(char *expr, char *candidate, int search, int insensitive) -{ - char buffer[256]; - // handle multiple search strings - char *s = strchr(expr, ';'); - char *last = expr; - while (s) { - int z; - // need to allow for non-writeable strings... assume they're small - if (s - last < 256) { - stb_strncpy(buffer, last, (int) (s-last+1)); - buffer[s-last] = 0; - z = stb__wildmatch_raw2(buffer, candidate, search, insensitive); - } else { - *s = 0; - z = stb__wildmatch_raw2(last, candidate, search, insensitive); - *s = ';'; - } - if (z >= 0) return z; - last = s+1; - s = strchr(last, ';'); - } - return stb__wildmatch_raw2(last, candidate, search, insensitive); -} - -int stb_wildmatch(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 0,0) >= 0; -} - -int stb_wildmatchi(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 0,1) >= 0; -} - -int stb_wildfind(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 1,0); -} - -int stb_wildfindi(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 1,1); -} - -typedef struct -{ - stb_int16 transition[256]; -} stb_dfa; - -// an NFA node represents a state you're in; it then has -// an arbitrary number of edges dangling off of it -// note this isn't utf8-y -typedef struct -{ - stb_int16 match; // character/set to match - stb_uint16 node; // output node to go to -} stb_nfa_edge; - -typedef struct -{ - stb_int16 goal; // does reaching this win the prize? - stb_uint8 active; // is this in the active list - stb_nfa_edge *out; - stb_uint16 *eps; // list of epsilon closures -} stb_nfa_node; - -#define STB__DFA_UNDEF -1 -#define STB__DFA_GOAL -2 -#define STB__DFA_END -3 -#define STB__DFA_MGOAL -4 -#define STB__DFA_VALID 0 - -#define STB__NFA_STOP_GOAL -1 - -// compiled regexp -struct stb_matcher -{ - stb_uint16 start_node; - stb_int16 dfa_start; - stb_uint32 *charset; - int num_charset; - int match_start; - stb_nfa_node *nodes; - int does_lex; - - // dfa matcher - stb_dfa * dfa; - stb_uint32 * dfa_mapping; - stb_int16 * dfa_result; - int num_words_per_dfa; -}; - -static int stb__add_node(stb_matcher *matcher) -{ - stb_nfa_node z; - z.active = 0; - z.eps = 0; - z.goal = 0; - z.out = 0; - stb_arr_push(matcher->nodes, z); - return stb_arr_len(matcher->nodes)-1; -} - -static void stb__add_epsilon(stb_matcher *matcher, int from, int to) -{ - assert(from != to); - if (matcher->nodes[from].eps == NULL) - stb_arr_malloc((void **) &matcher->nodes[from].eps, matcher); - stb_arr_push(matcher->nodes[from].eps, to); -} - -static void stb__add_edge(stb_matcher *matcher, int from, int to, int type) -{ - stb_nfa_edge z = { (stb_int16)type, (stb_uint16)to }; - if (matcher->nodes[from].out == NULL) - stb_arr_malloc((void **) &matcher->nodes[from].out, matcher); - stb_arr_push(matcher->nodes[from].out, z); -} - -static char *stb__reg_parse_alt(stb_matcher *m, int s, char *r, stb_uint16 *e); -static char *stb__reg_parse(stb_matcher *matcher, int start, char *regex, stb_uint16 *end) -{ - int n; - int last_start = -1; - stb_uint16 last_end = start; - - while (*regex) { - switch (*regex) { - case '(': - last_start = last_end; - regex = stb__reg_parse_alt(matcher, last_end, regex+1, &last_end); - if (regex == NULL || *regex != ')') - return NULL; - ++regex; - break; - - case '|': - case ')': - *end = last_end; - return regex; - - case '?': - if (last_start < 0) return NULL; - stb__add_epsilon(matcher, last_start, last_end); - ++regex; - break; - - case '*': - if (last_start < 0) return NULL; - stb__add_epsilon(matcher, last_start, last_end); - - // fall through - - case '+': - if (last_start < 0) return NULL; - stb__add_epsilon(matcher, last_end, last_start); - // prevent links back to last_end from chaining to last_start - n = stb__add_node(matcher); - stb__add_epsilon(matcher, last_end, n); - last_end = n; - ++regex; - break; - - case '{': // not supported! - // @TODO: given {n,m}, clone last_start to last_end m times, - // and include epsilons from start to first m-n blocks - return NULL; - - case '\\': - ++regex; - if (!*regex) return NULL; - - // fallthrough - default: // match exactly this character - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, *regex); - last_start = last_end; - last_end = n; - ++regex; - break; - - case '$': - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, '\n'); - last_start = last_end; - last_end = n; - ++regex; - break; - - case '.': - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, -1); - last_start = last_end; - last_end = n; - ++regex; - break; - - case '[': { - stb_uint8 flags[256]; - int invert = 0,z; - ++regex; - if (matcher->num_charset == 0) { - matcher->charset = (stb_uint *) stb_malloc(matcher, sizeof(*matcher->charset) * 256); - memset(matcher->charset, 0, sizeof(*matcher->charset) * 256); - } - - memset(flags,0,sizeof(flags)); - - // leading ^ is special - if (*regex == '^') - ++regex, invert = 1; - - // leading ] is special - if (*regex == ']') { - flags[(int) ']'] = 1; - ++regex; - } - while (*regex != ']') { - stb_uint a; - if (!*regex) return NULL; - a = *regex++; - if (regex[0] == '-' && regex[1] != ']') { - stb_uint i,b = regex[1]; - regex += 2; - if (b == 0) return NULL; - if (a > b) return NULL; - for (i=a; i <= b; ++i) - flags[i] = 1; - } else - flags[a] = 1; - } - ++regex; - if (invert) { - int i; - for (i=0; i < 256; ++i) - flags[i] = 1-flags[i]; - } - - // now check if any existing charset matches - for (z=0; z < matcher->num_charset; ++z) { - int i, k[2] = { 0, 1 << z}; - for (i=0; i < 256; ++i) { - unsigned int f = k[flags[i]]; - if ((matcher->charset[i] & k[1]) != f) - break; - } - if (i == 256) break; - } - - if (z == matcher->num_charset) { - int i; - ++matcher->num_charset; - if (matcher->num_charset > 32) { - assert(0); /* NOTREACHED */ - return NULL; // too many charsets, oops - } - for (i=0; i < 256; ++i) - if (flags[i]) - matcher->charset[i] |= (1 << z); - } - - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, -2 - z); - last_start = last_end; - last_end = n; - break; - } - } - } - *end = last_end; - return regex; -} - -static char *stb__reg_parse_alt(stb_matcher *matcher, int start, char *regex, stb_uint16 *end) -{ - stb_uint16 last_end = start; - stb_uint16 main_end; - - int head, tail; - - head = stb__add_node(matcher); - stb__add_epsilon(matcher, start, head); - - regex = stb__reg_parse(matcher, head, regex, &last_end); - if (regex == NULL) return NULL; - if (*regex == 0 || *regex == ')') { - *end = last_end; - return regex; - } - - main_end = last_end; - tail = stb__add_node(matcher); - - stb__add_epsilon(matcher, last_end, tail); - - // start alternatives from the same starting node; use epsilon - // transitions to combine their endings - while(*regex && *regex != ')') { - assert(*regex == '|'); - head = stb__add_node(matcher); - stb__add_epsilon(matcher, start, head); - regex = stb__reg_parse(matcher, head, regex+1, &last_end); - if (regex == NULL) - return NULL; - stb__add_epsilon(matcher, last_end, tail); - } - - *end = tail; - return regex; -} - -static char *stb__wild_parse(stb_matcher *matcher, int start, char *str, stb_uint16 *end) -{ - int n; - stb_uint16 last_end; - - last_end = stb__add_node(matcher); - stb__add_epsilon(matcher, start, last_end); - - while (*str) { - switch (*str) { - // fallthrough - default: // match exactly this character - n = stb__add_node(matcher); - if (toupper(*str) == tolower(*str)) { - stb__add_edge(matcher, last_end, n, *str); - } else { - stb__add_edge(matcher, last_end, n, tolower(*str)); - stb__add_edge(matcher, last_end, n, toupper(*str)); - } - last_end = n; - ++str; - break; - - case '?': - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, -1); - last_end = n; - ++str; - break; - - case '*': - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, -1); - stb__add_epsilon(matcher, last_end, n); - stb__add_epsilon(matcher, n, last_end); - last_end = n; - ++str; - break; - } - } - - // now require end of string to match - n = stb__add_node(matcher); - stb__add_edge(matcher, last_end, n, 0); - last_end = n; - - *end = last_end; - return str; -} - -static int stb__opt(stb_matcher *m, int n) -{ - for(;;) { - stb_nfa_node *p = &m->nodes[n]; - if (p->goal) return n; - if (stb_arr_len(p->out)) return n; - if (stb_arr_len(p->eps) != 1) return n; - n = p->eps[0]; - } -} - -static void stb__optimize(stb_matcher *m) -{ - // if the target of any edge is a node with exactly - // one out-epsilon, shorten it - int i,j; - for (i=0; i < stb_arr_len(m->nodes); ++i) { - stb_nfa_node *p = &m->nodes[i]; - for (j=0; j < stb_arr_len(p->out); ++j) - p->out[j].node = stb__opt(m,p->out[j].node); - for (j=0; j < stb_arr_len(p->eps); ++j) - p->eps[j] = stb__opt(m,p->eps[j] ); - } - m->start_node = stb__opt(m,m->start_node); -} - -void stb_matcher_free(stb_matcher *f) -{ - stb_free(f); -} - -static stb_matcher *stb__alloc_matcher(void) -{ - stb_matcher *matcher = (stb_matcher *) stb_malloc(0,sizeof(*matcher)); - - matcher->start_node = 0; - stb_arr_malloc((void **) &matcher->nodes, matcher); - matcher->num_charset = 0; - matcher->match_start = 0; - matcher->does_lex = 0; - - matcher->dfa_start = STB__DFA_UNDEF; - stb_arr_malloc((void **) &matcher->dfa, matcher); - stb_arr_malloc((void **) &matcher->dfa_mapping, matcher); - stb_arr_malloc((void **) &matcher->dfa_result, matcher); - - stb__add_node(matcher); - - return matcher; -} - -static void stb__lex_reset(stb_matcher *matcher) -{ - // flush cached dfa data - stb_arr_setlen(matcher->dfa, 0); - stb_arr_setlen(matcher->dfa_mapping, 0); - stb_arr_setlen(matcher->dfa_result, 0); - matcher->dfa_start = STB__DFA_UNDEF; -} - -stb_matcher *stb_regex_matcher(char *regex) -{ - char *z; - stb_uint16 end; - stb_matcher *matcher = stb__alloc_matcher(); - if (*regex == '^') { - matcher->match_start = 1; - ++regex; - } - - z = stb__reg_parse_alt(matcher, matcher->start_node, regex, &end); - - if (!z || *z) { - stb_free(matcher); - return NULL; - } - - ((matcher->nodes)[(int) end]).goal = STB__NFA_STOP_GOAL; - - return matcher; -} - -stb_matcher *stb_lex_matcher(void) -{ - stb_matcher *matcher = stb__alloc_matcher(); - - matcher->match_start = 1; - matcher->does_lex = 1; - - return matcher; -} - -int stb_lex_item(stb_matcher *matcher, const char *regex, int result) -{ - char *z; - stb_uint16 end; - - z = stb__reg_parse_alt(matcher, matcher->start_node, (char*) regex, &end); - - if (z == NULL) - return 0; - - stb__lex_reset(matcher); - - matcher->nodes[(int) end].goal = result; - return 1; -} - -int stb_lex_item_wild(stb_matcher *matcher, const char *regex, int result) -{ - char *z; - stb_uint16 end; - - z = stb__wild_parse(matcher, matcher->start_node, (char*) regex, &end); - - if (z == NULL) - return 0; - - stb__lex_reset(matcher); - - matcher->nodes[(int) end].goal = result; - return 1; -} - -static void stb__clear(stb_matcher *m, stb_uint16 *list) -{ - int i; - for (i=0; i < stb_arr_len(list); ++i) - m->nodes[(int) list[i]].active = 0; -} - -static int stb__clear_goalcheck(stb_matcher *m, stb_uint16 *list) -{ - int i, t=0; - for (i=0; i < stb_arr_len(list); ++i) { - t += m->nodes[(int) list[i]].goal; - m->nodes[(int) list[i]].active = 0; - } - return t; -} - -static stb_uint16 * stb__add_if_inactive(stb_matcher *m, stb_uint16 *list, int n) -{ - if (!m->nodes[n].active) { - stb_arr_push(list, n); - m->nodes[n].active = 1; - } - return list; -} - -static stb_uint16 * stb__eps_closure(stb_matcher *m, stb_uint16 *list) -{ - int i,n = stb_arr_len(list); - - for(i=0; i < n; ++i) { - stb_uint16 *e = m->nodes[(int) list[i]].eps; - if (e) { - int j,k = stb_arr_len(e); - for (j=0; j < k; ++j) - list = stb__add_if_inactive(m, list, e[j]); - n = stb_arr_len(list); - } - } - - return list; -} - -int stb_matcher_match(stb_matcher *m, char *str) -{ - int result = 0; - int i,j,y,z; - stb_uint16 *previous = NULL; - stb_uint16 *current = NULL; - stb_uint16 *temp; - - stb_arr_setsize(previous, 4); - stb_arr_setsize(current, 4); - - previous = stb__add_if_inactive(m, previous, m->start_node); - previous = stb__eps_closure(m,previous); - stb__clear(m, previous); - - while (*str && stb_arr_len(previous)) { - y = stb_arr_len(previous); - for (i=0; i < y; ++i) { - stb_nfa_node *n = &m->nodes[(int) previous[i]]; - z = stb_arr_len(n->out); - for (j=0; j < z; ++j) { - if (n->out[j].match >= 0) { - if (n->out[j].match == *str) - current = stb__add_if_inactive(m, current, n->out[j].node); - } else if (n->out[j].match == -1) { - if (*str != '\n') - current = stb__add_if_inactive(m, current, n->out[j].node); - } else if (n->out[j].match < -1) { - int z = -n->out[j].match - 2; - if (m->charset[(stb_uint8) *str] & (1 << z)) - current = stb__add_if_inactive(m, current, n->out[j].node); - } - } - } - stb_arr_setlen(previous, 0); - - temp = previous; - previous = current; - current = temp; - - previous = stb__eps_closure(m,previous); - stb__clear(m, previous); - - ++str; - } - - // transition to pick up a '$' at the end - y = stb_arr_len(previous); - for (i=0; i < y; ++i) - m->nodes[(int) previous[i]].active = 1; - - for (i=0; i < y; ++i) { - stb_nfa_node *n = &m->nodes[(int) previous[i]]; - z = stb_arr_len(n->out); - for (j=0; j < z; ++j) { - if (n->out[j].match == '\n') - current = stb__add_if_inactive(m, current, n->out[j].node); - } - } - - previous = stb__eps_closure(m,previous); - stb__clear(m, previous); - - y = stb_arr_len(previous); - for (i=0; i < y; ++i) - if (m->nodes[(int) previous[i]].goal) - result = 1; - - stb_arr_free(previous); - stb_arr_free(current); - - return result && *str == 0; -} - -stb_int16 stb__get_dfa_node(stb_matcher *m, stb_uint16 *list) -{ - stb_uint16 node; - stb_uint32 data[8], *state, *newstate; - int i,j,n; - - state = (stb_uint32 *) stb_temp(data, m->num_words_per_dfa * 4); - memset(state, 0, m->num_words_per_dfa*4); - - n = stb_arr_len(list); - for (i=0; i < n; ++i) { - int x = list[i]; - state[x >> 5] |= 1 << (x & 31); - } - - // @TODO use a hash table - n = stb_arr_len(m->dfa_mapping); - i=j=0; - for(; j < n; ++i, j += m->num_words_per_dfa) { - // @TODO special case for <= 32 - if (!memcmp(state, m->dfa_mapping + j, m->num_words_per_dfa*4)) { - node = i; - goto done; - } - } - - assert(stb_arr_len(m->dfa) == i); - node = i; - - newstate = stb_arr_addn(m->dfa_mapping, m->num_words_per_dfa); - memcpy(newstate, state, m->num_words_per_dfa*4); - - // set all transitions to 'unknown' - stb_arr_add(m->dfa); - memset(m->dfa[i].transition, -1, sizeof(m->dfa[i].transition)); - - if (m->does_lex) { - int result = -1; - n = stb_arr_len(list); - for (i=0; i < n; ++i) { - if (m->nodes[(int) list[i]].goal > result) - result = m->nodes[(int) list[i]].goal; - } - - stb_arr_push(m->dfa_result, result); - } - -done: - stb_tempfree(data, state); - return node; -} - -static int stb__matcher_dfa(stb_matcher *m, char *str_c, int *len) -{ - stb_uint8 *str = (stb_uint8 *) str_c; - stb_int16 node,prevnode; - stb_dfa *trans; - int match_length = 0; - stb_int16 match_result=0; - - if (m->dfa_start == STB__DFA_UNDEF) { - stb_uint16 *list; - - m->num_words_per_dfa = (stb_arr_len(m->nodes)+31) >> 5; - stb__optimize(m); - - list = stb__add_if_inactive(m, NULL, m->start_node); - list = stb__eps_closure(m,list); - if (m->does_lex) { - m->dfa_start = stb__get_dfa_node(m,list); - stb__clear(m, list); - // DON'T allow start state to be a goal state! - // this allows people to specify regexes that can match 0 - // characters without them actually matching (also we don't - // check _before_ advancing anyway - if (m->dfa_start <= STB__DFA_MGOAL) - m->dfa_start = -(m->dfa_start - STB__DFA_MGOAL); - } else { - if (stb__clear_goalcheck(m, list)) - m->dfa_start = STB__DFA_GOAL; - else - m->dfa_start = stb__get_dfa_node(m,list); - } - stb_arr_free(list); - } - - prevnode = STB__DFA_UNDEF; - node = m->dfa_start; - trans = m->dfa; - - if (m->dfa_start == STB__DFA_GOAL) - return 1; - - for(;;) { - assert(node >= STB__DFA_VALID); - - // fast inner DFA loop; especially if STB__DFA_VALID is 0 - - do { - prevnode = node; - node = trans[node].transition[*str++]; - } while (node >= STB__DFA_VALID); - - assert(node >= STB__DFA_MGOAL - stb_arr_len(m->dfa)); - assert(node < stb_arr_len(m->dfa)); - - // special case for lex: need _longest_ match, so notice goal - // state without stopping - if (node <= STB__DFA_MGOAL) { - match_length = (int) (str - (stb_uint8 *) str_c); - node = -(node - STB__DFA_MGOAL); - match_result = node; - continue; - } - - // slow NFA->DFA conversion - - // or we hit the goal or the end of the string, but those - // can only happen once per search... - - if (node == STB__DFA_UNDEF) { - // build a list -- @TODO special case <= 32 states - // heck, use a more compact data structure for <= 16 and <= 8 ?! - - // @TODO keep states/newstates around instead of reallocating them - stb_uint16 *states = NULL; - stb_uint16 *newstates = NULL; - int i,j,y,z; - stb_uint32 *flags = &m->dfa_mapping[prevnode * m->num_words_per_dfa]; - assert(prevnode != STB__DFA_UNDEF); - stb_arr_setsize(states, 4); - stb_arr_setsize(newstates,4); - for (j=0; j < m->num_words_per_dfa; ++j) { - for (i=0; i < 32; ++i) { - if (*flags & (1 << i)) - stb_arr_push(states, j*32+i); - } - ++flags; - } - // states is now the states we were in in the previous node; - // so now we can compute what node it transitions to on str[-1] - - y = stb_arr_len(states); - for (i=0; i < y; ++i) { - stb_nfa_node *n = &m->nodes[(int) states[i]]; - z = stb_arr_len(n->out); - for (j=0; j < z; ++j) { - if (n->out[j].match >= 0) { - if (n->out[j].match == str[-1] || (str[-1] == 0 && n->out[j].match == '\n')) - newstates = stb__add_if_inactive(m, newstates, n->out[j].node); - } else if (n->out[j].match == -1) { - if (str[-1] != '\n' && str[-1]) - newstates = stb__add_if_inactive(m, newstates, n->out[j].node); - } else if (n->out[j].match < -1) { - int z = -n->out[j].match - 2; - if (m->charset[str[-1]] & (1 << z)) - newstates = stb__add_if_inactive(m, newstates, n->out[j].node); - } - } - } - // AND add in the start state! - if (!m->match_start || (str[-1] == '\n' && !m->does_lex)) - newstates = stb__add_if_inactive(m, newstates, m->start_node); - // AND epsilon close it - newstates = stb__eps_closure(m, newstates); - // if it's a goal state, then that's all there is to it - if (stb__clear_goalcheck(m, newstates)) { - if (m->does_lex) { - match_length = (int) (str - (stb_uint8 *) str_c); - node = stb__get_dfa_node(m,newstates); - match_result = node; - node = -node + STB__DFA_MGOAL; - trans = m->dfa; // could have gotten realloc()ed - } else - node = STB__DFA_GOAL; - } else if (str[-1] == 0 || stb_arr_len(newstates) == 0) { - node = STB__DFA_END; - } else { - node = stb__get_dfa_node(m,newstates); - trans = m->dfa; // could have gotten realloc()ed - } - trans[prevnode].transition[str[-1]] = node; - if (node <= STB__DFA_MGOAL) - node = -(node - STB__DFA_MGOAL); - stb_arr_free(newstates); - stb_arr_free(states); - } - - if (node == STB__DFA_GOAL) { - return 1; - } - if (node == STB__DFA_END) { - if (m->does_lex) { - if (match_result) { - if (len) *len = match_length; - return m->dfa_result[(int) match_result]; - } - } - return 0; - } - - assert(node != STB__DFA_UNDEF); - } -} - -int stb_matcher_find(stb_matcher *m, char *str) -{ - assert(m->does_lex == 0); - return stb__matcher_dfa(m, str, NULL); -} - -int stb_lex(stb_matcher *m, char *str, int *len) -{ - assert(m->does_lex); - return stb__matcher_dfa(m, str, len); -} - -#ifdef STB_PERFECT_HASH -int stb_regex(char *regex, char *str) -{ - static stb_perfect p; - static stb_matcher ** matchers; - static char ** regexps; - static char ** regexp_cache; - static unsigned short *mapping; - int z = stb_perfect_hash(&p, (int)(size_t) regex); - if (z >= 0) { - if (strcmp(regex, regexp_cache[(int) mapping[z]])) { - int i = mapping[z]; - stb_matcher_free(matchers[i]); - free(regexp_cache[i]); - regexps[i] = regex; - regexp_cache[i] = stb_p_strdup(regex); - matchers[i] = stb_regex_matcher(regex); - } - } else { - int i,n; - if (regex == NULL) { - for (i=0; i < stb_arr_len(matchers); ++i) { - stb_matcher_free(matchers[i]); - free(regexp_cache[i]); - } - stb_arr_free(matchers); - stb_arr_free(regexps); - stb_arr_free(regexp_cache); - stb_perfect_destroy(&p); - free(mapping); mapping = NULL; - return -1; - } - stb_arr_push(regexps, regex); - stb_arr_push(regexp_cache, stb_p_strdup(regex)); - stb_arr_push(matchers, stb_regex_matcher(regex)); - stb_perfect_destroy(&p); - n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps)); - mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping)); - for (i=0; i < stb_arr_len(regexps); ++i) - mapping[stb_perfect_hash(&p, (int)(size_t) regexps[i])] = i; - z = stb_perfect_hash(&p, (int)(size_t) regex); - } - return stb_matcher_find(matchers[(int) mapping[z]], str); -} -#endif -#endif // STB_DEFINE - - -#if 0 -////////////////////////////////////////////////////////////////////////////// -// -// C source-code introspection -// - -// runtime structure -typedef struct -{ - char *name; - char *type; // base type - char *comment; // content of comment field - int size; // size of base type - int offset; // field offset - int arrcount[8]; // array sizes; -1 = pointer indirection; 0 = end of list -} stb_info_field; - -typedef struct -{ - char *structname; - int size; - int num_fields; - stb_info_field *fields; -} stb_info_struct; - -extern stb_info_struct stb_introspect_output[]; - -// - -STB_EXTERN void stb_introspect_precompiled(stb_info_struct *compiled); -STB_EXTERN void stb__introspect(char *path, char *file); - -#define stb_introspect_ship() stb__introspect(NULL, NULL, stb__introspect_output) - -#ifdef STB_SHIP -#define stb_introspect() stb_introspect_ship() -#define stb_introspect_path(p) stb_introspect_ship() -#else -// bootstrapping: define stb_introspect() (or 'path') the first time -#define stb_introspect() stb__introspect(NULL, __FILE__, NULL) -#define stb_introspect_auto() stb__introspect(NULL, __FILE__, stb__introspect_output) - -#define stb_introspect_path(p) stb__introspect(p, __FILE__, NULL) -#define stb_introspect_path(p) stb__introspect(p, __FILE__, NULL) -#endif - -#ifdef STB_DEFINE - -#ifndef STB_INTROSPECT_CPP - #ifdef __cplusplus - #define STB_INTROSPECT_CPP 1 - #else - #define STB_INTROSPECT_CPP 0 - #endif -#endif - -void stb_introspect_precompiled(stb_info_struct *compiled) -{ - -} - - -static void stb__introspect_filename(char *buffer, char *path) -{ - #if STB_INTROSPECT_CPP - stb_p_sprintf(buffer stb_p_size(9999), "%s/stb_introspect.cpp", path); - #else - stb_p_sprintf(buffer stb_p_size(9999), "%s/stb_introspect.c", path); - #endif -} - -static void stb__introspect_compute(char *path, char *file) -{ - int i; - char ** include_list = NULL; - char ** introspect_list = NULL; - FILE *f; - f = stb_p_fopen(file, "w"); - if (!f) return; - - fputs("// if you get compiler errors, change the following 0 to a 1:\n", f); - fputs("#define STB_INTROSPECT_INVALID 0\n\n", f); - fputs("// this will force the code to compile, and force the introspector\n", f); - fputs("// to run and then exit, allowing you to recompile\n\n\n", f); - fputs("#include \"stb.h\"\n\n",f ); - fputs("#if STB_INTROSPECT_INVALID\n", f); - fputs(" stb_info_struct stb__introspect_output[] = { (void *) 1 }\n", f); - fputs("#else\n\n", f); - for (i=0; i < stb_arr_len(include_list); ++i) - fprintf(f, " #include \"%s\"\n", include_list[i]); - - fputs(" stb_info_struct stb__introspect_output[] =\n{\n", f); - for (i=0; i < stb_arr_len(introspect_list); ++i) - fprintf(f, " stb_introspect_%s,\n", introspect_list[i]); - fputs(" };\n", f); - fputs("#endif\n", f); - fclose(f); -} - -static stb_info_struct *stb__introspect_info; - -#ifndef STB_SHIP - -#endif - -void stb__introspect(char *path, char *file, stb_info_struct *compiled) -{ - static int first=1; - if (!first) return; - first=0; - - stb__introspect_info = compiled; - - #ifndef STB_SHIP - if (path || file) { - int bail_flag = compiled && compiled[0].structname == (void *) 1; - int needs_building = bail_flag; - struct stb__stat st; - char buffer[1024], buffer2[1024]; - if (!path) { - stb_splitpath(buffer, file, STB_PATH); - path = buffer; - } - // bail if the source path doesn't exist - if (!stb_fexists(path)) return; - - stb__introspect_filename(buffer2, path); - - // get source/include files timestamps, compare to output-file timestamp; - // if mismatched, regenerate - - if (stb__stat(buffer2, &st)) - needs_building = STB_TRUE; - - { - // find any file that contains an introspection command and is newer - // if needs_building is already true, we don't need to do this test, - // but we still need these arrays, so go ahead and get them - char **all[3]; - all[0] = stb_readdir_files_mask(path, "*.h"); - all[1] = stb_readdir_files_mask(path, "*.c"); - all[2] = stb_readdir_files_mask(path, "*.cpp"); - int i,j; - if (needs_building) { - for (j=0; j < 3; ++j) { - for (i=0; i < stb_arr_len(all[j]); ++i) { - struct stb__stat st2; - if (!stb__stat(all[j][i], &st2)) { - if (st.st_mtime < st2.st_mtime) { - char *z = stb_filec(all[j][i], NULL); - int found=STB_FALSE; - while (y) { - y = strstr(y, "//si"); - if (y && isspace(y[4])) { - found = STB_TRUE; - break; - } - } - needs_building = STB_TRUE; - goto done; - } - } - } - } - done:; - } - char *z = stb_filec(all[i], NULL), *y = z; - int found=STB_FALSE; - while (y) { - y = strstr(y, "//si"); - if (y && isspace(y[4])) { - found = STB_TRUE; - break; - } - } - if (found) - stb_arr_push(introspect_h, stb_p_strdup(all[i])); - free(z); - } - } - stb_readdir_free(all); - if (!needs_building) { - for (i=0; i < stb_arr_len(introspect_h); ++i) { - struct stb__stat st2; - if (!stb__stat(introspect_h[i], &st2)) - if (st.st_mtime < st2.st_mtime) - needs_building = STB_TRUE; - } - } - - if (needs_building) { - stb__introspect_compute(path, buffer2); - } - } - } - #endif -} -#endif -#endif - -#ifdef STB_INTROSPECT -// compile-time code-generator -#define INTROSPECT(x) int main(int argc, char **argv) { stb__introspect(__FILE__); return 0; } -#define FILE(x) - -void stb__introspect(char *filename) -{ - char *file = stb_file(filename, NULL); - char *s = file, *t, **p; - char *out_name = "stb_introspect.c"; - char *out_path; - STB_ARR(char) filelist = NULL; - int i,n; - if (!file) stb_fatal("Couldn't open %s", filename); - - out_path = stb_splitpathdup(filename, STB_PATH); - - // search for the macros - while (*s) { - char buffer[256]; - while (*s && !isupper(*s)) ++s; - s = stb_strtok_invert(buffer, s, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - s = stb_skipwhite(s); - if (*s == '(') { - ++s; - t = strchr(s, ')'); - if (t == NULL) stb_fatal("Error parsing %s", filename); - - } - } -} - - - -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// STB-C sliding-window dictionary compression -// -// This uses a DEFLATE-style sliding window, but no bitwise entropy. -// Everything is on byte boundaries, so you could then apply a byte-wise -// entropy code, though that's nowhere near as effective. -// -// An STB-C stream begins with a 16-byte header: -// 4 bytes: 0x57 0xBC 0x00 0x00 -// 8 bytes: big-endian size of decompressed data, 64-bits -// 4 bytes: big-endian size of window (how far back decompressor may need) -// -// The following symbols appear in the stream (these were determined ad hoc, -// not by analysis): -// -// [dict] 00000100 yyyyyyyy yyyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx -// [END] 00000101 11111010 cccccccc cccccccc cccccccc cccccccc -// [dict] 00000110 yyyyyyyy yyyyyyyy yyyyyyyy xxxxxxxx -// [literals] 00000111 zzzzzzzz zzzzzzzz -// [literals] 00001zzz zzzzzzzz -// [dict] 00010yyy yyyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx -// [dict] 00011yyy yyyyyyyy yyyyyyyy xxxxxxxx -// [literals] 001zzzzz -// [dict] 01yyyyyy yyyyyyyy xxxxxxxx -// [dict] 1xxxxxxx yyyyyyyy -// -// xxxxxxxx: match length - 1 -// yyyyyyyy: backwards distance - 1 -// zzzzzzzz: num literals - 1 -// cccccccc: adler32 checksum of decompressed data -// (all big-endian) - - -STB_EXTERN stb_uint stb_decompress_length(stb_uchar *input); -STB_EXTERN stb_uint stb_decompress(stb_uchar *out,stb_uchar *in,stb_uint len); -STB_EXTERN stb_uint stb_compress (stb_uchar *out,stb_uchar *in,stb_uint len); -STB_EXTERN void stb_compress_window(int z); -STB_EXTERN void stb_compress_hashsize(unsigned int z); - -STB_EXTERN int stb_compress_tofile(char *filename, char *in, stb_uint len); -STB_EXTERN int stb_compress_intofile(FILE *f, char *input, stb_uint len); -STB_EXTERN char *stb_decompress_fromfile(char *filename, stb_uint *len); - -STB_EXTERN int stb_compress_stream_start(FILE *f); -STB_EXTERN void stb_compress_stream_end(int close); -STB_EXTERN void stb_write(char *data, int data_len); - -#ifdef STB_DEFINE - -stb_uint stb_decompress_length(stb_uchar *input) -{ - return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; -} - -//////////////////// decompressor /////////////////////// - -// simple implementation that just writes whole thing into big block - -static unsigned char *stb__barrier; -static unsigned char *stb__barrier2; -static unsigned char *stb__barrier3; -static unsigned char *stb__barrier4; - -static stb_uchar *stb__dout; -static void stb__match(stb_uchar *data, stb_uint length) -{ - // INVERSE of memmove... write each byte before copying the next... - assert (stb__dout + length <= stb__barrier); - if (stb__dout + length > stb__barrier) { stb__dout += length; return; } - if (data < stb__barrier4) { stb__dout = stb__barrier+1; return; } - while (length--) *stb__dout++ = *data++; -} - -static void stb__lit(stb_uchar *data, stb_uint length) -{ - assert (stb__dout + length <= stb__barrier); - if (stb__dout + length > stb__barrier) { stb__dout += length; return; } - if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } - memcpy(stb__dout, data, length); - stb__dout += length; -} - -#define stb__in2(x) ((i[x] << 8) + i[(x)+1]) -#define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) -#define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) - -static stb_uchar *stb_decompress_token(stb_uchar *i) -{ - if (*i >= 0x20) { // use fewer if's for cases that expand small - if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; - else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; - else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); - } else { // more ifs for cases that expand large, since overhead is amortized - if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; - else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; - else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); - else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); - else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; - else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; - } - return i; -} - -stb_uint stb_decompress(stb_uchar *output, stb_uchar *i, stb_uint length) -{ - stb_uint olen; - if (stb__in4(0) != 0x57bC0000) return 0; - if (stb__in4(4) != 0) return 0; // error! stream is > 4GB - olen = stb_decompress_length(i); - stb__barrier2 = i; - stb__barrier3 = i+length; - stb__barrier = output + olen; - stb__barrier4 = output; - i += 16; - - stb__dout = output; - while (1) { - stb_uchar *old_i = i; - i = stb_decompress_token(i); - if (i == old_i) { - if (*i == 0x05 && i[1] == 0xfa) { - assert(stb__dout == output + olen); - if (stb__dout != output + olen) return 0; - if (stb_adler32(1, output, olen) != (stb_uint) stb__in4(2)) - return 0; - return olen; - } else { - assert(0); /* NOTREACHED */ - return 0; - } - } - assert(stb__dout <= output + olen); - if (stb__dout > output + olen) - return 0; - } -} - -char *stb_decompress_fromfile(char *filename, unsigned int *len) -{ - unsigned int n; - char *q; - unsigned char *p; - FILE *f = stb_p_fopen(filename, "rb"); if (f == NULL) return NULL; - fseek(f, 0, SEEK_END); - n = ftell(f); - fseek(f, 0, SEEK_SET); - p = (unsigned char * ) malloc(n); if (p == NULL) return NULL; - fread(p, 1, n, f); - fclose(f); - if (p == NULL) return NULL; - if (p[0] != 0x57 || p[1] != 0xBc || p[2] || p[3]) { free(p); return NULL; } - q = (char *) malloc(stb_decompress_length(p)+1); - if (!q) { free(p); return NULL; } - *len = stb_decompress((unsigned char *) q, p, n); - if (*len) q[*len] = 0; - free(p); - return q; -} - -#if 0 -// streaming decompressor - -static struct -{ - stb__uchar *in_buffer; - stb__uchar *match; - - stb__uint pending_literals; - stb__uint pending_match; -} xx; - - - -static void stb__match(stb_uchar *data, stb_uint length) -{ - // INVERSE of memmove... write each byte before copying the next... - assert (stb__dout + length <= stb__barrier); - if (stb__dout + length > stb__barrier) { stb__dout += length; return; } - if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } - while (length--) *stb__dout++ = *data++; -} - -static void stb__lit(stb_uchar *data, stb_uint length) -{ - assert (stb__dout + length <= stb__barrier); - if (stb__dout + length > stb__barrier) { stb__dout += length; return; } - if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } - memcpy(stb__dout, data, length); - stb__dout += length; -} - -static void sx_match(stb_uchar *data, stb_uint length) -{ - xx.match = data; - xx.pending_match = length; -} - -static void sx_lit(stb_uchar *data, stb_uint length) -{ - xx.pending_lit = length; -} - -static int stb_decompress_token_state(void) -{ - stb__uchar *i = xx.in_buffer; - - if (*i >= 0x20) { // use fewer if's for cases that expand small - if (*i >= 0x80) sx_match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; - else if (*i >= 0x40) sx_match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; - else /* *i >= 0x20 */ sx_lit(i+1, i[0] - 0x20 + 1), i += 1; - } else { // more ifs for cases that expand large, since overhead is amortized - if (*i >= 0x18) sx_match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; - else if (*i >= 0x10) sx_match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; - else if (*i >= 0x08) sx_lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2; - else if (*i == 0x07) sx_lit(i+3, stb__in2(1) + 1), i += 3; - else if (*i == 0x06) sx_match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; - else if (*i == 0x04) sx_match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; - else return 0; - } - xx.in_buffer = i; - return 1; -} -#endif - - - -//////////////////// compressor /////////////////////// - -static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen) -{ - stb_uint i; - for (i=0; i < maxlen; ++i) - if (m1[i] != m2[i]) return i; - return i; -} - -// simple implementation that just takes the source data in a big block - -static stb_uchar *stb__out; -static FILE *stb__outfile; -static stb_uint stb__outbytes; - -static void stb__write(unsigned char v) -{ - fputc(v, stb__outfile); - ++stb__outbytes; -} - -#define stb_out(v) (stb__out ? (void)(*stb__out++ = (stb_uchar) (v)) : stb__write((stb_uchar) (v))) - -static void stb_out2(stb_uint v) -{ - stb_out(v >> 8); - stb_out(v); -} - -static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); } -static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); - stb_out(v >> 8 ); stb_out(v); } - -static void outliterals(stb_uchar *in, ptrdiff_t numlit) -{ - while (numlit > 65536) { - outliterals(in,65536); - in += 65536; - numlit -= 65536; - } - - if (numlit == 0) ; - else if (numlit <= 32) stb_out (0x000020 + (stb_uint) numlit-1); - else if (numlit <= 2048) stb_out2(0x000800 + (stb_uint) numlit-1); - else /* numlit <= 65536) */ stb_out3(0x070000 + (stb_uint) numlit-1); - - if (stb__out) { - memcpy(stb__out,in,numlit); - stb__out += numlit; - } else - fwrite(in, 1, numlit, stb__outfile); -} - -static int stb__window = 0x40000; // 256K -void stb_compress_window(int z) -{ - if (z >= 0x1000000) z = 0x1000000; // limit of implementation - if (z < 0x100) z = 0x100; // insanely small - stb__window = z; -} - -static int stb_not_crap(int best, int dist) -{ - return ((best > 2 && dist <= 0x00100) - || (best > 5 && dist <= 0x04000) - || (best > 7 && dist <= 0x80000)); -} - -static stb_uint stb__hashsize = 32768; -void stb_compress_hashsize(unsigned int y) -{ - unsigned int z = 1024; - while (z < y) z <<= 1; - stb__hashsize = z >> 2; // pass in bytes, store #pointers -} - -// note that you can play with the hashing functions all you -// want without needing to change the decompressor -#define stb__hc(q,h,c) (((h) << 7) + ((h) >> 25) + q[c]) -#define stb__hc2(q,h,c,d) (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d]) -#define stb__hc3(q,c,d,e) ((q[c] << 14) + (q[d] << 7) + q[e]) - -static stb_uint32 stb__running_adler; - -static int stb_compress_chunk(stb_uchar *history, - stb_uchar *start, - stb_uchar *end, - int length, - int *pending_literals, - stb_uchar **chash, - stb_uint mask) -{ - int window = stb__window; - stb_uint match_max; - stb_uchar *lit_start = start - *pending_literals; - stb_uchar *q = start; - - #define STB__SCRAMBLE(h) (((h) + ((h) >> 16)) & mask) - - // stop short of the end so we don't scan off the end doing - // the hashing; this means we won't compress the last few bytes - // unless they were part of something longer - while (q < start+length && q+12 < end) { - int m; - stb_uint h1,h2,h3,h4, h; - stb_uchar *t; - int best = 2, dist=0; - - if (q+65536 > end) - match_max = (stb_uint) (end-q); - else - match_max = 65536u; - - #define stb__nc(b,d) ((d) <= window && ((b) > 9 || stb_not_crap(b,d))) - - #define STB__TRY(t,p) /* avoid retrying a match we already tried */ \ - if (p ? dist != (int) (q-t) : 1) \ - if ((m = (int) stb_matchlen(t, q, match_max)) > best)\ - if (stb__nc(m,(int) (q-(t)))) \ - best = m, dist = (int) (q - (t)) - - // rather than search for all matches, only try 4 candidate locations, - // chosen based on 4 different hash functions of different lengths. - // this strategy is inspired by LZO; hashing is unrolled here using the - // 'hc' macro - h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h); - t = chash[h1]; if (t) STB__TRY(t,0); - h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h); - h = stb__hc2(q,h, 5, 6); t = chash[h2]; if (t) STB__TRY(t,1); - h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h); - h = stb__hc2(q,h, 9,10); t = chash[h3]; if (t) STB__TRY(t,1); - h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h); - t = chash[h4]; if (t) STB__TRY(t,1); - - // because we use a shared hash table, can only update it - // _after_ we've probed all of them - chash[h1] = chash[h2] = chash[h3] = chash[h4] = q; - - if (best > 2) - assert(dist > 0); - - // see if our best match qualifies - if (best < 3) { // fast path literals - ++q; - } else if (best > 2 && best <= 0x80 && dist <= 0x100) { - outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out(0x80 + best-1); - stb_out(dist-1); - } else if (best > 5 && best <= 0x100 && dist <= 0x4000) { - outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out2(0x4000 + dist-1); - stb_out(best-1); - } else if (best > 7 && best <= 0x100 && dist <= 0x80000) { - outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out3(0x180000 + dist-1); - stb_out(best-1); - } else if (best > 8 && best <= 0x10000 && dist <= 0x80000) { - outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out3(0x100000 + dist-1); - stb_out2(best-1); - } else if (best > 9 && dist <= 0x1000000) { - if (best > 65536) best = 65536; - outliterals(lit_start, q-lit_start); lit_start = (q += best); - if (best <= 0x100) { - stb_out(0x06); - stb_out3(dist-1); - stb_out(best-1); - } else { - stb_out(0x04); - stb_out3(dist-1); - stb_out2(best-1); - } - } else { // fallback literals if no match was a balanced tradeoff - ++q; - } - } - - // if we didn't get all the way, add the rest to literals - if (q-start < length) - q = start+length; - - // the literals are everything from lit_start to q - *pending_literals = (int) (q - lit_start); - - stb__running_adler = stb_adler32(stb__running_adler, start, (int) (q - start)); - return (int) (q - start); -} - -static int stb_compress_inner(stb_uchar *input, stb_uint length) -{ - int literals = 0; - stb_uint len,i; - - stb_uchar **chash; - chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*)); - if (chash == NULL) return 0; // failure - for (i=0; i < stb__hashsize; ++i) - chash[i] = NULL; - - // stream signature - stb_out(0x57); stb_out(0xbc); - stb_out2(0); - - stb_out4(0); // 64-bit length requires 32-bit leading 0 - stb_out4(length); - stb_out4(stb__window); - - stb__running_adler = 1; - - len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1); - assert(len == length); - - outliterals(input+length - literals, literals); - - free(chash); - - stb_out2(0x05fa); // end opcode - - stb_out4(stb__running_adler); - - return 1; // success -} - -stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length) -{ - stb__out = out; - stb__outfile = NULL; - - stb_compress_inner(input, length); - - return (stb_uint) (stb__out - out); -} - -int stb_compress_tofile(char *filename, char *input, unsigned int length) -{ - //int maxlen = length + 512 + (length >> 2); // total guess - //char *buffer = (char *) malloc(maxlen); - //int blen = stb_compress((stb_uchar*)buffer, (stb_uchar*)input, length); - - stb__out = NULL; - stb__outfile = stb_p_fopen(filename, "wb"); - if (!stb__outfile) return 0; - - stb__outbytes = 0; - - if (!stb_compress_inner((stb_uchar*)input, length)) - return 0; - - fclose(stb__outfile); - - return stb__outbytes; -} - -int stb_compress_intofile(FILE *f, char *input, unsigned int length) -{ - //int maxlen = length + 512 + (length >> 2); // total guess - //char *buffer = (char*)malloc(maxlen); - //int blen = stb_compress((stb_uchar*)buffer, (stb_uchar*)input, length); - - stb__out = NULL; - stb__outfile = f; - if (!stb__outfile) return 0; - - stb__outbytes = 0; - - if (!stb_compress_inner((stb_uchar*)input, length)) - return 0; - - return stb__outbytes; -} - -////////////////////// streaming I/O version ///////////////////// - - -static size_t stb_out_backpatch_id(void) -{ - if (stb__out) - return (size_t) stb__out; - else - return ftell(stb__outfile); -} - -static void stb_out_backpatch(size_t id, stb_uint value) -{ - stb_uchar data[4] = { (stb_uchar)(value >> 24), (stb_uchar)(value >> 16), (stb_uchar)(value >> 8), (stb_uchar)(value) }; - if (stb__out) { - memcpy((void *) id, data, 4); - } else { - stb_uint where = ftell(stb__outfile); - fseek(stb__outfile, (long) id, SEEK_SET); - fwrite(data, 4, 1, stb__outfile); - fseek(stb__outfile, where, SEEK_SET); - } -} - -// ok, the wraparound buffer was a total failure. let's instead -// use a copying-in-place buffer, which lets us share the code. -// This is way less efficient but it'll do for now. - -static struct -{ - stb_uchar *buffer; - int size; // physical size of buffer in bytes - - int valid; // amount of valid data in bytes - int start; // bytes of data already output - - int window; - int fsize; - - int pending_literals; // bytes not-quite output but counted in start - int length_id; - - stb_uint total_bytes; - - stb_uchar **chash; - stb_uint hashmask; -} xtb; - -static int stb_compress_streaming_start(void) -{ - stb_uint i; - xtb.size = stb__window * 3; - xtb.buffer = (stb_uchar*)malloc(xtb.size); - if (!xtb.buffer) return 0; - - xtb.chash = (stb_uchar**)malloc(sizeof(*xtb.chash) * stb__hashsize); - if (!xtb.chash) { - free(xtb.buffer); - return 0; - } - - for (i=0; i < stb__hashsize; ++i) - xtb.chash[i] = NULL; - - xtb.hashmask = stb__hashsize-1; - - xtb.valid = 0; - xtb.start = 0; - xtb.window = stb__window; - xtb.fsize = stb__window; - xtb.pending_literals = 0; - xtb.total_bytes = 0; - - // stream signature - stb_out(0x57); stb_out(0xbc); stb_out2(0); - - stb_out4(0); // 64-bit length requires 32-bit leading 0 - - xtb.length_id = (int) stb_out_backpatch_id(); - stb_out4(0); // we don't know the output length yet - - stb_out4(stb__window); - - stb__running_adler = 1; - - return 1; -} - -static int stb_compress_streaming_end(void) -{ - // flush out any remaining data - stb_compress_chunk(xtb.buffer, xtb.buffer+xtb.start, xtb.buffer+xtb.valid, - xtb.valid-xtb.start, &xtb.pending_literals, xtb.chash, xtb.hashmask); - - // write out pending literals - outliterals(xtb.buffer + xtb.valid - xtb.pending_literals, xtb.pending_literals); - - stb_out2(0x05fa); // end opcode - stb_out4(stb__running_adler); - - stb_out_backpatch(xtb.length_id, xtb.total_bytes); - - free(xtb.buffer); - free(xtb.chash); - return 1; -} - -void stb_write(char *data, int data_len) -{ - stb_uint i; - - // @TODO: fast path for filling the buffer and doing nothing else - // if (xtb.valid + data_len < xtb.size) - - xtb.total_bytes += data_len; - - while (data_len) { - // fill buffer - if (xtb.valid < xtb.size) { - int amt = xtb.size - xtb.valid; - if (data_len < amt) amt = data_len; - memcpy(xtb.buffer + xtb.valid, data, amt); - data_len -= amt; - data += amt; - xtb.valid += amt; - } - if (xtb.valid < xtb.size) - return; - - // at this point, the buffer is full - - // if we can process some data, go for it; make sure - // we leave an 'fsize's worth of data, though - if (xtb.start + xtb.fsize < xtb.valid) { - int amount = (xtb.valid - xtb.fsize) - xtb.start; - int n; - assert(amount > 0); - n = stb_compress_chunk(xtb.buffer, xtb.buffer + xtb.start, xtb.buffer + xtb.valid, - amount, &xtb.pending_literals, xtb.chash, xtb.hashmask); - xtb.start += n; - } - - assert(xtb.start + xtb.fsize >= xtb.valid); - // at this point, our future size is too small, so we - // need to flush some history. we, in fact, flush exactly - // one window's worth of history - - { - int flush = xtb.window; - assert(xtb.start >= flush); - assert(xtb.valid >= flush); - - // if 'pending literals' extends back into the shift region, - // write them out - if (xtb.start - xtb.pending_literals < flush) { - outliterals(xtb.buffer + xtb.start - xtb.pending_literals, xtb.pending_literals); - xtb.pending_literals = 0; - } - - // now shift the window - memmove(xtb.buffer, xtb.buffer + flush, xtb.valid - flush); - xtb.start -= flush; - xtb.valid -= flush; - - for (i=0; i <= xtb.hashmask; ++i) - if (xtb.chash[i] < xtb.buffer + flush) - xtb.chash[i] = NULL; - else - xtb.chash[i] -= flush; - } - // and now that we've made room for more data, go back to the top - } -} - -int stb_compress_stream_start(FILE *f) -{ - stb__out = NULL; - stb__outfile = f; - - if (f == NULL) - return 0; - - if (!stb_compress_streaming_start()) - return 0; - - return 1; -} - -void stb_compress_stream_end(int close) -{ - stb_compress_streaming_end(); - if (close && stb__outfile) { - fclose(stb__outfile); - } -} - -#endif // STB_DEFINE - -////////////////////////////////////////////////////////////////////////////// -// -// File abstraction... tired of not having this... we can write -// compressors to be layers over these that auto-close their children. - - -typedef struct stbfile -{ - int (*getbyte)(struct stbfile *); // -1 on EOF - unsigned int (*getdata)(struct stbfile *, void *block, unsigned int len); - - int (*putbyte)(struct stbfile *, int byte); - unsigned int (*putdata)(struct stbfile *, void *block, unsigned int len); - - unsigned int (*size)(struct stbfile *); - - unsigned int (*tell)(struct stbfile *); - void (*backpatch)(struct stbfile *, unsigned int tell, void *block, unsigned int len); - - void (*close)(struct stbfile *); - - FILE *f; // file to fread/fwrite - unsigned char *buffer; // input/output buffer - unsigned char *indata, *inend; // input buffer - union { - int various; - void *ptr; - }; -} stbfile; - -STB_EXTERN unsigned int stb_getc(stbfile *f); // read -STB_EXTERN int stb_putc(stbfile *f, int ch); // write -STB_EXTERN unsigned int stb_getdata(stbfile *f, void *buffer, unsigned int len); // read -STB_EXTERN unsigned int stb_putdata(stbfile *f, void *buffer, unsigned int len); // write -STB_EXTERN unsigned int stb_tell(stbfile *f); // read -STB_EXTERN unsigned int stb_size(stbfile *f); // read/write -STB_EXTERN void stb_backpatch(stbfile *f, unsigned int tell, void *buffer, unsigned int len); // write - -#ifdef STB_DEFINE - -unsigned int stb_getc(stbfile *f) { return f->getbyte(f); } -int stb_putc(stbfile *f, int ch) { return f->putbyte(f, ch); } - -unsigned int stb_getdata(stbfile *f, void *buffer, unsigned int len) -{ - return f->getdata(f, buffer, len); -} -unsigned int stb_putdata(stbfile *f, void *buffer, unsigned int len) -{ - return f->putdata(f, buffer, len); -} -void stb_close(stbfile *f) -{ - f->close(f); - free(f); -} -unsigned int stb_tell(stbfile *f) { return f->tell(f); } -unsigned int stb_size(stbfile *f) { return f->size(f); } -void stb_backpatch(stbfile *f, unsigned int tell, void *buffer, unsigned int len) -{ - f->backpatch(f,tell,buffer,len); -} - -// FILE * implementation -static int stb__fgetbyte(stbfile *f) { return fgetc(f->f); } -static int stb__fputbyte(stbfile *f, int ch) { return fputc(ch, f->f)==0; } -static unsigned int stb__fgetdata(stbfile *f, void *buffer, unsigned int len) { return (unsigned int) fread(buffer,1,len,f->f); } -static unsigned int stb__fputdata(stbfile *f, void *buffer, unsigned int len) { return (unsigned int) fwrite(buffer,1,len,f->f); } -static unsigned int stb__fsize(stbfile *f) { return (unsigned int) stb_filelen(f->f); } -static unsigned int stb__ftell(stbfile *f) { return (unsigned int) ftell(f->f); } -static void stb__fbackpatch(stbfile *f, unsigned int where, void *buffer, unsigned int len) -{ - fseek(f->f, where, SEEK_SET); - fwrite(buffer, 1, len, f->f); - fseek(f->f, 0, SEEK_END); -} -static void stb__fclose(stbfile *f) { fclose(f->f); } - -stbfile *stb_openf(FILE *f) -{ - stbfile m = { stb__fgetbyte, stb__fgetdata, - stb__fputbyte, stb__fputdata, - stb__fsize, stb__ftell, stb__fbackpatch, stb__fclose, - 0,0,0, }; - stbfile *z = (stbfile *) malloc(sizeof(*z)); - if (z) { - *z = m; - z->f = f; - } - return z; -} - -static int stb__nogetbyte(stbfile *f) { assert(0); return -1; } -static unsigned int stb__nogetdata(stbfile *f, void *buffer, unsigned int len) { assert(0); return 0; } -static int stb__noputbyte(stbfile *f, int ch) { assert(0); return 0; } -static unsigned int stb__noputdata(stbfile *f, void *buffer, unsigned int len) { assert(0); return 0; } -static void stb__nobackpatch(stbfile *f, unsigned int where, void *buffer, unsigned int len) { assert(0); } - -static int stb__bgetbyte(stbfile *s) -{ - if (s->indata < s->inend) - return *s->indata++; - else - return -1; -} - -static unsigned int stb__bgetdata(stbfile *s, void *buffer, unsigned int len) -{ - if (s->indata + len > s->inend) - len = (unsigned int) (s->inend - s->indata); - memcpy(buffer, s->indata, len); - s->indata += len; - return len; -} -static unsigned int stb__bsize(stbfile *s) { return (unsigned int) (s->inend - s->buffer); } -static unsigned int stb__btell(stbfile *s) { return (unsigned int) (s->indata - s->buffer); } - -static void stb__bclose(stbfile *s) -{ - if (s->various) - free(s->buffer); -} - -stbfile *stb_open_inbuffer(void *buffer, unsigned int len) -{ - stbfile m = { stb__bgetbyte, stb__bgetdata, - stb__noputbyte, stb__noputdata, - stb__bsize, stb__btell, stb__nobackpatch, stb__bclose }; - stbfile *z = (stbfile *) malloc(sizeof(*z)); - if (z) { - *z = m; - z->buffer = (unsigned char *) buffer; - z->indata = z->buffer; - z->inend = z->indata + len; - } - return z; -} - -stbfile *stb_open_inbuffer_free(void *buffer, unsigned int len) -{ - stbfile *z = stb_open_inbuffer(buffer, len); - if (z) - z->various = 1; // free - return z; -} - -#ifndef STB_VERSION -// if we've been cut-and-pasted elsewhere, you get a limited -// version of stb_open, without the 'k' flag and utf8 support -static void stb__fclose2(stbfile *f) -{ - fclose(f->f); -} - -stbfile *stb_open(char *filename, char *mode) -{ - FILE *f = stb_p_fopen(filename, mode); - stbfile *s; - if (f == NULL) return NULL; - s = stb_openf(f); - if (s) - s->close = stb__fclose2; - return s; -} -#else -// the full version depends on some code in stb.h; this -// also includes the memory buffer output format implemented with stb_arr -static void stb__fclose2(stbfile *f) -{ - stb_fclose(f->f, f->various); -} - -stbfile *stb_open(char *filename, char *mode) -{ - FILE *f = stb_fopen(filename, mode[0] == 'k' ? mode+1 : mode); - stbfile *s; - if (f == NULL) return NULL; - s = stb_openf(f); - if (s) { - s->close = stb__fclose2; - s->various = mode[0] == 'k' ? stb_keep_if_different : stb_keep_yes; - } - return s; -} - -static int stb__aputbyte(stbfile *f, int ch) -{ - stb_arr_push(f->buffer, ch); - return 1; -} -static unsigned int stb__aputdata(stbfile *f, void *data, unsigned int len) -{ - memcpy(stb_arr_addn(f->buffer, (int) len), data, len); - return len; -} -static unsigned int stb__asize(stbfile *f) { return stb_arr_len(f->buffer); } -static void stb__abackpatch(stbfile *f, unsigned int where, void *data, unsigned int len) -{ - memcpy(f->buffer+where, data, len); -} -static void stb__aclose(stbfile *f) -{ - *(unsigned char **) f->ptr = f->buffer; -} - -stbfile *stb_open_outbuffer(unsigned char **update_on_close) -{ - stbfile m = { stb__nogetbyte, stb__nogetdata, - stb__aputbyte, stb__aputdata, - stb__asize, stb__asize, stb__abackpatch, stb__aclose }; - stbfile *z = (stbfile *) malloc(sizeof(*z)); - if (z) { - z->ptr = update_on_close; - *z = m; - } - return z; -} -#endif -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// Arithmetic coder... based on cbloom's notes on the subject, should be -// less code than a huffman code. - -typedef struct -{ - unsigned int range_low; - unsigned int range_high; - unsigned int code, range; // decode - int buffered_u8; - int pending_ffs; - stbfile *output; -} stb_arith; - -STB_EXTERN void stb_arith_init_encode(stb_arith *a, stbfile *out); -STB_EXTERN void stb_arith_init_decode(stb_arith *a, stbfile *in); -STB_EXTERN stbfile *stb_arith_encode_close(stb_arith *a); -STB_EXTERN stbfile *stb_arith_decode_close(stb_arith *a); - -STB_EXTERN void stb_arith_encode(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq); -STB_EXTERN void stb_arith_encode_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq); -STB_EXTERN unsigned int stb_arith_decode_value(stb_arith *a, unsigned int totalfreq); -STB_EXTERN void stb_arith_decode_advance(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq); -STB_EXTERN unsigned int stb_arith_decode_value_log2(stb_arith *a, unsigned int totalfreq2); -STB_EXTERN void stb_arith_decode_advance_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq); - -STB_EXTERN void stb_arith_encode_byte(stb_arith *a, int byte); -STB_EXTERN int stb_arith_decode_byte(stb_arith *a); - -// this is a memory-inefficient way of doing things, but it's -// fast(?) and simple -typedef struct -{ - unsigned short cumfreq; - unsigned short samples; -} stb_arith_symstate_item; - -typedef struct -{ - int num_sym; - unsigned int pow2; - int countdown; - stb_arith_symstate_item data[1]; -} stb_arith_symstate; - -#ifdef STB_DEFINE -void stb_arith_init_encode(stb_arith *a, stbfile *out) -{ - a->range_low = 0; - a->range_high = 0xffffffff; - a->pending_ffs = -1; // means no buffered character currently, to speed up normal case - a->output = out; -} - -static void stb__arith_carry(stb_arith *a) -{ - int i; - assert(a->pending_ffs != -1); // can't carry with no data - stb_putc(a->output, a->buffered_u8); - for (i=0; i < a->pending_ffs; ++i) - stb_putc(a->output, 0); -} - -static void stb__arith_putbyte(stb_arith *a, int byte) -{ - if (a->pending_ffs) { - if (a->pending_ffs == -1) { // means no buffered data; encoded for fast path efficiency - if (byte == 0xff) - stb_putc(a->output, byte); // just write it immediately - else { - a->buffered_u8 = byte; - a->pending_ffs = 0; - } - } else if (byte == 0xff) { - ++a->pending_ffs; - } else { - int i; - stb_putc(a->output, a->buffered_u8); - for (i=0; i < a->pending_ffs; ++i) - stb_putc(a->output, 0xff); - } - } else if (byte == 0xff) { - ++a->pending_ffs; - } else { - // fast path - stb_putc(a->output, a->buffered_u8); - a->buffered_u8 = byte; - } -} - -static void stb__arith_flush(stb_arith *a) -{ - if (a->pending_ffs >= 0) { - int i; - stb_putc(a->output, a->buffered_u8); - for (i=0; i < a->pending_ffs; ++i) - stb_putc(a->output, 0xff); - } -} - -static void stb__renorm_encoder(stb_arith *a) -{ - stb__arith_putbyte(a, a->range_low >> 24); - a->range_low <<= 8; - a->range_high = (a->range_high << 8) | 0xff; -} - -static void stb__renorm_decoder(stb_arith *a) -{ - int c = stb_getc(a->output); - a->code = (a->code << 8) + (c >= 0 ? c : 0); // if EOF, insert 0 -} - -void stb_arith_encode(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq) -{ - unsigned int range = a->range_high - a->range_low; - unsigned int old = a->range_low; - range /= totalfreq; - a->range_low += range * cumfreq; - a->range_high = a->range_low + range*freq; - if (a->range_low < old) - stb__arith_carry(a); - while (a->range_high - a->range_low < 0x1000000) - stb__renorm_encoder(a); -} - -void stb_arith_encode_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq) -{ - unsigned int range = a->range_high - a->range_low; - unsigned int old = a->range_low; - range >>= totalfreq2; - a->range_low += range * cumfreq; - a->range_high = a->range_low + range*freq; - if (a->range_low < old) - stb__arith_carry(a); - while (a->range_high - a->range_low < 0x1000000) - stb__renorm_encoder(a); -} - -unsigned int stb_arith_decode_value(stb_arith *a, unsigned int totalfreq) -{ - unsigned int freqsize = a->range / totalfreq; - unsigned int z = a->code / freqsize; - return z >= totalfreq ? totalfreq-1 : z; -} - -void stb_arith_decode_advance(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq) -{ - unsigned int freqsize = a->range / totalfreq; // @OPTIMIZE, share with above divide somehow? - a->code -= freqsize * cumfreq; - a->range = freqsize * freq; - while (a->range < 0x1000000) - stb__renorm_decoder(a); -} - -unsigned int stb_arith_decode_value_log2(stb_arith *a, unsigned int totalfreq2) -{ - unsigned int freqsize = a->range >> totalfreq2; - unsigned int z = a->code / freqsize; - return z >= (1U<range >> totalfreq2; - a->code -= freqsize * cumfreq; - a->range = freqsize * freq; - while (a->range < 0x1000000) - stb__renorm_decoder(a); -} - -stbfile *stb_arith_encode_close(stb_arith *a) -{ - // put exactly as many bytes as we'll read, so we can turn on/off arithmetic coding in a stream - stb__arith_putbyte(a, a->range_low >> 24); - stb__arith_putbyte(a, a->range_low >> 16); - stb__arith_putbyte(a, a->range_low >> 8); - stb__arith_putbyte(a, a->range_low >> 0); - stb__arith_flush(a); - return a->output; -} - -stbfile *stb_arith_decode_close(stb_arith *a) -{ - return a->output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Threads -// - -#ifndef _WIN32 -#ifdef STB_THREADS -#error "threads not implemented except for Windows" -#endif -#endif - -// call this function to free any global variables for memory testing -STB_EXTERN void stb_thread_cleanup(void); - -typedef void * (*stb_thread_func)(void *); - -// do not rely on these types, this is an implementation detail. -// compare against STB_THREAD_NULL and ST_SEMAPHORE_NULL -typedef void *stb_thread; -typedef void *stb_semaphore; -typedef void *stb_mutex; -typedef struct stb__sync *stb_sync; - -#define STB_SEMAPHORE_NULL NULL -#define STB_THREAD_NULL NULL -#define STB_MUTEX_NULL NULL -#define STB_SYNC_NULL NULL - -// get the number of processors (limited to those in the affinity mask for this process). -STB_EXTERN int stb_processor_count(void); -// force to run on a single core -- needed for RDTSC to work, e.g. for iprof -STB_EXTERN void stb_force_uniprocessor(void); - -// stb_work functions: queue up work to be done by some worker threads - -// set number of threads to serve the queue; you can change this on the fly, -// but if you decrease it, it won't decrease until things currently on the -// queue are finished -STB_EXTERN void stb_work_numthreads(int n); -// set maximum number of units in the queue; you can only set this BEFORE running any work functions -STB_EXTERN int stb_work_maxunits(int n); -// enqueue some work to be done (can do this from any thread, or even from a piece of work); -// return value of f is stored in *return_code if non-NULL -STB_EXTERN int stb_work(stb_thread_func f, void *d, volatile void **return_code); -// as above, but stb_sync_reach is called on 'rel' after work is complete -STB_EXTERN int stb_work_reach(stb_thread_func f, void *d, volatile void **return_code, stb_sync rel); - - -// necessary to call this when using volatile to order writes/reads -STB_EXTERN void stb_barrier(void); - -// support for independent queues with their own threads - -typedef struct stb__workqueue stb_workqueue; - -STB_EXTERN stb_workqueue*stb_workq_new(int numthreads, int max_units); -STB_EXTERN stb_workqueue*stb_workq_new_flags(int numthreads, int max_units, int no_add_mutex, int no_remove_mutex); -STB_EXTERN void stb_workq_delete(stb_workqueue *q); -STB_EXTERN void stb_workq_numthreads(stb_workqueue *q, int n); -STB_EXTERN int stb_workq(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code); -STB_EXTERN int stb_workq_reach(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code, stb_sync rel); -STB_EXTERN int stb_workq_length(stb_workqueue *q); - -STB_EXTERN stb_thread stb_create_thread (stb_thread_func f, void *d); -STB_EXTERN stb_thread stb_create_thread2(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel); -STB_EXTERN void stb_destroy_thread(stb_thread t); - -STB_EXTERN stb_semaphore stb_sem_new(int max_val); -STB_EXTERN stb_semaphore stb_sem_new_extra(int max_val, int start_val); -STB_EXTERN void stb_sem_delete (stb_semaphore s); -STB_EXTERN void stb_sem_waitfor(stb_semaphore s); -STB_EXTERN void stb_sem_release(stb_semaphore s); - -STB_EXTERN stb_mutex stb_mutex_new(void); -STB_EXTERN void stb_mutex_delete(stb_mutex m); -STB_EXTERN void stb_mutex_begin(stb_mutex m); -STB_EXTERN void stb_mutex_end(stb_mutex m); - -STB_EXTERN stb_sync stb_sync_new(void); -STB_EXTERN void stb_sync_delete(stb_sync s); -STB_EXTERN int stb_sync_set_target(stb_sync s, int count); -STB_EXTERN void stb_sync_reach_and_wait(stb_sync s); // wait for 'target' reachers -STB_EXTERN int stb_sync_reach(stb_sync s); - -typedef struct stb__threadqueue stb_threadqueue; -#define STB_THREADQ_DYNAMIC 0 -STB_EXTERN stb_threadqueue *stb_threadq_new(int item_size, int num_items, int many_add, int many_remove); -STB_EXTERN void stb_threadq_delete(stb_threadqueue *tq); -STB_EXTERN int stb_threadq_get(stb_threadqueue *tq, void *output); -STB_EXTERN void stb_threadq_get_block(stb_threadqueue *tq, void *output); -STB_EXTERN int stb_threadq_add(stb_threadqueue *tq, void *input); -// can return FALSE if STB_THREADQ_DYNAMIC and attempt to grow fails -STB_EXTERN int stb_threadq_add_block(stb_threadqueue *tq, void *input); - -#ifdef STB_THREADS -#ifdef STB_DEFINE - -typedef struct -{ - stb_thread_func f; - void *d; - volatile void **return_val; - stb_semaphore sem; -} stb__thread; - -// this is initialized along all possible paths to create threads, therefore -// it's always initialized before any other threads are create, therefore -// it's free of races AS LONG AS you only create threads through stb_* -static stb_mutex stb__threadmutex, stb__workmutex; - -static void stb__threadmutex_init(void) -{ - if (stb__threadmutex == STB_SEMAPHORE_NULL) { - stb__threadmutex = stb_mutex_new(); - stb__workmutex = stb_mutex_new(); - } -} - -#ifdef STB_THREAD_TEST -volatile float stb__t1=1, stb__t2; - -static void stb__wait(int n) -{ - float z = 0; - int i; - for (i=0; i < n; ++i) - z += 1 / (stb__t1+i); - stb__t2 = z; -} -#else -#define stb__wait(x) -#endif - -#ifdef _WIN32 - -// avoid including windows.h -- note that our definitions aren't -// exactly the same (we don't define the security descriptor struct) -// so if you want to include windows.h, make sure you do it first. -#include - -#ifndef _WINDOWS_ // check windows.h guard -#define STB__IMPORT STB_EXTERN __declspec(dllimport) -#define STB__DW unsigned long - -STB__IMPORT int __stdcall TerminateThread(void *, STB__DW); -STB__IMPORT void * __stdcall CreateSemaphoreA(void *sec, long,long,char*); -STB__IMPORT int __stdcall CloseHandle(void *); -STB__IMPORT STB__DW __stdcall WaitForSingleObject(void *, STB__DW); -STB__IMPORT int __stdcall ReleaseSemaphore(void *, long, long *); -STB__IMPORT void __stdcall Sleep(STB__DW); -#endif - -// necessary to call this when using volatile to order writes/reads -void stb_barrier(void) -{ - #ifdef MemoryBarrier - MemoryBarrier(); - #else - long temp; - __asm xchg temp,eax; - #endif -} - -static void stb__thread_run(void *t) -{ - void *res; - stb__thread info = * (stb__thread *) t; - free(t); - res = info.f(info.d); - if (info.return_val) - *info.return_val = res; - if (info.sem != STB_SEMAPHORE_NULL) - stb_sem_release(info.sem); -} - -static stb_thread stb_create_thread_raw(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel) -{ -#ifdef _MT -#if defined(STB_FASTMALLOC) && !defined(STB_FASTMALLOC_ITS_OKAY_I_ONLY_MALLOC_IN_ONE_THREAD) - stb_fatal("Error! Cannot use STB_FASTMALLOC with threads.\n"); - return STB_THREAD_NULL; -#else - unsigned long id; - stb__thread *data = (stb__thread *) malloc(sizeof(*data)); - if (!data) return NULL; - stb__threadmutex_init(); - data->f = f; - data->d = d; - data->return_val = return_code; - data->sem = rel; - id = _beginthread(stb__thread_run, 0, data); - if (id == -1) return NULL; - return (void *) id; -#endif -#else -#ifdef STB_NO_STB_STRINGS - stb_fatal("Invalid compilation"); -#else - stb_fatal("Must compile mult-threaded to use stb_thread/stb_work."); -#endif - return NULL; -#endif -} - -// trivial win32 wrappers -void stb_destroy_thread(stb_thread t) { TerminateThread(t,0); } -stb_semaphore stb_sem_new(int maxv) {return CreateSemaphoreA(NULL,0,maxv,NULL); } -stb_semaphore stb_sem_new_extra(int maxv,int start){return CreateSemaphoreA(NULL,start,maxv,NULL); } -void stb_sem_delete(stb_semaphore s) { if (s != NULL) CloseHandle(s); } -void stb_sem_waitfor(stb_semaphore s) { WaitForSingleObject(s, 0xffffffff); } // INFINITE -void stb_sem_release(stb_semaphore s) { ReleaseSemaphore(s,1,NULL); } -static void stb__thread_sleep(int ms) { Sleep(ms); } - -#ifndef _WINDOWS_ -STB__IMPORT int __stdcall GetProcessAffinityMask(void *, STB__DW *, STB__DW *); -STB__IMPORT void * __stdcall GetCurrentProcess(void); -STB__IMPORT int __stdcall SetProcessAffinityMask(void *, STB__DW); -#endif - -int stb_processor_count(void) -{ - unsigned long proc,sys; - GetProcessAffinityMask(GetCurrentProcess(), &proc, &sys); - return stb_bitcount(proc); -} - -void stb_force_uniprocessor(void) -{ - unsigned long proc,sys; - GetProcessAffinityMask(GetCurrentProcess(), &proc, &sys); - if (stb_bitcount(proc) > 1) { - int z; - for (z=0; z < 32; ++z) - if (proc & (1 << z)) - break; - if (z < 32) { - proc = 1 << z; - SetProcessAffinityMask(GetCurrentProcess(), proc); - } - } -} - -#ifdef _WINDOWS_ -#define STB_MUTEX_NATIVE -void *stb_mutex_new(void) -{ - CRITICAL_SECTION *p = (CRITICAL_SECTION *) malloc(sizeof(*p)); - if (p) -#if _WIN32_WINNT >= 0x0500 - InitializeCriticalSectionAndSpinCount(p, 500); -#else - InitializeCriticalSection(p); -#endif - return p; -} - -void stb_mutex_delete(void *p) -{ - if (p) { - DeleteCriticalSection((CRITICAL_SECTION *) p); - free(p); - } -} - -void stb_mutex_begin(void *p) -{ - stb__wait(500); - if (p) - EnterCriticalSection((CRITICAL_SECTION *) p); -} - -void stb_mutex_end(void *p) -{ - if (p) - LeaveCriticalSection((CRITICAL_SECTION *) p); - stb__wait(500); -} -#endif // _WINDOWS_ - -#if 0 -// for future reference, -// InterlockedCompareExchange for x86: - int cas64_mp(void * dest, void * xcmp, void * xxchg) { - __asm - { - mov esi, [xxchg] ; exchange - mov ebx, [esi + 0] - mov ecx, [esi + 4] - - mov esi, [xcmp] ; comparand - mov eax, [esi + 0] - mov edx, [esi + 4] - - mov edi, [dest] ; destination - lock cmpxchg8b [edi] - jz yyyy; - - mov [esi + 0], eax; - mov [esi + 4], edx; - -yyyy: - xor eax, eax; - setz al; - }; - -inline unsigned __int64 _InterlockedCompareExchange64(volatile unsigned __int64 *dest - ,unsigned __int64 exchange - ,unsigned __int64 comperand) -{ - //value returned in eax::edx - __asm { - lea esi,comperand; - lea edi,exchange; - - mov eax,[esi]; - mov edx,4[esi]; - mov ebx,[edi]; - mov ecx,4[edi]; - mov esi,dest; - lock CMPXCHG8B [esi]; - } -#endif // #if 0 - -#endif // _WIN32 - -stb_thread stb_create_thread2(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel) -{ - return stb_create_thread_raw(f,d,return_code,rel); -} - -stb_thread stb_create_thread(stb_thread_func f, void *d) -{ - return stb_create_thread2(f,d,NULL,STB_SEMAPHORE_NULL); -} - -// mutex implemented by wrapping semaphore -#ifndef STB_MUTEX_NATIVE -stb_mutex stb_mutex_new(void) { return stb_sem_new_extra(1,1); } -void stb_mutex_delete(stb_mutex m) { stb_sem_delete (m); } -void stb_mutex_begin(stb_mutex m) { stb__wait(500); if (m) stb_sem_waitfor(m); } -void stb_mutex_end(stb_mutex m) { if (m) stb_sem_release(m); stb__wait(500); } -#endif - -// thread merge operation -struct stb__sync -{ - int target; // target number of threads to hit it - int sofar; // total threads that hit it - int waiting; // total threads waiting - - stb_mutex start; // mutex to prevent starting again before finishing previous - stb_mutex mutex; // mutex while tweaking state - stb_semaphore release; // semaphore wake up waiting threads - // we have to wake them up one at a time, rather than using a single release - // call, because win32 semaphores don't let you dynamically change the max count! -}; - -stb_sync stb_sync_new(void) -{ - stb_sync s = (stb_sync) malloc(sizeof(*s)); - if (!s) return s; - - s->target = s->sofar = s->waiting = 0; - s->mutex = stb_mutex_new(); - s->start = stb_mutex_new(); - s->release = stb_sem_new(1); - if (s->mutex == STB_MUTEX_NULL || s->release == STB_SEMAPHORE_NULL || s->start == STB_MUTEX_NULL) { - stb_mutex_delete(s->mutex); - stb_mutex_delete(s->mutex); - stb_sem_delete(s->release); - free(s); - return NULL; - } - return s; -} - -void stb_sync_delete(stb_sync s) -{ - if (s->waiting) { - // it's bad to delete while there are threads waiting! - // shall we wait for them to reach, or just bail? just bail - assert(0); - } - stb_mutex_delete(s->mutex); - stb_mutex_delete(s->release); - free(s); -} - -int stb_sync_set_target(stb_sync s, int count) -{ - // don't allow setting a target until the last one is fully released; - // note that this can lead to inefficient pipelining, and maybe we'd - // be better off ping-ponging between two internal syncs? - // I tried seeing how often this happened using TryEnterCriticalSection - // and could _never_ get it to happen in imv(stb), even with more threads - // than processors. So who knows! - stb_mutex_begin(s->start); - - // this mutex is pointless, since it's not valid for threads - // to call reach() before anyone calls set_target() anyway - stb_mutex_begin(s->mutex); - - assert(s->target == 0); // enforced by start mutex - s->target = count; - s->sofar = 0; - s->waiting = 0; - stb_mutex_end(s->mutex); - return STB_TRUE; -} - -void stb__sync_release(stb_sync s) -{ - if (s->waiting) - stb_sem_release(s->release); - else { - s->target = 0; - stb_mutex_end(s->start); - } -} - -int stb_sync_reach(stb_sync s) -{ - int n; - stb_mutex_begin(s->mutex); - assert(s->sofar < s->target); - n = ++s->sofar; // record this value to avoid possible race if we did 'return s->sofar'; - if (s->sofar == s->target) - stb__sync_release(s); - stb_mutex_end(s->mutex); - return n; -} - -void stb_sync_reach_and_wait(stb_sync s) -{ - stb_mutex_begin(s->mutex); - assert(s->sofar < s->target); - ++s->sofar; - if (s->sofar == s->target) { - stb__sync_release(s); - stb_mutex_end(s->mutex); - } else { - ++s->waiting; // we're waiting, so one more waiter - stb_mutex_end(s->mutex); // release the mutex to other threads - - stb_sem_waitfor(s->release); // wait for merge completion - - stb_mutex_begin(s->mutex); // on merge completion, grab the mutex - --s->waiting; // we're done waiting - stb__sync_release(s); // restart the next waiter - stb_mutex_end(s->mutex); // and now we're done - // this ends the same as the first case, but it's a lot - // clearer to understand without sharing the code - } -} - -struct stb__threadqueue -{ - stb_mutex add, remove; - stb_semaphore nonempty, nonfull; - int head_blockers; // number of threads blocking--used to know whether to release(avail) - int tail_blockers; - int head, tail, array_size, growable; - int item_size; - char *data; -}; - -static int stb__tq_wrap(volatile stb_threadqueue *z, int p) -{ - if (p == z->array_size) - return p - z->array_size; - else - return p; -} - -int stb__threadq_get_raw(stb_threadqueue *tq2, void *output, int block) -{ - volatile stb_threadqueue *tq = (volatile stb_threadqueue *) tq2; - if (tq->head == tq->tail && !block) return 0; - - stb_mutex_begin(tq->remove); - - while (tq->head == tq->tail) { - if (!block) { - stb_mutex_end(tq->remove); - return 0; - } - ++tq->head_blockers; - stb_mutex_end(tq->remove); - - stb_sem_waitfor(tq->nonempty); - - stb_mutex_begin(tq->remove); - --tq->head_blockers; - } - - memcpy(output, tq->data + tq->head*tq->item_size, tq->item_size); - stb_barrier(); - tq->head = stb__tq_wrap(tq, tq->head+1); - - stb_sem_release(tq->nonfull); - if (tq->head_blockers) // can't check if actually non-empty due to race? - stb_sem_release(tq->nonempty); // if there are other blockers, wake one - - stb_mutex_end(tq->remove); - return STB_TRUE; -} - -int stb__threadq_grow(volatile stb_threadqueue *tq) -{ - int n; - char *p; - assert(tq->remove != STB_MUTEX_NULL); // must have this to allow growth! - stb_mutex_begin(tq->remove); - - n = tq->array_size * 2; - p = (char *) realloc(tq->data, n * tq->item_size); - if (p == NULL) { - stb_mutex_end(tq->remove); - stb_mutex_end(tq->add); - return STB_FALSE; - } - if (tq->tail < tq->head) { - memcpy(p + tq->array_size * tq->item_size, p, tq->tail * tq->item_size); - tq->tail += tq->array_size; - } - tq->data = p; - tq->array_size = n; - - stb_mutex_end(tq->remove); - return STB_TRUE; -} - -int stb__threadq_add_raw(stb_threadqueue *tq2, void *input, int block) -{ - int tail,pos; - volatile stb_threadqueue *tq = (volatile stb_threadqueue *) tq2; - stb_mutex_begin(tq->add); - for(;;) { - pos = tq->tail; - tail = stb__tq_wrap(tq, pos+1); - if (tail != tq->head) break; - - // full - if (tq->growable) { - if (!stb__threadq_grow(tq)) { - stb_mutex_end(tq->add); - return STB_FALSE; // out of memory - } - } else if (!block) { - stb_mutex_end(tq->add); - return STB_FALSE; - } else { - ++tq->tail_blockers; - stb_mutex_end(tq->add); - - stb_sem_waitfor(tq->nonfull); - - stb_mutex_begin(tq->add); - --tq->tail_blockers; - } - } - memcpy(tq->data + tq->item_size * pos, input, tq->item_size); - stb_barrier(); - tq->tail = tail; - stb_sem_release(tq->nonempty); - if (tq->tail_blockers) // can't check if actually non-full due to race? - stb_sem_release(tq->nonfull); - stb_mutex_end(tq->add); - return STB_TRUE; -} - -int stb_threadq_length(stb_threadqueue *tq2) -{ - int a,b,n; - volatile stb_threadqueue *tq = (volatile stb_threadqueue *) tq2; - stb_mutex_begin(tq->add); - a = tq->head; - b = tq->tail; - n = tq->array_size; - stb_mutex_end(tq->add); - if (a > b) b += n; - return b-a; -} - -int stb_threadq_get(stb_threadqueue *tq, void *output) -{ - return stb__threadq_get_raw(tq, output, STB_FALSE); -} - -void stb_threadq_get_block(stb_threadqueue *tq, void *output) -{ - stb__threadq_get_raw(tq, output, STB_TRUE); -} - -int stb_threadq_add(stb_threadqueue *tq, void *input) -{ - return stb__threadq_add_raw(tq, input, STB_FALSE); -} - -int stb_threadq_add_block(stb_threadqueue *tq, void *input) -{ - return stb__threadq_add_raw(tq, input, STB_TRUE); -} - -void stb_threadq_delete(stb_threadqueue *tq) -{ - if (tq) { - free(tq->data); - stb_mutex_delete(tq->add); - stb_mutex_delete(tq->remove); - stb_sem_delete(tq->nonempty); - stb_sem_delete(tq->nonfull); - free(tq); - } -} - -#define STB_THREADQUEUE_DYNAMIC 0 -stb_threadqueue *stb_threadq_new(int item_size, int num_items, int many_add, int many_remove) -{ - int error=0; - stb_threadqueue *tq = (stb_threadqueue *) malloc(sizeof(*tq)); - if (tq == NULL) return NULL; - - if (num_items == STB_THREADQUEUE_DYNAMIC) { - tq->growable = STB_TRUE; - num_items = 32; - } else - tq->growable = STB_FALSE; - - tq->item_size = item_size; - tq->array_size = num_items+1; - - tq->add = tq->remove = STB_MUTEX_NULL; - tq->nonempty = tq->nonfull = STB_SEMAPHORE_NULL; - tq->data = NULL; - if (many_add) - { tq->add = stb_mutex_new(); if (tq->add == STB_MUTEX_NULL) goto error; } - if (many_remove || tq->growable) - { tq->remove = stb_mutex_new(); if (tq->remove == STB_MUTEX_NULL) goto error; } - tq->nonempty = stb_sem_new(1); if (tq->nonempty == STB_SEMAPHORE_NULL) goto error; - tq->nonfull = stb_sem_new(1); if (tq->nonfull == STB_SEMAPHORE_NULL) goto error; - tq->data = (char *) malloc(tq->item_size * tq->array_size); - if (tq->data == NULL) goto error; - - tq->head = tq->tail = 0; - tq->head_blockers = tq->tail_blockers = 0; - - return tq; - -error: - stb_threadq_delete(tq); - return NULL; -} - -typedef struct -{ - stb_thread_func f; - void *d; - volatile void **retval; - stb_sync sync; -} stb__workinfo; - -//static volatile stb__workinfo *stb__work; - -struct stb__workqueue -{ - int numthreads; - stb_threadqueue *tq; -}; - -static stb_workqueue *stb__work_global; - -static void *stb__thread_workloop(void *p) -{ - volatile stb_workqueue *q = (volatile stb_workqueue *) p; - for(;;) { - void *z; - stb__workinfo w; - stb_threadq_get_block(q->tq, &w); - if (w.f == NULL) // null work is a signal to end the thread - return NULL; - z = w.f(w.d); - if (w.retval) { stb_barrier(); *w.retval = z; } - if (w.sync != STB_SYNC_NULL) stb_sync_reach(w.sync); - } -} - -stb_workqueue *stb_workq_new(int num_threads, int max_units) -{ - return stb_workq_new_flags(num_threads, max_units, 0,0); -} - -stb_workqueue *stb_workq_new_flags(int numthreads, int max_units, int no_add_mutex, int no_remove_mutex) -{ - stb_workqueue *q = (stb_workqueue *) malloc(sizeof(*q)); - if (q == NULL) return NULL; - q->tq = stb_threadq_new(sizeof(stb__workinfo), max_units, !no_add_mutex, !no_remove_mutex); - if (q->tq == NULL) { free(q); return NULL; } - q->numthreads = 0; - stb_workq_numthreads(q, numthreads); - return q; -} - -void stb_workq_delete(stb_workqueue *q) -{ - while (stb_workq_length(q) != 0) - stb__thread_sleep(1); - stb_threadq_delete(q->tq); - free(q); -} - -static int stb__work_maxitems = STB_THREADQUEUE_DYNAMIC; - -static void stb_work_init(int num_threads) -{ - if (stb__work_global == NULL) { - stb__threadmutex_init(); - stb_mutex_begin(stb__workmutex); - stb_barrier(); - if (*(stb_workqueue * volatile *) &stb__work_global == NULL) - stb__work_global = stb_workq_new(num_threads, stb__work_maxitems); - stb_mutex_end(stb__workmutex); - } -} - -static int stb__work_raw(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code, stb_sync rel) -{ - stb__workinfo w; - if (q == NULL) { - stb_work_init(1); - q = stb__work_global; - } - w.f = f; - w.d = d; - w.retval = return_code; - w.sync = rel; - return stb_threadq_add(q->tq, &w); -} - -int stb_workq_length(stb_workqueue *q) -{ - return stb_threadq_length(q->tq); -} - -int stb_workq(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code) -{ - if (f == NULL) return 0; - return stb_workq_reach(q, f, d, return_code, NULL); -} - -int stb_workq_reach(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code, stb_sync rel) -{ - if (f == NULL) return 0; - return stb__work_raw(q, f, d, return_code, rel); -} - -static void stb__workq_numthreads(stb_workqueue *q, int n) -{ - while (q->numthreads < n) { - stb_create_thread(stb__thread_workloop, q); - ++q->numthreads; - } - while (q->numthreads > n) { - stb__work_raw(q, NULL, NULL, NULL, NULL); - --q->numthreads; - } -} - -void stb_workq_numthreads(stb_workqueue *q, int n) -{ - stb_mutex_begin(stb__threadmutex); - stb__workq_numthreads(q,n); - stb_mutex_end(stb__threadmutex); -} - -int stb_work_maxunits(int n) -{ - if (stb__work_global == NULL) { - stb__work_maxitems = n; - stb_work_init(1); - } - return stb__work_maxitems; -} - -int stb_work(stb_thread_func f, void *d, volatile void **return_code) -{ - return stb_workq(stb__work_global, f,d,return_code); -} - -int stb_work_reach(stb_thread_func f, void *d, volatile void **return_code, stb_sync rel) -{ - return stb_workq_reach(stb__work_global, f,d,return_code,rel); -} - -void stb_work_numthreads(int n) -{ - if (stb__work_global == NULL) - stb_work_init(n); - else - stb_workq_numthreads(stb__work_global, n); -} -#endif // STB_DEFINE - - -////////////////////////////////////////////////////////////////////////////// -// -// Background disk I/O -// -// - -#define STB_BGIO_READ_ALL (-1) -STB_EXTERN int stb_bgio_read (char *filename, int offset, int len, stb_uchar **result, int *olen); -STB_EXTERN int stb_bgio_readf (FILE *f , int offset, int len, stb_uchar **result, int *olen); -STB_EXTERN int stb_bgio_read_to (char *filename, int offset, int len, stb_uchar *buffer, int *olen); -STB_EXTERN int stb_bgio_readf_to(FILE *f , int offset, int len, stb_uchar *buffer, int *olen); - -typedef struct -{ - int have_data; - int is_valid; - int is_dir; - time_t filetime; - stb_int64 filesize; -} stb_bgstat; - -STB_EXTERN int stb_bgio_stat (char *filename, stb_bgstat *result); - -#ifdef STB_DEFINE - -static stb_workqueue *stb__diskio; -static stb_mutex stb__diskio_mutex; - -void stb_thread_cleanup(void) -{ - if (stb__work_global) stb_workq_delete(stb__work_global); stb__work_global = NULL; - if (stb__threadmutex) stb_mutex_delete(stb__threadmutex); stb__threadmutex = NULL; - if (stb__workmutex) stb_mutex_delete(stb__workmutex); stb__workmutex = NULL; - if (stb__diskio) stb_workq_delete(stb__diskio); stb__diskio = NULL; - if (stb__diskio_mutex)stb_mutex_delete(stb__diskio_mutex);stb__diskio_mutex= NULL; -} - - -typedef struct -{ - char *filename; - FILE *f; - int offset; - int len; - - stb_bgstat *stat_out; - stb_uchar *output; - stb_uchar **result; - int *len_output; - int *flag; -} stb__disk_command; - -#define STB__MAX_DISK_COMMAND 100 -static stb__disk_command stb__dc_queue[STB__MAX_DISK_COMMAND]; -static int stb__dc_offset; - -void stb__io_init(void) -{ - if (!stb__diskio) { - stb__threadmutex_init(); - stb_mutex_begin(stb__threadmutex); - stb_barrier(); - if (*(stb_thread * volatile *) &stb__diskio == NULL) { - stb__diskio_mutex = stb_mutex_new(); - // use many threads so OS can try to schedule seeks - stb__diskio = stb_workq_new_flags(16,STB__MAX_DISK_COMMAND,STB_FALSE,STB_FALSE); - } - stb_mutex_end(stb__threadmutex); - } -} - -static void * stb__io_error(stb__disk_command *dc) -{ - if (dc->len_output) *dc->len_output = 0; - if (dc->result) *dc->result = NULL; - if (dc->flag) *dc->flag = -1; - return NULL; -} - -static void * stb__io_task(void *p) -{ - stb__disk_command *dc = (stb__disk_command *) p; - int len; - FILE *f; - stb_uchar *buf; - - if (dc->stat_out) { - struct _stati64 s; - if (!_stati64(dc->filename, &s)) { - dc->stat_out->filesize = s.st_size; - dc->stat_out->filetime = s.st_mtime; - dc->stat_out->is_dir = s.st_mode & _S_IFDIR; - dc->stat_out->is_valid = (s.st_mode & _S_IFREG) || dc->stat_out->is_dir; - } else - dc->stat_out->is_valid = 0; - stb_barrier(); - dc->stat_out->have_data = 1; - free(dc->filename); - return 0; - } - if (dc->f) { - #ifdef WIN32 - f = _fdopen(_dup(_fileno(dc->f)), "rb"); - #else - f = fdopen(dup(fileno(dc->f)), "rb"); - #endif - if (!f) - return stb__io_error(dc); - } else { - f = fopen(dc->filename, "rb"); - free(dc->filename); - if (!f) - return stb__io_error(dc); - } - - len = dc->len; - if (len < 0) { - fseek(f, 0, SEEK_END); - len = ftell(f) - dc->offset; - } - - if (fseek(f, dc->offset, SEEK_SET)) { - fclose(f); - return stb__io_error(dc); - } - - if (dc->output) - buf = dc->output; - else { - buf = (stb_uchar *) malloc(len); - if (buf == NULL) { - fclose(f); - return stb__io_error(dc); - } - } - - len = fread(buf, 1, len, f); - fclose(f); - if (dc->len_output) *dc->len_output = len; - if (dc->result) *dc->result = buf; - if (dc->flag) *dc->flag = 1; - - return NULL; -} - -int stb__io_add(char *fname, FILE *f, int off, int len, stb_uchar *out, stb_uchar **result, int *olen, int *flag, stb_bgstat *stat) -{ - int res; - stb__io_init(); - // do memory allocation outside of mutex - if (fname) fname = stb_p_strdup(fname); - stb_mutex_begin(stb__diskio_mutex); - { - stb__disk_command *dc = &stb__dc_queue[stb__dc_offset]; - dc->filename = fname; - dc->f = f; - dc->offset = off; - dc->len = len; - dc->output = out; - dc->result = result; - dc->len_output = olen; - dc->flag = flag; - dc->stat_out = stat; - res = stb_workq(stb__diskio, stb__io_task, dc, NULL); - if (res) - stb__dc_offset = (stb__dc_offset + 1 == STB__MAX_DISK_COMMAND ? 0 : stb__dc_offset+1); - } - stb_mutex_end(stb__diskio_mutex); - return res; -} - -int stb_bgio_read(char *filename, int offset, int len, stb_uchar **result, int *olen) -{ - return stb__io_add(filename,NULL,offset,len,NULL,result,olen,NULL,NULL); -} - -int stb_bgio_readf(FILE *f, int offset, int len, stb_uchar **result, int *olen) -{ - return stb__io_add(NULL,f,offset,len,NULL,result,olen,NULL,NULL); -} - -int stb_bgio_read_to(char *filename, int offset, int len, stb_uchar *buffer, int *olen) -{ - return stb__io_add(filename,NULL,offset,len,buffer,NULL,olen,NULL,NULL); -} - -int stb_bgio_readf_to(FILE *f, int offset, int len, stb_uchar *buffer, int *olen) -{ - return stb__io_add(NULL,f,offset,len,buffer,NULL,olen,NULL,NULL); -} - -STB_EXTERN int stb_bgio_stat (char *filename, stb_bgstat *result) -{ - result->have_data = 0; - return stb__io_add(filename,NULL,0,0,0,NULL,0,NULL, result); -} -#endif -#endif - - - -////////////////////////////////////////////////////////////////////////////// -// -// Fast malloc implementation -// -// This is a clone of TCMalloc, but without the thread support. -// 1. large objects are allocated directly, page-aligned -// 2. small objects are allocated in homogeonous heaps, 0 overhead -// -// We keep an allocation table for pages a la TCMalloc. This would -// require 4MB for the entire address space, but we only allocate -// the parts that are in use. The overhead from using homogenous heaps -// everywhere is 3MB. (That is, if you allocate 1 object of each size, -// you'll use 3MB.) - -#if defined(STB_DEFINE) && ((defined(_WIN32) && !defined(_M_AMD64)) || defined(STB_FASTMALLOC)) - -#ifdef _WIN32 - #ifndef _WINDOWS_ - #ifndef STB__IMPORT - #define STB__IMPORT STB_EXTERN __declspec(dllimport) - #define STB__DW unsigned long - #endif - STB__IMPORT void * __stdcall VirtualAlloc(void *p, unsigned long size, unsigned long type, unsigned long protect); - STB__IMPORT int __stdcall VirtualFree(void *p, unsigned long size, unsigned long freetype); - #endif - #define stb__alloc_pages_raw(x) (stb_uint32) VirtualAlloc(NULL, (x), 0x3000, 0x04) - #define stb__dealloc_pages_raw(p) VirtualFree((void *) p, 0, 0x8000) -#else - #error "Platform not currently supported" -#endif - -typedef struct stb__span -{ - int start, len; - struct stb__span *next, *prev; - void *first_free; - unsigned short list; // 1..256 free; 257..511 sizeclass; 0=large block - short allocations; // # outstanding allocations for sizeclass -} stb__span; // 24 - -static stb__span **stb__span_for_page; -static int stb__firstpage, stb__lastpage; -static void stb__update_page_range(int first, int last) -{ - stb__span **sfp; - int i, f,l; - if (first >= stb__firstpage && last <= stb__lastpage) return; - if (stb__span_for_page == NULL) { - f = first; - l = f+stb_max(last-f, 16384); - l = stb_min(l, 1<<20); - } else if (last > stb__lastpage) { - f = stb__firstpage; - l = f + (stb__lastpage - f) * 2; - l = stb_clamp(last, l,1<<20); - } else { - l = stb__lastpage; - f = l - (l - stb__firstpage) * 2; - f = stb_clamp(f, 0,first); - } - sfp = (stb__span **) stb__alloc_pages_raw(sizeof(void *) * (l-f)); - for (i=f; i < stb__firstpage; ++i) sfp[i - f] = NULL; - for ( ; i < stb__lastpage ; ++i) sfp[i - f] = stb__span_for_page[i - stb__firstpage]; - for ( ; i < l ; ++i) sfp[i - f] = NULL; - if (stb__span_for_page) stb__dealloc_pages_raw(stb__span_for_page); - stb__firstpage = f; - stb__lastpage = l; - stb__span_for_page = sfp; -} - -static stb__span *stb__span_free=NULL; -static stb__span *stb__span_first, *stb__span_end; -static stb__span *stb__span_alloc(void) -{ - stb__span *s = stb__span_free; - if (s) - stb__span_free = s->next; - else { - if (!stb__span_first) { - stb__span_first = (stb__span *) stb__alloc_pages_raw(65536); - if (stb__span_first == NULL) return NULL; - stb__span_end = stb__span_first + (65536 / sizeof(stb__span)); - } - s = stb__span_first++; - if (stb__span_first == stb__span_end) stb__span_first = NULL; - } - return s; -} - -static stb__span *stb__spanlist[512]; - -static void stb__spanlist_unlink(stb__span *s) -{ - if (s->prev) - s->prev->next = s->next; - else { - int n = s->list; - assert(stb__spanlist[n] == s); - stb__spanlist[n] = s->next; - } - if (s->next) - s->next->prev = s->prev; - s->next = s->prev = NULL; - s->list = 0; -} - -static void stb__spanlist_add(int n, stb__span *s) -{ - s->list = n; - s->next = stb__spanlist[n]; - s->prev = NULL; - stb__spanlist[n] = s; - if (s->next) s->next->prev = s; -} - -#define stb__page_shift 12 -#define stb__page_size (1 << stb__page_shift) -#define stb__page_number(x) ((x) >> stb__page_shift) -#define stb__page_address(x) ((x) << stb__page_shift) - -static void stb__set_span_for_page(stb__span *s) -{ - int i; - for (i=0; i < s->len; ++i) - stb__span_for_page[s->start + i - stb__firstpage] = s; -} - -static stb__span *stb__coalesce(stb__span *a, stb__span *b) -{ - assert(a->start + a->len == b->start); - if (a->list) stb__spanlist_unlink(a); - if (b->list) stb__spanlist_unlink(b); - a->len += b->len; - b->len = 0; - b->next = stb__span_free; - stb__span_free = b; - stb__set_span_for_page(a); - return a; -} - -static void stb__free_span(stb__span *s) -{ - stb__span *n = NULL; - if (s->start > stb__firstpage) { - n = stb__span_for_page[s->start-1 - stb__firstpage]; - if (n && n->allocations == -2 && n->start + n->len == s->start) s = stb__coalesce(n,s); - } - if (s->start + s->len < stb__lastpage) { - n = stb__span_for_page[s->start + s->len - stb__firstpage]; - if (n && n->allocations == -2 && s->start + s->len == n->start) s = stb__coalesce(s,n); - } - s->allocations = -2; - stb__spanlist_add(s->len > 256 ? 256 : s->len, s); -} - -static stb__span *stb__alloc_pages(int num) -{ - stb__span *s = stb__span_alloc(); - int p; - if (!s) return NULL; - p = stb__alloc_pages_raw(num << stb__page_shift); - if (p == 0) { s->next = stb__span_free; stb__span_free = s; return 0; } - assert(stb__page_address(stb__page_number(p)) == p); - p = stb__page_number(p); - stb__update_page_range(p, p+num); - s->start = p; - s->len = num; - s->next = NULL; - s->prev = NULL; - stb__set_span_for_page(s); - return s; -} - -static stb__span *stb__alloc_span(int pagecount) -{ - int i; - stb__span *p = NULL; - for(i=pagecount; i < 256; ++i) - if (stb__spanlist[i]) { - p = stb__spanlist[i]; - break; - } - if (!p) { - p = stb__spanlist[256]; - while (p && p->len < pagecount) - p = p->next; - } - if (!p) { - p = stb__alloc_pages(pagecount < 16 ? 16 : pagecount); - if (p == NULL) return 0; - } else - stb__spanlist_unlink(p); - - if (p->len > pagecount) { - stb__span *q = stb__span_alloc(); - if (q) { - q->start = p->start + pagecount; - q->len = p->len - pagecount; - p->len = pagecount; - for (i=0; i < q->len; ++i) - stb__span_for_page[q->start+i - stb__firstpage] = q; - stb__spanlist_add(q->len > 256 ? 256 : q->len, q); - } - } - return p; -} - -#define STB__MAX_SMALL_SIZE 32768 -#define STB__MAX_SIZE_CLASSES 256 - -static unsigned char stb__class_base[32]; -static unsigned char stb__class_shift[32]; -static unsigned char stb__pages_for_class[STB__MAX_SIZE_CLASSES]; -static int stb__size_for_class[STB__MAX_SIZE_CLASSES]; - -stb__span *stb__get_nonempty_sizeclass(int c) -{ - int s = c + 256, i, size, tsize; // remap to span-list index - char *z; - void *q; - stb__span *p = stb__spanlist[s]; - if (p) { - if (p->first_free) return p; // fast path: it's in the first one in list - for (p=p->next; p; p=p->next) - if (p->first_free) { - // move to front for future queries - stb__spanlist_unlink(p); - stb__spanlist_add(s, p); - return p; - } - } - // no non-empty ones, so allocate a new one - p = stb__alloc_span(stb__pages_for_class[c]); - if (!p) return NULL; - // create the free list up front - size = stb__size_for_class[c]; - tsize = stb__pages_for_class[c] << stb__page_shift; - i = 0; - z = (char *) stb__page_address(p->start); - q = NULL; - while (i + size <= tsize) { - * (void **) z = q; q = z; - z += size; - i += size; - } - p->first_free = q; - p->allocations = 0; - stb__spanlist_add(s,p); - return p; -} - -static int stb__sizeclass(size_t sz) -{ - int z = stb_log2_floor(sz); // -1 below to group e.g. 13,14,15,16 correctly - return stb__class_base[z] + ((sz-1) >> stb__class_shift[z]); -} - -static void stb__init_sizeclass(void) -{ - int i, size, overhead; - int align_shift = 2; // allow 4-byte and 12-byte blocks as well, vs. TCMalloc - int next_class = 1; - int last_log = 0; - - for (i = 0; i < align_shift; i++) { - stb__class_base [i] = next_class; - stb__class_shift[i] = align_shift; - } - - for (size = 1 << align_shift; size <= STB__MAX_SMALL_SIZE; size += 1 << align_shift) { - i = stb_log2_floor(size); - if (i > last_log) { - if (size == 16) ++align_shift; // switch from 4-byte to 8-byte alignment - else if (size >= 128 && align_shift < 8) ++align_shift; - stb__class_base[i] = next_class - ((size-1) >> align_shift); - stb__class_shift[i] = align_shift; - last_log = i; - } - stb__size_for_class[next_class++] = size; - } - - for (i=1; i <= STB__MAX_SMALL_SIZE; ++i) - assert(i <= stb__size_for_class[stb__sizeclass(i)]); - - overhead = 0; - for (i = 1; i < next_class; i++) { - int s = stb__size_for_class[i]; - size = stb__page_size; - while (size % s > size >> 3) - size += stb__page_size; - stb__pages_for_class[i] = (unsigned char) (size >> stb__page_shift); - overhead += size; - } - assert(overhead < (4 << 20)); // make sure it's under 4MB of overhead -} - -#ifdef STB_DEBUG -#define stb__smemset(a,b,c) memset((void *) a, b, c) -#elif defined(STB_FASTMALLOC_INIT) -#define stb__smemset(a,b,c) memset((void *) a, b, c) -#else -#define stb__smemset(a,b,c) -#endif -void *stb_smalloc(size_t sz) -{ - stb__span *s; - if (sz == 0) return NULL; - if (stb__size_for_class[1] == 0) stb__init_sizeclass(); - if (sz > STB__MAX_SMALL_SIZE) { - s = stb__alloc_span((sz + stb__page_size - 1) >> stb__page_shift); - if (s == NULL) return NULL; - s->list = 0; - s->next = s->prev = NULL; - s->allocations = -32767; - stb__smemset(stb__page_address(s->start), 0xcd, (sz+3)&~3); - return (void *) stb__page_address(s->start); - } else { - void *p; - int c = stb__sizeclass(sz); - s = stb__spanlist[256+c]; - if (!s || !s->first_free) - s = stb__get_nonempty_sizeclass(c); - if (s == NULL) return NULL; - p = s->first_free; - s->first_free = * (void **) p; - ++s->allocations; - stb__smemset(p,0xcd, sz); - return p; - } -} - -int stb_ssize(void *p) -{ - stb__span *s; - if (p == NULL) return 0; - s = stb__span_for_page[stb__page_number((stb_uint) p) - stb__firstpage]; - if (s->list >= 256) { - return stb__size_for_class[s->list - 256]; - } else { - assert(s->list == 0); - return s->len << stb__page_shift; - } -} - -void stb_sfree(void *p) -{ - stb__span *s; - if (p == NULL) return; - s = stb__span_for_page[stb__page_number((stb_uint) p) - stb__firstpage]; - if (s->list >= 256) { - stb__smemset(p, 0xfe, stb__size_for_class[s->list-256]); - * (void **) p = s->first_free; - s->first_free = p; - if (--s->allocations == 0) { - stb__spanlist_unlink(s); - stb__free_span(s); - } - } else { - assert(s->list == 0); - stb__smemset(p, 0xfe, stb_ssize(p)); - stb__free_span(s); - } -} - -void *stb_srealloc(void *p, size_t sz) -{ - size_t cur_size; - if (p == NULL) return stb_smalloc(sz); - if (sz == 0) { stb_sfree(p); return NULL; } - cur_size = stb_ssize(p); - if (sz > cur_size || sz <= (cur_size >> 1)) { - void *q; - if (sz > cur_size && sz < (cur_size << 1)) sz = cur_size << 1; - q = stb_smalloc(sz); if (q == NULL) return NULL; - memcpy(q, p, sz < cur_size ? sz : cur_size); - stb_sfree(p); - return q; - } - return p; -} - -void *stb_scalloc(size_t n, size_t sz) -{ - void *p; - if (n == 0 || sz == 0) return NULL; - if (stb_log2_ceil(n) + stb_log2_ceil(n) >= 32) return NULL; - p = stb_smalloc(n*sz); - if (p) memset(p, 0, n*sz); - return p; -} - -char *stb_sstrdup(char *s) -{ - int n = strlen(s); - char *p = (char *) stb_smalloc(n+1); - if (p) stb_p_strcpy_s(p,n+1,s); - return p; -} -#endif // STB_DEFINE - - - -////////////////////////////////////////////////////////////////////////////// -// -// Source code constants -// -// This is a trivial system to let you specify constants in source code, -// then while running you can change the constants. -// -// Note that you can't wrap the #defines, because we need to know their -// names. So we provide a pre-wrapped version without 'STB_' for convenience; -// to request it, #define STB_CONVENIENT_H, yielding: -// KI -- integer -// KU -- unsigned integer -// KF -- float -// KD -- double -// KS -- string constant -// -// Defaults to functioning in debug build, not in release builds. -// To force on, define STB_ALWAYS_H - -#ifdef STB_CONVENIENT_H -#define KI(x) STB_I(x) -#define KU(x) STB_UI(x) -#define KF(x) STB_F(x) -#define KD(x) STB_D(x) -#define KS(x) STB_S(x) -#endif - -STB_EXTERN void stb_source_path(char *str); -#ifdef STB_DEFINE -char *stb__source_path; -void stb_source_path(char *path) -{ - stb__source_path = path; -} - -char *stb__get_sourcefile_path(char *file) -{ - static char filebuf[512]; - if (stb__source_path) { - stb_p_sprintf(filebuf stb_p_size(sizeof(filebuf)), "%s/%s", stb__source_path, file); - if (stb_fexists(filebuf)) return filebuf; - } - - if (stb_fexists(file)) return file; - - stb_p_sprintf(filebuf stb_p_size(sizeof(filebuf)), "../%s", file); - if (!stb_fexists(filebuf)) return filebuf; - - return file; -} -#endif - -#define STB_F(x) ((float) STB_H(x)) -#define STB_UI(x) ((unsigned int) STB_I(x)) - -#if !defined(STB_DEBUG) && !defined(STB_ALWAYS_H) -#define STB_D(x) ((double) (x)) -#define STB_I(x) ((int) (x)) -#define STB_S(x) ((char *) (x)) -#else -#define STB_D(x) stb__double_constant(__FILE__, __LINE__-1, (x)) -#define STB_I(x) stb__int_constant(__FILE__, __LINE__-1, (x)) -#define STB_S(x) stb__string_constant(__FILE__, __LINE__-1, (x)) - -STB_EXTERN double stb__double_constant(char *file, int line, double x); -STB_EXTERN int stb__int_constant(char *file, int line, int x); -STB_EXTERN char * stb__string_constant(char *file, int line, char *str); - -#ifdef STB_DEFINE - -enum -{ - STB__CTYPE_int, - STB__CTYPE_uint, - STB__CTYPE_float, - STB__CTYPE_double, - STB__CTYPE_string, -}; - -typedef struct -{ - int line; - int type; - union { - int ival; - double dval; - char *sval; - }; -} stb__Entry; - -typedef struct -{ - stb__Entry *entries; - char *filename; - time_t timestamp; - char **file_data; - int file_len; - unsigned short *line_index; -} stb__FileEntry; - -static void stb__constant_parse(stb__FileEntry *f, int i) -{ - char *s; - int n; - if (!stb_arr_valid(f->entries, i)) return; - n = f->entries[i].line; - if (n >= f->file_len) return; - s = f->file_data[n]; - switch (f->entries[i].type) { - case STB__CTYPE_float: - while (*s) { - if (!strncmp(s, "STB_D(", 6)) { s+=6; goto matched_float; } - if (!strncmp(s, "STB_F(", 6)) { s+=6; goto matched_float; } - if (!strncmp(s, "KD(", 3)) { s+=3; goto matched_float; } - if (!strncmp(s, "KF(", 3)) { s+=3; goto matched_float; } - ++s; - } - break; - matched_float: - f->entries[i].dval = strtod(s, NULL); - break; - case STB__CTYPE_int: - while (*s) { - if (!strncmp(s, "STB_I(", 6)) { s+=6; goto matched_int; } - if (!strncmp(s, "STB_UI(", 7)) { s+=7; goto matched_int; } - if (!strncmp(s, "KI(", 3)) { s+=3; goto matched_int; } - if (!strncmp(s, "KU(", 3)) { s+=3; goto matched_int; } - ++s; - } - break; - matched_int: { - int neg=0; - s = stb_skipwhite(s); - while (*s == '-') { neg = !neg; s = stb_skipwhite(s+1); } // handle '- - 5', pointlessly - if (s[0] == '0' && tolower(s[1]) == 'x') - f->entries[i].ival = strtol(s, NULL, 16); - else if (s[0] == '0') - f->entries[i].ival = strtol(s, NULL, 8); - else - f->entries[i].ival = strtol(s, NULL, 10); - if (neg) f->entries[i].ival = -f->entries[i].ival; - break; - } - case STB__CTYPE_string: - // @TODO - break; - } -} - -static stb_sdict *stb__constant_file_hash; - -stb__Entry *stb__constant_get_entry(char *filename, int line, int type) -{ - int i; - stb__FileEntry *f; - if (stb__constant_file_hash == NULL) - stb__constant_file_hash = stb_sdict_new(STB_TRUE); - f = (stb__FileEntry*) stb_sdict_get(stb__constant_file_hash, filename); - if (f == NULL) { - char *s = stb__get_sourcefile_path(filename); - if (s == NULL || !stb_fexists(s)) return 0; - f = (stb__FileEntry *) malloc(sizeof(*f)); - f->timestamp = stb_ftimestamp(s); - f->file_data = stb_stringfile(s, &f->file_len); - f->filename = stb_p_strdup(s); // cache the full path - f->entries = NULL; - f->line_index = 0; - stb_arr_setlen(f->line_index, f->file_len); - memset(f->line_index, 0xff, stb_arr_storage(f->line_index)); - } else { - time_t t = stb_ftimestamp(f->filename); - if (f->timestamp != t) { - f->timestamp = t; - free(f->file_data); - f->file_data = stb_stringfile(f->filename, &f->file_len); - stb_arr_setlen(f->line_index, f->file_len); - for (i=0; i < stb_arr_len(f->entries); ++i) - stb__constant_parse(f, i); - } - } - - if (line >= f->file_len) return 0; - - if (f->line_index[line] >= stb_arr_len(f->entries)) { - // need a new entry - int n = stb_arr_len(f->entries); - stb__Entry e; - e.line = line; - if (line < f->file_len) - f->line_index[line] = n; - e.type = type; - stb_arr_push(f->entries, e); - stb__constant_parse(f, n); - } - return f->entries + f->line_index[line]; -} - -double stb__double_constant(char *file, int line, double x) -{ - stb__Entry *e = stb__constant_get_entry(file, line, STB__CTYPE_float); - if (!e) return x; - return e->dval; -} - -int stb__int_constant(char *file, int line, int x) -{ - stb__Entry *e = stb__constant_get_entry(file, line, STB__CTYPE_int); - if (!e) return x; - return e->ival; -} - -char * stb__string_constant(char *file, int line, char *x) -{ - stb__Entry *e = stb__constant_get_entry(file, line, STB__CTYPE_string); - if (!e) return x; - return e->sval; -} - -#endif // STB_DEFINE -#endif // !STB_DEBUG && !STB_ALWAYS_H - -#undef STB_EXTERN -#endif // STB_INCLUDE_STB_H - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ diff --git a/source/engine/thirdparty/stb/deprecated/stb_image.c b/source/engine/thirdparty/stb/deprecated/stb_image.c deleted file mode 100644 index de0d935..0000000 --- a/source/engine/thirdparty/stb/deprecated/stb_image.c +++ /dev/null @@ -1,4678 +0,0 @@ -/* stb_image - v1.35 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c - when you control the images you're loading - no warranty implied; use at your own risk - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline (no JPEG progressive) - PNG 8-bit-per-channel only - - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels) - - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) - - Latest revisions: - 1.35 (2014-05-27) warnings, bugfixes, TGA optimization, etc - 1.34 (unknown ) warning fix - 1.33 (2011-07-14) minor fixes suggested by Dave Moore - 1.32 (2011-07-13) info support for all filetypes (SpartanJ) - 1.31 (2011-06-19) a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) added ability to load files via io callbacks (Ben Wenger) - 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) - - See end of file for full revision history. - - TODO: - stbi_info support for BMP,PSD,HDR,PIC - - - ============================ Contributors ========================= - - Image formats Bug fixes & warning fixes - Sean Barrett (jpeg, png, bmp) Marc LeBlanc - Nicolas Schulz (hdr, psd) Christpher Lloyd - Jonathan Dummer (tga) Dave Moore - Jean-Marc Lienher (gif) Won Chun - Tom Seddon (pic) the Horde3D community - Thatcher Ulrich (psd) Janez Zemva - Jonathan Blow - Laurent Gomila - Extensions, features Aruelien Pocheville - Jetro Lauha (stbi_info) Ryamond Barbiero - James "moose2000" Brown (iPhone PNG) David Woo - Ben "Disch" Wenger (io callbacks) Roy Eltham - Martin "SpartanJ" Golini Luke Graham - Thomas Ruf - John Bartholomew - Optimizations & bugfixes Ken Hamada - Fabian "ryg" Giesen Cort Stratton - Arseny Kapoulkine Blazej Dariusz Roszkowski - Thibault Reuille - If your name should be here but Paul Du Bois - isn't let Sean know. Guillaume George - -*/ - -#ifndef STBI_INCLUDE_STB_IMAGE_H -#define STBI_INCLUDE_STB_IMAGE_H - -// To get a header file for this, either cut and paste the header, -// or create stb_image.h, #define STBI_HEADER_FILE_ONLY, and -// then include stb_image.c from it. - -//// begin header file //////////////////////////////////////////////////// -// -// Limitations: -// - no jpeg progressive support -// - non-HDR formats support 8-bit samples only (jpeg, png) -// - no delayed line count (jpeg) -- IJG doesn't support either -// - no 1-bit BMP -// - GIF always returns *comp=4 -// -// Basic usage (see HDR discussion below): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *comp -- outputs # of image components in image file -// int req_comp -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. -// If req_comp is non-zero, *comp has the number of components that _would_ -// have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to easily see if it's opaque. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() -// can be queried for an extremely brief, end-user unfriendly explanation -// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid -// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. -// -// =========================================================================== -// -// iPhone PNG support: -// -// By default we convert iphone-formatted PNGs back to RGB; nominally they -// would silently load as BGR, except the existing code should have just -// failed on such iPhone PNGs. But you can disable this conversion by -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through. -// -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); -// -// =========================================================================== -// -// I/O callbacks -// -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. -// -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). - - -#ifndef STBI_NO_STDIO - -#if defined(_MSC_VER) && _MSC_VER >= 1400 -#define _CRT_SECURE_NO_WARNINGS // suppress warnings about fopen() -#pragma warning(push) -#pragma warning(disable:4996) // suppress even more warnings about fopen() -#endif -#include -#endif // STBI_NO_STDIO - -#define STBI_VERSION 1 - -enum -{ - STBI_default = 0, // only used for req_comp - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -typedef unsigned char stbi_uc; - -#ifdef __cplusplus -extern "C" { -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// PRIMARY API - works on images of any type -// - -// -// load image by filename, open file, or memory buffer -// - -extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - -#ifndef STBI_NO_STDIO -extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data -} stbi_io_callbacks; - -extern stbi_uc *stbi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); - -#ifndef STBI_NO_HDR - extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - - #ifndef STBI_NO_STDIO - extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); - extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); - #endif - - extern float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); - - extern void stbi_hdr_to_ldr_gamma(float gamma); - extern void stbi_hdr_to_ldr_scale(float scale); - - extern void stbi_ldr_to_hdr_gamma(float gamma); - extern void stbi_ldr_to_hdr_scale(float scale); -#endif // STBI_NO_HDR - -// stbi_is_hdr is always defined -extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -extern int stbi_is_hdr (char const *filename); -extern int stbi_is_hdr_from_file(FILE *f); -#endif // STBI_NO_STDIO - - -// get a VERY brief reason for failure -// NOT THREADSAFE -extern const char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -extern void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -extern int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -extern int stbi_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); - -#endif - - - -// for image formats that explicitly notate that they have premultiplied alpha, -// we just return the colors as stored in the file. set this flag to force -// unpremultiplication. results are undefined if the unpremultiply overflow. -extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); - -// indicate whether we should process iphone images back to canonical format, -// or just pass them through "as-is" -extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); - - -// ZLIB client - used by PNG, available for other purposes - -extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -extern char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - - -// define faster low-level operations (typically SIMD support) -#ifdef STBI_SIMD -typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, short data[64], unsigned short *dequantize); -// compute an integer IDCT on "input" -// input[x] = data[x] * dequantize[x] -// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' -// CLAMP results to 0..255 -typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step); -// compute a conversion from YCbCr to RGB -// 'count' pixels -// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B -// y: Y input channel -// cb: Cb input channel; scale/biased to be 0..255 -// cr: Cr input channel; scale/biased to be 0..255 - -extern void stbi_install_idct(stbi_idct_8x8 func); -extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); -#endif // STBI_SIMD - - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBI_INCLUDE_STB_IMAGE_H - -#ifndef STBI_HEADER_FILE_ONLY - -#ifndef STBI_NO_HDR -#include // ldexp -#include // strcmp, strtok -#endif - -#ifndef STBI_NO_STDIO -#include -#endif -#include -#include -#include -#include -#include // ptrdiff_t on osx - -#ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif -#else - #define stbi_inline __forceinline -#endif - - -#ifdef _MSC_VER -typedef unsigned char stbi__uint8; -typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; -#else -#include -typedef uint8_t stbi__uint8; -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; -#endif - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) -#else -#define STBI_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef _MSC_VER -#define STBI_HAS_LROTL -#endif - -#ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) -#else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) -#endif - -/////////////////////////////////////////////// -// -// stbi struct and start_xxx functions - -// stbi structure is our basic context used by all images, so it -// contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; - - stbi_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; - int buflen; - stbi__uint8 buffer_start[128]; - - stbi__uint8 *img_buffer, *img_buffer_end; - stbi__uint8 *img_buffer_original; -} stbi; - - -static void refill_buffer(stbi *s); - -// initialize a memory-decode context -static void start_mem(stbi *s, stbi__uint8 const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi__uint8 *) buffer; - s->img_buffer_end = (stbi__uint8 *) buffer+len; -} - -// initialize a callback-based context -static void start_callbacks(stbi *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - refill_buffer(s); -} - -#ifndef STBI_NO_STDIO - -static int stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} - -static void stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} - -static int stdio_eof(void *user) -{ - return feof((FILE*) user); -} - -static stbi_io_callbacks stbi_stdio_callbacks = -{ - stdio_read, - stdio_skip, - stdio_eof, -}; - -static void start_file(stbi *s, FILE *f) -{ - start_callbacks(s, &stbi_stdio_callbacks, (void *) f); -} - -//static void stop_file(stbi *s) { } - -#endif // !STBI_NO_STDIO - -static void stbi_rewind(stbi *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; -} - -static int stbi_jpeg_test(stbi *s); -static stbi_uc *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp); -static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp); -static int stbi_png_test(stbi *s); -static stbi_uc *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp); -static int stbi_png_info(stbi *s, int *x, int *y, int *comp); -static int stbi_bmp_test(stbi *s); -static stbi_uc *stbi_bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp); -static int stbi_tga_test(stbi *s); -static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp); -static int stbi_tga_info(stbi *s, int *x, int *y, int *comp); -static int stbi_psd_test(stbi *s); -static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp); -#ifndef STBI_NO_HDR -static int stbi_hdr_test(stbi *s); -static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp); -#endif -static int stbi_pic_test(stbi *s); -static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp); -static int stbi_gif_test(stbi *s); -static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp); -static int stbi_gif_info(stbi *s, int *x, int *y, int *comp); - - -// this is not threadsafe -static const char *failure_reason; - -const char *stbi_failure_reason(void) -{ - return failure_reason; -} - -static int e(const char *str) -{ - failure_reason = str; - return 0; -} - -// e - error -// epf - error returning pointer to float -// epuc - error returning pointer to unsigned char - -#ifdef STBI_NO_FAILURE_STRINGS - #define e(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define e(x,y) e(y) -#else - #define e(x,y) e(x) -#endif - -#define epf(x,y) ((float *) (e(x,y)?NULL:NULL)) -#define epuc(x,y) ((unsigned char *) (e(x,y)?NULL:NULL)) - -void stbi_image_free(void *retval_from_stbi_load) -{ - free(retval_from_stbi_load); -} - -#ifndef STBI_NO_HDR -static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -static unsigned char *stbi_load_main(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - if (stbi_jpeg_test(s)) return stbi_jpeg_load(s,x,y,comp,req_comp); - if (stbi_png_test(s)) return stbi_png_load(s,x,y,comp,req_comp); - if (stbi_bmp_test(s)) return stbi_bmp_load(s,x,y,comp,req_comp); - if (stbi_gif_test(s)) return stbi_gif_load(s,x,y,comp,req_comp); - if (stbi_psd_test(s)) return stbi_psd_load(s,x,y,comp,req_comp); - if (stbi_pic_test(s)) return stbi_pic_load(s,x,y,comp,req_comp); - - #ifndef STBI_NO_HDR - if (stbi_hdr_test(s)) { - float *hdr = stbi_hdr_load(s, x,y,comp,req_comp); - return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - // test tga last because it's a crappy test! - if (stbi_tga_test(s)) - return stbi_tga_load(s,x,y,comp,req_comp); - return epuc("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO -unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = fopen(filename, "rb"); - unsigned char *result; - if (!f) return epuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi s; - start_file(&s,f); - result = stbi_load_main(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} -#endif //!STBI_NO_STDIO - -unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_mem(&s,buffer,len); - return stbi_load_main(&s,x,y,comp,req_comp); -} - -unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_load_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_HDR - -float *stbi_loadf_main(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi_hdr_test(s)) - return stbi_hdr_load(s,x,y,comp,req_comp); - #endif - data = stbi_load_main(s, x, y, comp, req_comp); - if (data) - return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return epf("unknown image type", "Image not of any known type, or corrupt"); -} - -float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_mem(&s,buffer,len); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} - -float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = fopen(filename, "rb"); - float *result; - if (!f) return epf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_file(&s,f); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} -#endif // !STBI_NO_STDIO - -#endif // !STBI_NO_HDR - -// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is -// defined, for API simplicity; if STBI_NO_HDR is defined, it always -// reports false! - -int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi s; - start_mem(&s,buffer,len); - return stbi_hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -extern int stbi_is_hdr (char const *filename) -{ - FILE *f = fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -extern int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - stbi s; - start_file(&s,f); - return stbi_hdr_test(&s); - #else - return 0; - #endif -} -#endif // !STBI_NO_STDIO - -extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi s; - start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_hdr_test(&s); - #else - return 0; - #endif -} - -#ifndef STBI_NO_HDR -static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f; -static float l2h_gamma=2.2f, l2h_scale=1.0f; - -void stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; } -void stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; } - -void stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; } -void stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; } -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -enum -{ - SCAN_load=0, - SCAN_type, - SCAN_header -}; - -static void refill_buffer(stbi *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static int get8(stbi *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -stbi_inline static int at_eof(stbi *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} - -stbi_inline static stbi__uint8 get8u(stbi *s) -{ - return (stbi__uint8) get8(s); -} - -static void skip(stbi *s, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} - -static int getn(stbi *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int get16(stbi *s) -{ - int z = get8(s); - return (z << 8) + get8(s); -} - -static stbi__uint32 get32(stbi *s) -{ - stbi__uint32 z = get16(s); - return (z << 16) + get16(s); -} - -static int get16le(stbi *s) -{ - int z = get8(s); - return z + (get8(s) << 8); -} - -static stbi__uint32 get32le(stbi *s) -{ - stbi__uint32 z = get16le(s); - return z + (get16le(s) << 16); -} - -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static stbi__uint8 compute_y(int r, int g, int b) -{ - return (stbi__uint8) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - assert(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) malloc(req_comp * x * y); - if (good == NULL) { - free(data); - return epuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define COMBO(a,b) ((a)*8+(b)) - #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (COMBO(img_n, req_comp)) { - CASE(1,2) dest[0]=src[0], dest[1]=255; break; - CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; - CASE(2,1) dest[0]=src[0]; break; - CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; - CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; - CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break; - CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break; - CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break; - CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; - CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; - default: assert(0); - } - #undef CASE - } - - free(data); - return good; -} - -#ifndef STBI_NO_HDR -static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output = (float *) malloc(x * y * comp * sizeof(float)); - if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale; - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - free(data); - return output; -} - -#define float2int(x) ((int) (x)) -static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output = (stbi_uc *) malloc(x * y * comp); - if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi__uint8) float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi__uint8) float2int(z); - } - } - free(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder (not actually fully baseline implementation) -// -// simple implementation -// - channel subsampling of at most 2 in each dimension -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - uses a lot of intermediate memory, could cache poorly -// - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4 -// stb_jpeg: 1.34 seconds (MSVC6, default release build) -// stb_jpeg: 1.06 seconds (MSVC6, processor = Pentium Pro) -// IJL11.dll: 1.08 seconds (compiled by intel) -// IJG 1998: 0.98 seconds (MSVC6, makefile provided by IJG) -// IJG 1998: 0.95 seconds (MSVC6, makefile + proc=PPro) - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi__uint8 fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi__uint8 values[256]; - stbi__uint8 size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} huffman; - -typedef struct -{ - #ifdef STBI_SIMD - unsigned short dequant2[4][64]; - #endif - stbi *s; - huffman huff_dc[4]; - huffman huff_ac[4]; - stbi__uint8 dequant[4][64]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi__uint8 *data; - void *raw_data; - stbi__uint8 *linebuf; - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int scan_n, order[4]; - int restart_interval, todo; -} jpeg; - -static int build_huffman(huffman *h, int *count) -{ - int i,j,k=0,code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi__uint8) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi__uint8) i; - } - } - } - return 1; -} - -static void grow_buffer_unsafe(jpeg *j) -{ - do { - int b = j->nomore ? 0 : get8(j->s); - if (b == 0xff) { - int c = get8(j->s); - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); -} - -// (1 << n) - 1 -static stbi__uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -stbi_inline static int decode(jpeg *j, huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & bmask[k]) + h->delta[k]; - assert((((j->code_buffer) >> (32 - h->size[c])) & bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; -} - -// combined JPEG 'receive' and JPEG 'extend', since baseline -// always extends everything it receives. -stbi_inline static int extend_receive(jpeg *j, int n) -{ - unsigned int m = 1 << (n-1); - unsigned int k; - if (j->code_bits < n) grow_buffer_unsafe(j); - - #if 1 - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~bmask[n]; - k &= bmask[n]; - j->code_bits -= n; - #else - k = (j->code_buffer >> (32 - n)) & bmask[n]; - j->code_bits -= n; - j->code_buffer <<= n; - #endif - // the following test is probably a random branch that won't - // predict well. I tried to table accelerate it but failed. - // maybe it's compiling as a conditional move? - if (k < m) - return (-1 << n) + k + 1; - else - return k; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static stbi__uint8 dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int decode_block(jpeg *j, short data[64], huffman *hdc, huffman *hac, int b) -{ - int diff,dc,k; - int t = decode(j, hdc); - if (t < 0) return e("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) dc; - - // decode AC components, see JPEG spec - k = 1; - do { - int r,s; - int rs = decode(j, hac); - if (rs < 0) return e("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - data[dezigzag[k++]] = (short) extend_receive(j,s); - } - } while (k < 64); - return 1; -} - -// take a -128..127 value and clamp it and convert to 0..255 -stbi_inline static stbi__uint8 clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi__uint8) x; -} - -#define f2f(x) (int) (((x) * 4096 + 0.5)) -#define fsh(x) ((x) << 12) - -// derived from jidctint -- DCT_ISLOW -#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * f2f(0.5411961f); \ - t2 = p1 + p3*f2f(-1.847759065f); \ - t3 = p1 + p2*f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = fsh(p2+p3); \ - t1 = fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*f2f( 1.175875602f); \ - t0 = t0*f2f( 0.298631336f); \ - t1 = t1*f2f( 2.053119869f); \ - t2 = t2*f2f( 3.072711026f); \ - t3 = t3*f2f( 1.501321110f); \ - p1 = p5 + p1*f2f(-0.899976223f); \ - p2 = p5 + p2*f2f(-2.562915447f); \ - p3 = p3*f2f(-1.961570560f); \ - p4 = p4*f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -#ifdef STBI_SIMD -typedef unsigned short stbi_dequantize_t; -#else -typedef stbi__uint8 stbi_dequantize_t; -#endif - -// .344 seconds on 3*anemones.jpg -static void idct_block(stbi__uint8 *out, int out_stride, short data[64], stbi_dequantize_t *dequantize) -{ - int i,val[64],*v=val; - stbi_dequantize_t *dq = dequantize; - stbi__uint8 *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d,++dq, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] * dq[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], - d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = clamp((x0+t3) >> 17); - o[7] = clamp((x0-t3) >> 17); - o[1] = clamp((x1+t2) >> 17); - o[6] = clamp((x1-t2) >> 17); - o[2] = clamp((x2+t1) >> 17); - o[5] = clamp((x2-t1) >> 17); - o[3] = clamp((x3+t0) >> 17); - o[4] = clamp((x3-t0) >> 17); - } -} - -#ifdef STBI_SIMD -static stbi_idct_8x8 stbi_idct_installed = idct_block; - -void stbi_install_idct(stbi_idct_8x8 func) -{ - stbi_idct_installed = func; -} -#endif - -#define MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static stbi__uint8 get_marker(jpeg *j) -{ - stbi__uint8 x; - if (j->marker != MARKER_none) { x = j->marker; j->marker = MARKER_none; return x; } - x = get8u(j->s); - if (x != 0xff) return MARKER_none; - while (x == 0xff) - x = get8u(j->s); - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -#define RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, reset the entropy decoder and -// the dc prediction -static void reset(jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; - j->marker = MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int parse_entropy_coded_data(jpeg *z) -{ - reset(z); - if (z->scan_n == 1) { - int i,j; - #ifdef STBI_SIMD - __declspec(align(16)) - #endif - short data[64]; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; - #ifdef STBI_SIMD - stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); - #else - idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); - #endif - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!RESTART(z->marker)) return 1; - reset(z); - } - } - } - } else { // interleaved! - int i,j,k,x,y; - short data[64]; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; - #ifdef STBI_SIMD - stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); - #else - idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); - #endif - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!RESTART(z->marker)) return 1; - reset(z); - } - } - } - } - return 1; -} - -static int process_marker(jpeg *z, int m) -{ - int L; - switch (m) { - case MARKER_none: // no marker found - return e("expected marker","Corrupt JPEG"); - - case 0xC2: // SOF - progressive - return e("progressive jpeg","JPEG format not supported (progressive)"); - - case 0xDD: // DRI - specify restart interval - if (get16(z->s) != 4) return e("bad DRI len","Corrupt JPEG"); - z->restart_interval = get16(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = get16(z->s)-2; - while (L > 0) { - int q = get8(z->s); - int p = q >> 4; - int t = q & 15,i; - if (p != 0) return e("bad DQT type","Corrupt JPEG"); - if (t > 3) return e("bad DQT table","Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][dezigzag[i]] = get8u(z->s); - #ifdef STBI_SIMD - for (i=0; i < 64; ++i) - z->dequant2[t][i] = z->dequant[t][i]; - #endif - L -= 65; - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = get16(z->s)-2; - while (L > 0) { - stbi__uint8 *v; - int sizes[16],i,n=0; - int q = get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = get8u(z->s); - L -= n; - } - return L==0; - } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - skip(z->s, get16(z->s)-2); - return 1; - } - return 0; -} - -// after we see SOS -static int process_scan_header(jpeg *z) -{ - int i; - int Ls = get16(z->s); - z->scan_n = get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return e("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return e("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = get8(z->s), which; - int q = get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG"); - get8(z->s); // should be 63, but might be 0 - if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG"); - - return 1; -} - -static int process_frame_header(jpeg *z, int scan) -{ - stbi *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = get16(s); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG - p = get8(s); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = get16(s); if (s->img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = get16(s); if (s->img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires - c = get8(s); - if (c != 3 && c != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return e("bad SOF len","Corrupt JPEG"); - - for (i=0; i < s->img_n; ++i) { - z->img_comp[i].id = get8(s); - if (z->img_comp[i].id != i+1) // JFIF requires - if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! - return e("bad component ID","Corrupt JPEG"); - q = get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return e("bad V","Corrupt JPEG"); - z->img_comp[i].tq = get8(s); if (z->img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); - } - - if (scan != SCAN_load) return 1; - - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); - if (z->img_comp[i].raw_data == NULL) { - for(--i; i >= 0; --i) { - free(z->img_comp[i].raw_data); - z->img_comp[i].data = NULL; - } - return e("outofmem", "Out of memory"); - } - // align blocks for installable-idct using mmx/sse - z->img_comp[i].data = (stbi__uint8*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - z->img_comp[i].linebuf = NULL; - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define DNL(x) ((x) == 0xdc) -#define SOI(x) ((x) == 0xd8) -#define EOI(x) ((x) == 0xd9) -#define SOF(x) ((x) == 0xc0 || (x) == 0xc1) -#define SOS(x) ((x) == 0xda) - -static int decode_jpeg_header(jpeg *z, int scan) -{ - int m; - z->marker = MARKER_none; // initialize cached marker to empty - m = get_marker(z); - if (!SOI(m)) return e("no SOI","Corrupt JPEG"); - if (scan == SCAN_type) return 1; - m = get_marker(z); - while (!SOF(m)) { - if (!process_marker(z,m)) return 0; - m = get_marker(z); - while (m == MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (at_eof(z->s)) return e("no SOF", "Corrupt JPEG"); - m = get_marker(z); - } - } - if (!process_frame_header(z, scan)) return 0; - return 1; -} - -static int decode_jpeg_image(jpeg *j) -{ - int m; - j->restart_interval = 0; - if (!decode_jpeg_header(j, SCAN_load)) return 0; - m = get_marker(j); - while (!EOI(m)) { - if (SOS(m)) { - if (!process_scan_header(j)) return 0; - if (!parse_entropy_coded_data(j)) return 0; - if (j->marker == MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!at_eof(j->s)) { - int x = get8(j->s); - if (x == 255) { - j->marker = get8u(j->s); - break; - } else if (x != 0) { - return 0; - } - } - // if we reach eof without hitting a marker, get_marker() below will fail and we'll eventually return 0 - } - } else { - if (!process_marker(j, m)) return 0; - } - m = get_marker(j); - } - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef stbi__uint8 *(*resample_row_func)(stbi__uint8 *out, stbi__uint8 *in0, stbi__uint8 *in1, - int w, int hs); - -#define div4(x) ((stbi__uint8) ((x) >> 2)) - -static stbi__uint8 *resample_row_1(stbi__uint8 *out, stbi__uint8 *in_near, stbi__uint8 *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; -} - -static stbi__uint8* resample_row_v_2(stbi__uint8 *out, stbi__uint8 *in_near, stbi__uint8 *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static stbi__uint8* resample_row_h_2(stbi__uint8 *out, stbi__uint8 *in_near, stbi__uint8 *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi__uint8 *input = in_near; - - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = div4(n+input[i-1]); - out[i*2+1] = div4(n+input[i+1]); - } - out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); - - return out; -} - -#define div16(x) ((stbi__uint8) ((x) >> 4)) - -static stbi__uint8 *resample_row_hv_2(stbi__uint8 *out, stbi__uint8 *in_near, stbi__uint8 *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = div16(3*t0 + t1 + 8); - out[i*2 ] = div16(3*t1 + t0 + 8); - } - out[w*2-1] = div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} - -static stbi__uint8 *resample_row_generic(stbi__uint8 *out, stbi__uint8 *in_near, stbi__uint8 *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) - -// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) -// VC6 without processor=Pro is generating multiple LEAs per multiply! -static void YCbCr_to_RGB_row(stbi__uint8 *out, const stbi__uint8 *y, const stbi__uint8 *pcb, const stbi__uint8 *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi__uint8)r; - out[1] = (stbi__uint8)g; - out[2] = (stbi__uint8)b; - out[3] = 255; - out += step; - } -} - -#ifdef STBI_SIMD -static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; - -void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) -{ - stbi_YCbCr_installed = func; -} -#endif - - -// clean up the temporary component buffers -static void cleanup_jpeg(jpeg *j) -{ - int i; - for (i=0; i < j->s->img_n; ++i) { - if (j->img_comp[i].data) { - free(j->img_comp[i].raw_data); - j->img_comp[i].data = NULL; - } - if (j->img_comp[i].linebuf) { - free(j->img_comp[i].linebuf); - j->img_comp[i].linebuf = NULL; - } - } -} - -typedef struct -{ - resample_row_func resample; - stbi__uint8 *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi_resample; - -static stbi__uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n; - // validate req_comp - if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); - z->s->img_n = 0; - - // load a jpeg image from whichever source - if (!decode_jpeg_image(z)) { cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n; - - if (z->s->img_n == 3 && n < 3) - decode_n = 1; - else - decode_n = z->s->img_n; - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi__uint8 *output; - stbi__uint8 *coutput[4]; - - stbi_resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi_resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi__uint8 *) malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2; - else r->resample = resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi__uint8 *) malloc(n * z->s->img_x * z->s->img_y + 1); - if (!output) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi__uint8 *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi_resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi__uint8 *y = coutput[0]; - if (z->s->img_n == 3) { - #ifdef STBI_SIMD - stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s->img_x, n); - #else - YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s->img_x, n); - #endif - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - stbi__uint8 *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n; // report original components, not output - return output; - } -} - -static unsigned char *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - jpeg j; - j.s = s; - return load_jpeg_image(&j, x,y,comp,req_comp); -} - -static int stbi_jpeg_test(stbi *s) -{ - int r; - jpeg j; - j.s = s; - r = decode_jpeg_header(&j, SCAN_type); - stbi_rewind(s); - return r; -} - -static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp) -{ - if (!decode_jpeg_header(j, SCAN_header)) { - stbi_rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n; - return 1; -} - -static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp) -{ - jpeg j; - j.s = s; - return stbi_jpeg_info_raw(&j, x, y, comp); -} - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define ZFAST_BITS 9 // accelerate all cases in default tables -#define ZFAST_MASK ((1 << ZFAST_BITS) - 1) - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi__uint8 size[288]; - stbi__uint16 value[288]; -} zhuffman; - -stbi_inline static int bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int bit_reverse(int v, int bits) -{ - assert(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return bitreverse16(v) >> (16-bits); -} - -static int zbuild_huffman(zhuffman *z, stbi__uint8 *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 255, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - assert(sizes[i] <= (1 << i)); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - z->size[c] = (stbi__uint8)s; - z->value[c] = (stbi__uint16)i; - if (s <= ZFAST_BITS) { - int k = bit_reverse(next_code[s],s); - while (k < (1 << ZFAST_BITS)) { - z->fast[k] = (stbi__uint16) c; - k += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -typedef struct -{ - stbi__uint8 *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - zhuffman z_length, z_distance; -} zbuf; - -stbi_inline static int zget8(zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void fill_bits(zbuf *z) -{ - do { - assert(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int zreceive(zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -stbi_inline static int zhuffman_decode(zbuf *a, zhuffman *z) -{ - int b,s,k; - if (a->num_bits < 16) fill_bits(a); - b = z->fast[a->code_buffer & ZFAST_MASK]; - if (b < 0xffff) { - s = z->size[b]; - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; - } - - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = bit_reverse(a->code_buffer, 16); - for (s=ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - assert(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -static int expand(zbuf *z, int n) // need to make room for n bytes -{ - char *q; - int cur, limit; - if (!z->z_expandable) return e("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) realloc(z->zout_start, limit); - if (q == NULL) return e("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static int length_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int length_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int dist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int parse_huffman_block(zbuf *a) -{ - for(;;) { - int z = zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes - if (a->zout >= a->zout_end) if (!expand(a, 1)) return 0; - *a->zout++ = (char) z; - } else { - stbi__uint8 *p; - int len,dist; - if (z == 256) return 1; - z -= 257; - len = length_base[z]; - if (length_extra[z]) len += zreceive(a, length_extra[z]); - z = zhuffman_decode(a, &a->z_distance); - if (z < 0) return e("bad huffman code","Corrupt PNG"); - dist = dist_base[z]; - if (dist_extra[z]) dist += zreceive(a, dist_extra[z]); - if (a->zout - a->zout_start < dist) return e("bad dist","Corrupt PNG"); - if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0; - p = (stbi__uint8 *) (a->zout - dist); - while (len--) - *a->zout++ = *p++; - } - } -} - -static int compute_huffman_codes(zbuf *a) -{ - static stbi__uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - zhuffman z_codelength; - stbi__uint8 lencodes[286+32+137];//padding for maximum single op - stbi__uint8 codelength_sizes[19]; - int i,n; - - int hlit = zreceive(a,5) + 257; - int hdist = zreceive(a,5) + 1; - int hclen = zreceive(a,4) + 4; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi__uint8) s; - } - if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < hlit + hdist) { - int c = zhuffman_decode(a, &z_codelength); - assert(c >= 0 && c < 19); - if (c < 16) - lencodes[n++] = (stbi__uint8) c; - else if (c == 16) { - c = zreceive(a,2)+3; - memset(lencodes+n, lencodes[n-1], c); - n += c; - } else if (c == 17) { - c = zreceive(a,3)+3; - memset(lencodes+n, 0, c); - n += c; - } else { - assert(c == 18); - c = zreceive(a,7)+11; - memset(lencodes+n, 0, c); - n += c; - } - } - if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG"); - if (!zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int parse_uncompressed_block(zbuf *a) -{ - stbi__uint8 header[4]; - int len,nlen,k; - if (a->num_bits & 7) - zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi__uint8) (a->code_buffer & 255); // wtf this warns? - a->code_buffer >>= 8; - a->num_bits -= 8; - } - assert(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = (stbi__uint8) zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return e("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!expand(a, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int parse_zlib_header(zbuf *a) -{ - int cmf = zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = zget8(a); - if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -// @TODO: should statically initialize these for optimal thread safety -static stbi__uint8 default_length[288], default_distance[32]; -static void init_defaults(void) -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) default_length[i] = 8; - for ( ; i <= 255; ++i) default_length[i] = 9; - for ( ; i <= 279; ++i) default_length[i] = 7; - for ( ; i <= 287; ++i) default_length[i] = 8; - - for (i=0; i <= 31; ++i) default_distance[i] = 5; -} - -int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead -static int parse_zlib(zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = zreceive(a,1); - type = zreceive(a,2); - if (type == 0) { - if (!parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!default_distance[31]) init_defaults(); - if (!zbuild_huffman(&a->z_length , default_length , 288)) return 0; - if (!zbuild_huffman(&a->z_distance, default_distance, 32)) return 0; - } else { - if (!compute_huffman_codes(a)) return 0; - } - if (!parse_huffman_block(a)) return 0; - } - if (stbi_png_partial && a->zout - a->zout_start > 65536) - break; - } while (!final); - return 1; -} - -static int do_zlib(zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return parse_zlib(a, parse_header); -} - -char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - zbuf a; - char *p = (char *) malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi__uint8 *) buffer; - a.zbuffer_end = (stbi__uint8 *) buffer + len; - if (do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - free(a.zout_start); - return NULL; - } -} - -char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - zbuf a; - char *p = (char *) malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi__uint8 *) buffer; - a.zbuffer_end = (stbi__uint8 *) buffer + len; - if (do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - free(a.zout_start); - return NULL; - } -} - -int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - zbuf a; - a.zbuffer = (stbi__uint8 *) ibuffer; - a.zbuffer_end = (stbi__uint8 *) ibuffer + ilen; - if (do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - zbuf a; - char *p = (char *) malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi__uint8 *) buffer; - a.zbuffer_end = (stbi__uint8 *) buffer+len; - if (do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - free(a.zout_start); - return NULL; - } -} - -int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - zbuf a; - a.zbuffer = (stbi__uint8 *) ibuffer; - a.zbuffer_end = (stbi__uint8 *) ibuffer + ilen; - if (do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - - -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; -} chunk; - -#define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static chunk get_chunk_header(stbi *s) -{ - chunk c; - c.length = get32(s); - c.type = get32(s); - return c; -} - -static int check_png_header(stbi *s) -{ - static stbi__uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (get8u(s) != png_sig[i]) return e("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - stbi *s; - stbi__uint8 *idata, *expanded, *out; -} png; - - -enum { - F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4, - F_avg_first, F_paeth_first -}; - -static stbi__uint8 first_row_filter[5] = -{ - F_none, F_sub, F_none, F_avg_first, F_paeth_first -}; - -static int paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -// create the png data from post-deflated data -static int create_png_image_raw(png *a, stbi__uint8 *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y) -{ - stbi *s = a->s; - stbi__uint32 i,j,stride = x*out_n; - int k; - int img_n = s->img_n; // copy it into a local for later - assert(out_n == s->img_n || out_n == s->img_n+1); - if (stbi_png_partial) y = 1; - a->out = (stbi__uint8 *) malloc(x * y * out_n); - if (!a->out) return e("outofmem", "Out of memory"); - if (!stbi_png_partial) { - if (s->img_x == x && s->img_y == y) { - if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); - } else { // interlaced: - if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); - } - } - for (j=0; j < y; ++j) { - stbi__uint8 *cur = a->out + stride*j; - stbi__uint8 *prior = cur - stride; - int filter = *raw++; - if (filter > 4) return e("invalid filter","Corrupt PNG"); - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - // handle first pixel explicitly - for (k=0; k < img_n; ++k) { - switch (filter) { - case F_none : cur[k] = raw[k]; break; - case F_sub : cur[k] = raw[k]; break; - case F_up : cur[k] = raw[k] + prior[k]; break; - case F_avg : cur[k] = raw[k] + (prior[k]>>1); break; - case F_paeth : cur[k] = (stbi__uint8) (raw[k] + paeth(0,prior[k],0)); break; - case F_avg_first : cur[k] = raw[k]; break; - case F_paeth_first: cur[k] = raw[k]; break; - } - } - if (img_n != out_n) cur[img_n] = 255; - raw += img_n; - cur += out_n; - prior += out_n; - // this is a little gross, so that we don't switch per-pixel or per-component - if (img_n == out_n) { - #define CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ - for (k=0; k < img_n; ++k) - switch (filter) { - CASE(F_none) cur[k] = raw[k]; break; - CASE(F_sub) cur[k] = raw[k] + cur[k-img_n]; break; - CASE(F_up) cur[k] = raw[k] + prior[k]; break; - CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break; - CASE(F_paeth) cur[k] = (stbi__uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; - CASE(F_avg_first) cur[k] = raw[k] + (cur[k-img_n] >> 1); break; - CASE(F_paeth_first) cur[k] = (stbi__uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break; - } - #undef CASE - } else { - assert(img_n+1 == out_n); - #define CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k) - switch (filter) { - CASE(F_none) cur[k] = raw[k]; break; - CASE(F_sub) cur[k] = raw[k] + cur[k-out_n]; break; - CASE(F_up) cur[k] = raw[k] + prior[k]; break; - CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break; - CASE(F_paeth) cur[k] = (stbi__uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(F_avg_first) cur[k] = raw[k] + (cur[k-out_n] >> 1); break; - CASE(F_paeth_first) cur[k] = (stbi__uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break; - } - #undef CASE - } - } - return 1; -} - -static int create_png_image(png *a, stbi__uint8 *raw, stbi__uint32 raw_len, int out_n, int interlaced) -{ - stbi__uint8 *final; - int p; - int save; - if (!interlaced) - return create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y); - save = stbi_png_partial; - stbi_png_partial = 0; - - // de-interlacing - final = (stbi__uint8 *) malloc(a->s->img_x * a->s->img_y * out_n); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) { - free(final); - return 0; - } - for (j=0; j < y; ++j) - for (i=0; i < x; ++i) - memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n, - a->out + (j*x+i)*out_n, out_n); - free(a->out); - raw += (x*out_n+1)*y; - raw_len -= (x*out_n+1)*y; - } - } - a->out = final; - - stbi_png_partial = save; - return 1; -} - -static int compute_transparency(png *z, stbi__uint8 tc[3], int out_n) -{ - stbi *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint8 *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - assert(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int expand_palette(png *a, stbi__uint8 *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi__uint8 *p, *temp_out, *orig = a->out; - - p = (stbi__uint8 *) malloc(pixel_count * pal_img_n); - if (p == NULL) return e("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - free(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -static int stbi_unpremultiply_on_load = 0; -static int stbi_de_iphone_flag = 0; - -void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi_unpremultiply_on_load = flag_true_if_should_unpremultiply; -} -void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi_de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi_de_iphone(png *z) -{ - stbi *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint8 *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi__uint8 t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - assert(s->img_out_n == 4); - if (stbi_unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi__uint8 a = p[3]; - stbi__uint8 t = p[0]; - if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi__uint8 t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -static int parse_png_file(png *z, int scan, int req_comp) -{ - stbi__uint8 palette[1024], pal_img_n=0; - stbi__uint8 has_trans=0, tc[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, iphone=0; - stbi *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!check_png_header(s)) return 0; - - if (scan == SCAN_type) return 1; - - for (;;) { - chunk c = get_chunk_header(s); - switch (c.type) { - case PNG_TYPE('C','g','B','I'): - iphone = stbi_de_iphone_flag; - skip(s, c.length); - break; - case PNG_TYPE('I','H','D','R'): { - int depth,color,comp,filter; - if (!first) return e("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); - s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); - s->img_y = get32(s); if (s->img_y > (1 << 24)) return e("too large","Very large image (corrupt?)"); - depth = get8(s); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); - color = get8(s); if (color > 6) return e("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); - comp = get8(s); if (comp) return e("bad comp method","Corrupt PNG"); - filter= get8(s); if (filter) return e("bad filter method","Corrupt PNG"); - interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); - if (scan == SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return e("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case PNG_TYPE('P','L','T','E'): { - if (first) return e("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = get8u(s); - palette[i*4+1] = get8u(s); - palette[i*4+2] = get8u(s); - palette[i*4+3] = 255; - } - break; - } - - case PNG_TYPE('t','R','N','S'): { - if (first) return e("first not IHDR", "Corrupt PNG"); - if (z->idata) return e("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = get8u(s); - } else { - if (!(s->img_n & 1)) return e("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return e("bad tRNS len","Corrupt PNG"); - has_trans = 1; - for (k=0; k < s->img_n; ++k) - tc[k] = (stbi__uint8) get16(s); // non 8-bit images will be larger - } - break; - } - - case PNG_TYPE('I','D','A','T'): { - if (first) return e("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG"); - if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; } - if (ioff + c.length > idata_limit) { - stbi__uint8 *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - p = (stbi__uint8 *) realloc(z->idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory"); - z->idata = p; - } - if (!getn(s, z->idata+ioff,c.length)) return e("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len; - if (first) return e("first not IHDR", "Corrupt PNG"); - if (scan != SCAN_load) return 1; - if (z->idata == NULL) return e("no IDAT","Corrupt PNG"); - z->expanded = (stbi__uint8 *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !iphone); - if (z->expanded == NULL) return 0; // zlib should set error - free(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0; - if (has_trans) - if (!compute_transparency(z, tc, s->img_out_n)) return 0; - if (iphone && s->img_out_n > 2) - stbi_de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!expand_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } - free(z->expanded); z->expanded = NULL; - return 1; - } - - default: - // if critical, fail - if (first) return e("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX chunk not known"; - invalid_chunk[0] = (stbi__uint8) (c.type >> 24); - invalid_chunk[1] = (stbi__uint8) (c.type >> 16); - invalid_chunk[2] = (stbi__uint8) (c.type >> 8); - invalid_chunk[3] = (stbi__uint8) (c.type >> 0); - #endif - return e(invalid_chunk, "PNG not supported: unknown chunk type"); - } - skip(s, c.length); - break; - } - // end of chunk, read and skip CRC - get32(s); - } -} - -static unsigned char *do_png(png *p, int *x, int *y, int *n, int req_comp) -{ - unsigned char *result=NULL; - if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); - if (parse_png_file(p, SCAN_load, req_comp)) { - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - result = convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - free(p->out); p->out = NULL; - free(p->expanded); p->expanded = NULL; - free(p->idata); p->idata = NULL; - - return result; -} - -static unsigned char *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - png p; - p.s = s; - return do_png(&p, x,y,comp,req_comp); -} - -static int stbi_png_test(stbi *s) -{ - int r; - r = check_png_header(s); - stbi_rewind(s); - return r; -} - -static int stbi_png_info_raw(png *p, int *x, int *y, int *comp) -{ - if (!parse_png_file(p, SCAN_header, 0)) { - stbi_rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi_png_info(stbi *s, int *x, int *y, int *comp) -{ - png p; - p.s = s; - return stbi_png_info_raw(&p, x, y, comp); -} - -// Microsoft/Windows BMP image - -static int bmp_test(stbi *s) -{ - int sz; - if (get8(s) != 'B') return 0; - if (get8(s) != 'M') return 0; - get32le(s); // discard filesize - get16le(s); // discard reserved - get16le(s); // discard reserved - get32le(s); // discard data offset - sz = get32le(s); - if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1; - return 0; -} - -static int stbi_bmp_test(stbi *s) -{ - int r = bmp_test(s); - stbi_rewind(s); - return r; -} - - -// returns 0..31 for the highest set bit -static int high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -static int shiftsigned(int v, int shift, int bits) -{ - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; -} - -static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint8 *out; - unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; - stbi_uc pal[256][4]; - int psize=0,i,j,compress=0,width; - int bpp, flip_vertically, pad, target, offset, hsz; - if (get8(s) != 'B' || get8(s) != 'M') return epuc("not BMP", "Corrupt BMP"); - get32le(s); // discard filesize - get16le(s); // discard reserved - get16le(s); // discard reserved - offset = get32le(s); - hsz = get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = get16le(s); - s->img_y = get16le(s); - } else { - s->img_x = get32le(s); - s->img_y = get32le(s); - } - if (get16le(s) != 1) return epuc("bad BMP", "bad BMP"); - bpp = get16le(s); - if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit"); - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - if (hsz == 12) { - if (bpp < 24) - psize = (offset - 14 - 24) / 3; - } else { - compress = get32le(s); - if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE"); - get32le(s); // discard sizeof - get32le(s); // discard hres - get32le(s); // discard vres - get32le(s); // discard colorsused - get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - get32le(s); - get32le(s); - get32le(s); - get32le(s); - } - if (bpp == 16 || bpp == 32) { - mr = mg = mb = 0; - if (compress == 0) { - if (bpp == 32) { - mr = 0xffu << 16; - mg = 0xffu << 8; - mb = 0xffu << 0; - ma = 0xffu << 24; - fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 - STBI_NOTUSED(fake_a); - } else { - mr = 31u << 10; - mg = 31u << 5; - mb = 31u << 0; - } - } else if (compress == 3) { - mr = get32le(s); - mg = get32le(s); - mb = get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (mr == mg && mg == mb) { - // ?!?!? - return epuc("bad BMP", "bad BMP"); - } - } else - return epuc("bad BMP", "bad BMP"); - } - } else { - assert(hsz == 108); - mr = get32le(s); - mg = get32le(s); - mb = get32le(s); - ma = get32le(s); - get32le(s); // discard color space - for (i=0; i < 12; ++i) - get32le(s); // discard color space parameters - } - if (bpp < 16) - psize = (offset - 14 - hsz) >> 2; - } - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - out = (stbi_uc *) malloc(target * s->img_x * s->img_y); - if (!out) return epuc("outofmem", "Out of memory"); - if (bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { free(out); return epuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = get8u(s); - pal[i][1] = get8u(s); - pal[i][0] = get8u(s); - if (hsz != 12) get8(s); - pal[i][3] = 255; - } - skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); - if (bpp == 4) width = (s->img_x + 1) >> 1; - else if (bpp == 8) width = s->img_x; - else { free(out); return epuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=get8(s),v2=0; - if (bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (bpp == 8) ? get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - skip(s, pad); - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - skip(s, offset - 14 - hsz); - if (bpp == 24) width = 3 * s->img_x; - else if (bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (bpp == 24) { - easy = 1; - } else if (bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { free(out); return epuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = high_bit(mr)-7; rcount = bitcount(mr); - gshift = high_bit(mg)-7; gcount = bitcount(mg); - bshift = high_bit(mb)-7; bcount = bitcount(mb); - ashift = high_bit(ma)-7; acount = bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - int a; - out[z+2] = get8u(s); - out[z+1] = get8u(s); - out[z+0] = get8u(s); - z += 3; - a = (easy == 2 ? get8(s) : 255); - if (target == 4) out[z++] = (stbi__uint8) a; - } - } else { - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (stbi__uint32) (bpp == 16 ? get16le(s) : get32le(s)); - int a; - out[z++] = (stbi__uint8) shiftsigned(v & mr, rshift, rcount); - out[z++] = (stbi__uint8) shiftsigned(v & mg, gshift, gcount); - out[z++] = (stbi__uint8) shiftsigned(v & mb, bshift, bcount); - a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = (stbi__uint8) a; - } - } - skip(s, pad); - } - } - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; -} - -static stbi_uc *stbi_bmp_load(stbi *s,int *x, int *y, int *comp, int req_comp) -{ - return bmp_load(s, x,y,comp,req_comp); -} - - -// Targa Truevision - TGA -// by Jonathan Dummer - -static int tga_info(stbi *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp; - int sz; - get8u(s); // discard Offset - sz = get8u(s); // color type - if( sz > 1 ) { - stbi_rewind(s); - return 0; // only RGB or indexed allowed - } - sz = get8u(s); // image type - // only RGB or grey allowed, +/- RLE - if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; - skip(s,9); - tga_w = get16le(s); - if( tga_w < 1 ) { - stbi_rewind(s); - return 0; // test width - } - tga_h = get16le(s); - if( tga_h < 1 ) { - stbi_rewind(s); - return 0; // test height - } - sz = get8(s); // bits per pixel - // only RGB or RGBA or grey allowed - if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { - stbi_rewind(s); - return 0; - } - tga_comp = sz; - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp / 8; - return 1; // seems to have passed everything -} - -int stbi_tga_info(stbi *s, int *x, int *y, int *comp) -{ - return tga_info(s, x, y, comp); -} - -static int tga_test(stbi *s) -{ - int sz; - get8u(s); // discard Offset - sz = get8u(s); // color type - if ( sz > 1 ) return 0; // only RGB or indexed allowed - sz = get8u(s); // image type - if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE - get16(s); // discard palette start - get16(s); // discard palette length - get8(s); // discard bits per palette color entry - get16(s); // discard x origin - get16(s); // discard y origin - if ( get16(s) < 1 ) return 0; // test width - if ( get16(s) < 1 ) return 0; // test height - sz = get8(s); // bits per pixel - if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0; // only RGB or RGBA or grey allowed - return 1; // seems to have passed everything -} - -static int stbi_tga_test(stbi *s) -{ - int res = tga_test(s); - stbi_rewind(s); - return res; -} - -static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - // read in the TGA header stuff - int tga_offset = get8u(s); - int tga_indexed = get8u(s); - int tga_image_type = get8u(s); - int tga_is_RLE = 0; - int tga_palette_start = get16le(s); - int tga_palette_len = get16le(s); - int tga_palette_bits = get8u(s); - int tga_x_origin = get16le(s); - int tga_y_origin = get16le(s); - int tga_width = get16le(s); - int tga_height = get16le(s); - int tga_bits_per_pixel = get8u(s); - int tga_comp = tga_bits_per_pixel / 8; - int tga_inverted = get8u(s); - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4]; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - /* int tga_alpha_bits = tga_inverted & 15; */ - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // error check - if ( //(tga_indexed) || - (tga_width < 1) || (tga_height < 1) || - (tga_image_type < 1) || (tga_image_type > 3) || - ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && - (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) - ) - { - return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA - } - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) - { - tga_comp = tga_palette_bits / 8; - } - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp ); - if (!tga_data) return epuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE) { - for (i=0; i < tga_height; ++i) { - int y = tga_inverted ? tga_height -i - 1 : i; - stbi__uint8 *tga_row = tga_data + y*tga_width*tga_comp; - getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 ); - if (!tga_palette) { - free(tga_data); - return epuc("outofmem", "Out of memory"); - } - if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { - free(tga_data); - free(tga_palette); - return epuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE chunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = get8u(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in 1 byte, then perform the lookup - int pal_idx = get8u(s); - if ( pal_idx >= tga_palette_len ) - { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_bits_per_pixel / 8; - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else - { - // read in the data raw - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = get8u(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * req_comp; - int index2 = (tga_height - 1 - j) * tga_width * req_comp; - for (i = tga_width * req_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - free( tga_palette ); - } - } - - // swap RGB - if (tga_comp >= 3) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; -} - -static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - return tga_load(s,x,y,comp,req_comp); -} - - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB - -static int psd_test(stbi *s) -{ - if (get32(s) != 0x38425053) return 0; // "8BPS" - else return 1; -} - -static int stbi_psd_test(stbi *s) -{ - int r = psd_test(s); - stbi_rewind(s); - return r; -} - -static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - int pixelCount; - int channelCount, compression; - int channel, i, count, len; - int w,h; - stbi__uint8 *out; - - // Check identifier - if (get32(s) != 0x38425053) // "8BPS" - return epuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (get16(s) != 1) - return epuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = get16(s); - if (channelCount < 0 || channelCount > 16) - return epuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = get32(s); - w = get32(s); - - // Make sure the depth is 8 bits. - if (get16(s) != 8) - return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (get16(s) != 3) - return epuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - skip(s,get32(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - skip(s, get32(s) ); - - // Skip the reserved data. - skip(s, get32(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = get16(s); - if (compression > 1) - return epuc("bad compression", "PSD has an unknown compression format"); - - // Create the destination image. - out = (stbi_uc *) malloc(4 * w*h); - if (!out) return epuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi__uint8 *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; - } else { - // Read the RLE data. - count = 0; - while (count < pixelCount) { - len = get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - count += len; - while (len) { - *p = get8u(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi__uint8 val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0x0FF; - len += 2; - val = get8u(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - stbi__uint8 *p; - - p = out + channel; - if (channel > channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; - } else { - // Read the data. - for (i = 0; i < pixelCount; i++) - *p = get8u(s), p += 4; - } - } - } - - if (req_comp && req_comp != 4) { - out = convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // convert_format frees input on failure - } - - if (comp) *comp = channelCount; - *y = h; - *x = w; - - return out; -} - -static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - return psd_load(s,x,y,comp,req_comp); -} - -// ************************************************************************************************* -// Softimage PIC loader -// by Tom Seddon -// -// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format -// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ - -static int pic_is4(stbi *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int pic_test(stbi *s) -{ - int i; - - if (!pic_is4(s,"\x53\x80\xF6\x34")) - return 0; - - for(i=0;i<84;++i) - get8(s); - - if (!pic_is4(s,"PICT")) - return 0; - - return 1; -} - -typedef struct -{ - stbi_uc size,type,channel; -} pic_packet_t; - -static stbi_uc *pic_readval(stbi *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; - - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (at_eof(s)) return epuc("bad file","PIC file too short"); - dest[i]=get8u(s); - } - } - - return dest; -} - -static void pic_copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; - - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} - -static stbi_uc *pic_load2(stbi *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - pic_packet_t packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - pic_packet_t *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return epuc("bad format","too many packets"); - - packet = &packets[num_packets++]; - - chained = get8(s); - packet->size = get8u(s); - packet->type = get8u(s); - packet->channel = get8u(s); - - act_comp |= packet->channel; - - if (at_eof(s)) return epuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return epuc("bad format","packet isn't 8bpp"); - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - - for(y=0; ytype) { - default: - return epuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=get8u(s); - if (at_eof(s)) return epuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi__uint8) left; - - if (!pic_readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = get8(s), i; - if (at_eof(s)) return epuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - int i; - - if (count==128) - count = get16(s); - else - count -= 127; - if (count > left) - return epuc("bad file","scanline overrun"); - - if (!pic_readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return epuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static stbi_uc *pic_load(stbi *s,int *px,int *py,int *comp,int req_comp) -{ - stbi_uc *result; - int i, x,y; - - for (i=0; i<92; ++i) - get8(s); - - x = get16(s); - y = get16(s); - if (at_eof(s)) return epuc("bad file","file too short (pic header)"); - if ((1 << 28) / x < y) return epuc("too large", "Image too large to decode"); - - get32(s); //skip `ratio' - get16(s); //skip `fields' - get16(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) malloc(x*y*4); - memset(result, 0xff, x*y*4); - - if (!pic_load2(s,x,y,comp, result)) { - free(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi_pic_test(stbi *s) -{ - int r = pic_test(s); - stbi_rewind(s); - return r; -} - -static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - return pic_load(s,x,y,comp,req_comp); -} - -// ************************************************************************************************* -// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb -typedef struct stbi_gif_lzw_struct { - stbi__int16 prefix; - stbi__uint8 first; - stbi__uint8 suffix; -} stbi_gif_lzw; - -typedef struct stbi_gif_struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags; - stbi__uint8 pal[256][4]; - stbi__uint8 lpal[256][4]; - stbi_gif_lzw codes[4096]; - stbi__uint8 *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; -} stbi_gif; - -static int gif_test(stbi *s) -{ - int sz; - if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return 0; - sz = get8(s); - if (sz != '9' && sz != '7') return 0; - if (get8(s) != 'a') return 0; - return 1; -} - -static int stbi_gif_test(stbi *s) -{ - int r = gif_test(s); - stbi_rewind(s); - return r; -} - -static void stbi_gif_parse_colortable(stbi *s, stbi__uint8 pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = get8u(s); - pal[i][1] = get8u(s); - pal[i][0] = get8u(s); - pal[i][3] = transp ? 0 : 255; - } -} - -static int stbi_gif_header(stbi *s, stbi_gif *g, int *comp, int is_info) -{ - stbi__uint8 version; - if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') - return e("not GIF", "Corrupt GIF"); - - version = get8u(s); - if (version != '7' && version != '9') return e("not GIF", "Corrupt GIF"); - if (get8(s) != 'a') return e("not GIF", "Corrupt GIF"); - - failure_reason = ""; - g->w = get16le(s); - g->h = get16le(s); - g->flags = get8(s); - g->bgindex = get8(s); - g->ratio = get8(s); - g->transparent = -1; - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi_gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi_gif_info_raw(stbi *s, int *x, int *y, int *comp) -{ - stbi_gif g; - if (!stbi_gif_header(s, &g, comp, 1)) { - stbi_rewind( s ); - return 0; - } - if (x) *x = g.w; - if (y) *y = g.h; - return 1; -} - -static void stbi_out_gif_code(stbi_gif *g, stbi__uint16 code) -{ - stbi__uint8 *p, *c; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi_out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - p = &g->out[g->cur_x + g->cur_y]; - c = &g->color_table[g->codes[code].suffix * 4]; - - if (c[3] >= 128) { - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi__uint8 *stbi_process_gif_raster(stbi *s, stbi_gif *g) -{ - stbi__uint8 lzw_cs; - stbi__int32 len, code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi_gif_lzw *p; - - lzw_cs = get8u(s); - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (code = 0; code < clear; code++) { - g->codes[code].prefix = -1; - g->codes[code].first = (stbi__uint8) code; - g->codes[code].suffix = (stbi__uint8) code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - skip(s, len); - while ((len = get8(s)) > 0) - skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) return epuc("no clear code", "Corrupt GIF"); - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 4096) return epuc("too many codes", "Corrupt GIF"); - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return epuc("illegal code in raster", "Corrupt GIF"); - - stbi_out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return epuc("illegal code in raster", "Corrupt GIF"); - } - } - } -} - -static void stbi_fill_gif_background(stbi_gif *g) -{ - int i; - stbi__uint8 *c = g->pal[g->bgindex]; - // @OPTIMIZE: write a dword at a time - for (i = 0; i < g->w * g->h * 4; i += 4) { - stbi__uint8 *p = &g->out[i]; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } -} - -// this function is designed to support animated gifs, although stb_image doesn't support it -static stbi__uint8 *stbi_gif_load_next(stbi *s, stbi_gif *g, int *comp, int req_comp) -{ - int i; - stbi__uint8 *old_out = 0; - - if (g->out == 0) { - if (!stbi_gif_header(s, g, comp,0)) return 0; // failure_reason set by stbi_gif_header - g->out = (stbi__uint8 *) malloc(4 * g->w * g->h); - if (g->out == 0) return epuc("outofmem", "Out of memory"); - stbi_fill_gif_background(g); - } else { - // animated-gif-only path - if (((g->eflags & 0x1C) >> 2) == 3) { - old_out = g->out; - g->out = (stbi__uint8 *) malloc(4 * g->w * g->h); - if (g->out == 0) return epuc("outofmem", "Out of memory"); - memcpy(g->out, old_out, g->w*g->h*4); - } - } - - for (;;) { - switch (get8(s)) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi__uint8 *o; - - x = get16le(s); - y = get16le(s); - w = get16le(s); - h = get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return epuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - g->lflags = get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi_gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi__uint8 *) g->lpal; - } else if (g->flags & 0x80) { - for (i=0; i < 256; ++i) // @OPTIMIZE: reset only the previous transparent - g->pal[i][3] = 255; - if (g->transparent >= 0 && (g->eflags & 0x01)) - g->pal[g->transparent][3] = 0; - g->color_table = (stbi__uint8 *) g->pal; - } else - return epuc("missing color table", "Corrupt GIF"); - - o = stbi_process_gif_raster(s, g); - if (o == NULL) return NULL; - - if (req_comp && req_comp != 4) - o = convert_format(o, 4, req_comp, g->w, g->h); - return o; - } - - case 0x21: // Comment Extension. - { - int len; - if (get8(s) == 0xF9) { // Graphic Control Extension. - len = get8(s); - if (len == 4) { - g->eflags = get8(s); - get16le(s); // delay - g->transparent = get8(s); - } else { - skip(s, len); - break; - } - } - while ((len = get8(s)) != 0) - skip(s, len); - break; - } - - case 0x3B: // gif stream termination code - return (stbi__uint8 *) 1; - - default: - return epuc("unknown code", "Corrupt GIF"); - } - } -} - -static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint8 *u = 0; - stbi_gif g={0}; - - u = stbi_gif_load_next(s, &g, comp, req_comp); - if (u == (void *) 1) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - } - - return u; -} - -static int stbi_gif_info(stbi *s, int *x, int *y, int *comp) -{ - return stbi_gif_info_raw(s,x,y,comp); -} - - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int hdr_test(stbi *s) -{ - const char *signature = "#?RADIANCE\n"; - int i; - for (i=0; signature[i]; ++i) - if (get8(s) != signature[i]) - return 0; - return 1; -} - -static int stbi_hdr_test(stbi* s) -{ - int r = hdr_test(s); - stbi_rewind(s); - return r; -} - -#define HDR_BUFLEN 1024 -static char *hdr_gettoken(stbi *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) get8(z); - - while (!at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == HDR_BUFLEN-1) { - // flush to end of line - while (!at_eof(z) && get8(z) != '\n') - ; - break; - } - c = (char) get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - char buffer[HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - - - // Check identifier - if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) - return epf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return epf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - *x = width; - *y = height; - - *comp = 3; - if (req_comp == 0) req_comp = 3; - - // Read data - hdr_data = (float *) malloc(height * width * req_comp * sizeof(float)); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - getn(s, rgbe, 4); - hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = get8(s); - c2 = get8(s); - len = get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi__uint8 rgbe[4]; - rgbe[0] = (stbi__uint8) c1; - rgbe[1] = (stbi__uint8) c2; - rgbe[2] = (stbi__uint8) len; - rgbe[3] = (stbi__uint8) get8u(s); - hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - free(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= get8(s); - if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); - - for (k = 0; k < 4; ++k) { - i = 0; - while (i < width) { - count = get8u(s); - if (count > 128) { - // Run - value = get8u(s); - count -= 128; - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = get8u(s); - } - } - } - for (i=0; i < width; ++i) - hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - free(scanline); - } - - return hdr_data; -} - -static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - return hdr_load(s,x,y,comp,req_comp); -} - -static int stbi_hdr_info(stbi *s, int *x, int *y, int *comp) -{ - char buffer[HDR_BUFLEN]; - char *token; - int valid = 0; - - if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { - stbi_rewind( s ); - return 0; - } - - for(;;) { - token = hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi_rewind( s ); - return 0; - } - token = hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi_rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi_rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; -} -#endif // STBI_NO_HDR - -static int stbi_bmp_info(stbi *s, int *x, int *y, int *comp) -{ - int hsz; - if (get8(s) != 'B' || get8(s) != 'M') { - stbi_rewind( s ); - return 0; - } - skip(s,12); - hsz = get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) { - stbi_rewind( s ); - return 0; - } - if (hsz == 12) { - *x = get16le(s); - *y = get16le(s); - } else { - *x = get32le(s); - *y = get32le(s); - } - if (get16le(s) != 1) { - stbi_rewind( s ); - return 0; - } - *comp = get16le(s) / 8; - return 1; -} - -static int stbi_psd_info(stbi *s, int *x, int *y, int *comp) -{ - int channelCount; - if (get32(s) != 0x38425053) { - stbi_rewind( s ); - return 0; - } - if (get16(s) != 1) { - stbi_rewind( s ); - return 0; - } - skip(s, 6); - channelCount = get16(s); - if (channelCount < 0 || channelCount > 16) { - stbi_rewind( s ); - return 0; - } - *y = get32(s); - *x = get32(s); - if (get16(s) != 8) { - stbi_rewind( s ); - return 0; - } - if (get16(s) != 3) { - stbi_rewind( s ); - return 0; - } - *comp = 4; - return 1; -} - -static int stbi_pic_info(stbi *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained; - pic_packet_t packets[10]; - - skip(s, 92); - - *x = get16(s); - *y = get16(s); - if (at_eof(s)) return 0; - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi_rewind( s ); - return 0; - } - - skip(s, 8); - - do { - pic_packet_t *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = get8(s); - packet->size = get8u(s); - packet->type = get8u(s); - packet->channel = get8u(s); - act_comp |= packet->channel; - - if (at_eof(s)) { - stbi_rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi_rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; -} - -static int stbi_info_main(stbi *s, int *x, int *y, int *comp) -{ - if (stbi_jpeg_info(s, x, y, comp)) - return 1; - if (stbi_png_info(s, x, y, comp)) - return 1; - if (stbi_gif_info(s, x, y, comp)) - return 1; - if (stbi_bmp_info(s, x, y, comp)) - return 1; - if (stbi_psd_info(s, x, y, comp)) - return 1; - if (stbi_pic_info(s, x, y, comp)) - return 1; - #ifndef STBI_NO_HDR - if (stbi_hdr_info(s, x, y, comp)) - return 1; - #endif - // test tga last because it's a crappy test! - if (stbi_tga_info(s, x, y, comp)) - return 1; - return e("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO -int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = fopen(filename, "rb"); - int result; - if (!f) return e("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi s; - long pos = ftell(f); - start_file(&s, f); - r = stbi_info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} -#endif // !STBI_NO_STDIO - -int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi s; - start_mem(&s,buffer,len); - return stbi_info_main(&s,x,y,comp); -} - -int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi s; - start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi_info_main(&s,x,y,comp); -} - -#endif // STBI_HEADER_FILE_ONLY - -#if !defined(STBI_NO_STDIO) && defined(_MSC_VER) && _MSC_VER >= 1400 -#pragma warning(pop) -#endif - - -/* - revision history: - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi__uint8 to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.e. Janez (U+017D)emva) - 1.21 fix use of 'stbi__uint8' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 2008-08-02 - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 first released version -*/ diff --git a/source/engine/thirdparty/stb/deprecated/stb_image_resize.h b/source/engine/thirdparty/stb/deprecated/stb_image_resize.h deleted file mode 100644 index ef9e6fe..0000000 --- a/source/engine/thirdparty/stb/deprecated/stb_image_resize.h +++ /dev/null @@ -1,2634 +0,0 @@ -/* stb_image_resize - v0.97 - public domain image resizing - by Jorge L Rodriguez (@VinoBS) - 2014 - http://github.com/nothings/stb - - Written with emphasis on usability, portability, and efficiency. (No - SIMD or threads, so it be easily outperformed by libs that use those.) - Only scaling and translation is supported, no rotations or shears. - Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. - - COMPILING & LINKING - In one C/C++ file that #includes this file, do this: - #define STB_IMAGE_RESIZE_IMPLEMENTATION - before the #include. That will create the implementation in that file. - - QUICKSTART - stbir_resize_uint8( input_pixels , in_w , in_h , 0, - output_pixels, out_w, out_h, 0, num_channels) - stbir_resize_float(...) - stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, - output_pixels, out_w, out_h, 0, - num_channels , alpha_chan , 0) - stbir_resize_uint8_srgb_edgemode( - input_pixels , in_w , in_h , 0, - output_pixels, out_w, out_h, 0, - num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) - // WRAP/REFLECT/ZERO - - FULL API - See the "header file" section of the source for API documentation. - - ADDITIONAL DOCUMENTATION - - SRGB & FLOATING POINT REPRESENTATION - The sRGB functions presume IEEE floating point. If you do not have - IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use - a slower implementation. - - MEMORY ALLOCATION - The resize functions here perform a single memory allocation using - malloc. To control the memory allocation, before the #include that - triggers the implementation, do: - - #define STBIR_MALLOC(size,context) ... - #define STBIR_FREE(ptr,context) ... - - Each resize function makes exactly one call to malloc/free, so to use - temp memory, store the temp memory in the context and return that. - - ASSERT - Define STBIR_ASSERT(boolval) to override assert() and not use assert.h - - OPTIMIZATION - Define STBIR_SATURATE_INT to compute clamp values in-range using - integer operations instead of float operations. This may be faster - on some platforms. - - DEFAULT FILTERS - For functions which don't provide explicit control over what filters - to use, you can change the compile-time defaults with - - #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something - #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something - - See stbir_filter in the header-file section for the list of filters. - - NEW FILTERS - A number of 1D filter kernels are used. For a list of - supported filters see the stbir_filter enum. To add a new filter, - write a filter function and add it to stbir__filter_info_table. - - PROGRESS - For interactive use with slow resize operations, you can install - a progress-report callback: - - #define STBIR_PROGRESS_REPORT(val) some_func(val) - - The parameter val is a float which goes from 0 to 1 as progress is made. - - For example: - - static void my_progress_report(float progress); - #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) - - #define STB_IMAGE_RESIZE_IMPLEMENTATION - #include "stb_image_resize.h" - - static void my_progress_report(float progress) - { - printf("Progress: %f%%\n", progress*100); - } - - MAX CHANNELS - If your image has more than 64 channels, define STBIR_MAX_CHANNELS - to the max you'll have. - - ALPHA CHANNEL - Most of the resizing functions provide the ability to control how - the alpha channel of an image is processed. The important things - to know about this: - - 1. The best mathematically-behaved version of alpha to use is - called "premultiplied alpha", in which the other color channels - have had the alpha value multiplied in. If you use premultiplied - alpha, linear filtering (such as image resampling done by this - library, or performed in texture units on GPUs) does the "right - thing". While premultiplied alpha is standard in the movie CGI - industry, it is still uncommon in the videogame/real-time world. - - If you linearly filter non-premultiplied alpha, strange effects - occur. (For example, the 50/50 average of 99% transparent bright green - and 1% transparent black produces 50% transparent dark green when - non-premultiplied, whereas premultiplied it produces 50% - transparent near-black. The former introduces green energy - that doesn't exist in the source image.) - - 2. Artists should not edit premultiplied-alpha images; artists - want non-premultiplied alpha images. Thus, art tools generally output - non-premultiplied alpha images. - - 3. You will get best results in most cases by converting images - to premultiplied alpha before processing them mathematically. - - 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the - resizer does not do anything special for the alpha channel; - it is resampled identically to other channels. This produces - the correct results for premultiplied-alpha images, but produces - less-than-ideal results for non-premultiplied-alpha images. - - 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, - then the resizer weights the contribution of input pixels - based on their alpha values, or, equivalently, it multiplies - the alpha value into the color channels, resamples, then divides - by the resultant alpha value. Input pixels which have alpha=0 do - not contribute at all to output pixels unless _all_ of the input - pixels affecting that output pixel have alpha=0, in which case - the result for that pixel is the same as it would be without - STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for - input images in integer formats. For input images in float format, - input pixels with alpha=0 have no effect, and output pixels - which have alpha=0 will be 0 in all channels. (For float images, - you can manually achieve the same result by adding a tiny epsilon - value to the alpha channel of every image, and then subtracting - or clamping it at the end.) - - 6. You can suppress the behavior described in #5 and make - all-0-alpha pixels have 0 in all channels by #defining - STBIR_NO_ALPHA_EPSILON. - - 7. You can separately control whether the alpha channel is - interpreted as linear or affected by the colorspace. By default - it is linear; you almost never want to apply the colorspace. - (For example, graphics hardware does not apply sRGB conversion - to the alpha channel.) - - CONTRIBUTORS - Jorge L Rodriguez: Implementation - Sean Barrett: API design, optimizations - Aras Pranckevicius: bugfix - Nathan Reed: warning fixes - - REVISIONS - 0.97 (2020-02-02) fixed warning - 0.96 (2019-03-04) fixed warnings - 0.95 (2017-07-23) fixed warnings - 0.94 (2017-03-18) fixed warnings - 0.93 (2017-03-03) fixed bug with certain combinations of heights - 0.92 (2017-01-02) fix integer overflow on large (>2GB) images - 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions - 0.90 (2014-09-17) first released version - - LICENSE - See end of file for license information. - - TODO - Don't decode all of the image data when only processing a partial tile - Don't use full-width decode buffers when only processing a partial tile - When processing wide images, break processing into tiles so data fits in L1 cache - Installable filters? - Resize that respects alpha test coverage - (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: - https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) -*/ - -#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H -#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H - -#ifdef _MSC_VER -typedef unsigned char stbir_uint8; -typedef unsigned short stbir_uint16; -typedef unsigned int stbir_uint32; -#else -#include -typedef uint8_t stbir_uint8; -typedef uint16_t stbir_uint16; -typedef uint32_t stbir_uint32; -#endif - -#ifndef STBIRDEF -#ifdef STB_IMAGE_RESIZE_STATIC -#define STBIRDEF static -#else -#ifdef __cplusplus -#define STBIRDEF extern "C" -#else -#define STBIRDEF extern -#endif -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Easy-to-use API: -// -// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) -// * input_w is input image width (x-axis), input_h is input image height (y-axis) -// * stride is the offset between successive rows of image data in memory, in bytes. you can -// specify 0 to mean packed continuously in memory -// * alpha channel is treated identically to other channels. -// * colorspace is linear or sRGB as specified by function name -// * returned result is 1 for success or 0 in case of an error. -// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. -// * Memory required grows approximately linearly with input and output size, but with -// discontinuities at input_w == output_w and input_h == output_h. -// * These functions use a "default" resampling filter defined at compile time. To change the filter, -// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE -// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. - -STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels); - -STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels); - - -// The following functions interpret image data as gamma-corrected sRGB. -// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, -// or otherwise provide the index of the alpha channel. Flags value -// of 0 will probably do the right thing if you're not sure what -// the flags mean. - -#define STBIR_ALPHA_CHANNEL_NONE -1 - -// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will -// use alpha-weighted resampling (effectively premultiplying, resampling, -// then unpremultiplying). -#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) -// The specified alpha channel should be handled as gamma-corrected value even -// when doing sRGB operations. -#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) - -STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags); - - -typedef enum -{ - STBIR_EDGE_CLAMP = 1, - STBIR_EDGE_REFLECT = 2, - STBIR_EDGE_WRAP = 3, - STBIR_EDGE_ZERO = 4, -} stbir_edge; - -// This function adds the ability to specify how requests to sample off the edge of the image are handled. -STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode); - -////////////////////////////////////////////////////////////////////////////// -// -// Medium-complexity API -// -// This extends the easy-to-use API as follows: -// -// * Alpha-channel can be processed separately -// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE -// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) -// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) -// * Filter can be selected explicitly -// * uint16 image type -// * sRGB colorspace available for all types -// * context parameter for passing to STBIR_MALLOC - -typedef enum -{ - STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses - STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios - STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering - STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque - STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline - STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 -} stbir_filter; - -typedef enum -{ - STBIR_COLORSPACE_LINEAR, - STBIR_COLORSPACE_SRGB, - - STBIR_MAX_COLORSPACES, -} stbir_colorspace; - -// The following functions are all identical except for the type of the image data - -STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context); - -STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context); - -STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context); - - - -////////////////////////////////////////////////////////////////////////////// -// -// Full-complexity API -// -// This extends the medium API as follows: -// -// * uint32 image type -// * not typesafe -// * separate filter types for each axis -// * separate edge modes for each axis -// * can specify scale explicitly for subpixel correctness -// * can specify image source tile using texture coordinates - -typedef enum -{ - STBIR_TYPE_UINT8 , - STBIR_TYPE_UINT16, - STBIR_TYPE_UINT32, - STBIR_TYPE_FLOAT , - - STBIR_MAX_TYPES -} stbir_datatype; - -STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context); - -STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float x_scale, float y_scale, - float x_offset, float y_offset); - -STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float s0, float t0, float s1, float t1); -// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H - - - - - -#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION - -#ifndef STBIR_ASSERT -#include -#define STBIR_ASSERT(x) assert(x) -#endif - -// For memset -#include - -#include - -#ifndef STBIR_MALLOC -#include -// use comma operator to evaluate c, to avoid "unused parameter" warnings -#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) -#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) -#endif - -#ifndef _MSC_VER -#ifdef __cplusplus -#define stbir__inline inline -#else -#define stbir__inline -#endif -#else -#define stbir__inline __forceinline -#endif - - -// should produce compiler error if size is wrong -typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBIR__NOTUSED(v) (void)(v) -#else -#define STBIR__NOTUSED(v) (void)sizeof(v) -#endif - -#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) - -#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE -#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM -#endif - -#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE -#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL -#endif - -#ifndef STBIR_PROGRESS_REPORT -#define STBIR_PROGRESS_REPORT(float_0_to_1) -#endif - -#ifndef STBIR_MAX_CHANNELS -#define STBIR_MAX_CHANNELS 64 -#endif - -#if STBIR_MAX_CHANNELS > 65536 -#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." -// because we store the indices in 16-bit variables -#endif - -// This value is added to alpha just before premultiplication to avoid -// zeroing out color values. It is equivalent to 2^-80. If you don't want -// that behavior (it may interfere if you have floating point images with -// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to -// disable it. -#ifndef STBIR_ALPHA_EPSILON -#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) -#endif - - - -#ifdef _MSC_VER -#define STBIR__UNUSED_PARAM(v) (void)(v) -#else -#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) -#endif - -// must match stbir_datatype -static unsigned char stbir__type_size[] = { - 1, // STBIR_TYPE_UINT8 - 2, // STBIR_TYPE_UINT16 - 4, // STBIR_TYPE_UINT32 - 4, // STBIR_TYPE_FLOAT -}; - -// Kernel function centered at 0 -typedef float (stbir__kernel_fn)(float x, float scale); -typedef float (stbir__support_fn)(float scale); - -typedef struct -{ - stbir__kernel_fn* kernel; - stbir__support_fn* support; -} stbir__filter_info; - -// When upsampling, the contributors are which source pixels contribute. -// When downsampling, the contributors are which destination pixels are contributed to. -typedef struct -{ - int n0; // First contributing pixel - int n1; // Last contributing pixel -} stbir__contributors; - -typedef struct -{ - const void* input_data; - int input_w; - int input_h; - int input_stride_bytes; - - void* output_data; - int output_w; - int output_h; - int output_stride_bytes; - - float s0, t0, s1, t1; - - float horizontal_shift; // Units: output pixels - float vertical_shift; // Units: output pixels - float horizontal_scale; - float vertical_scale; - - int channels; - int alpha_channel; - stbir_uint32 flags; - stbir_datatype type; - stbir_filter horizontal_filter; - stbir_filter vertical_filter; - stbir_edge edge_horizontal; - stbir_edge edge_vertical; - stbir_colorspace colorspace; - - stbir__contributors* horizontal_contributors; - float* horizontal_coefficients; - - stbir__contributors* vertical_contributors; - float* vertical_coefficients; - - int decode_buffer_pixels; - float* decode_buffer; - - float* horizontal_buffer; - - // cache these because ceil/floor are inexplicably showing up in profile - int horizontal_coefficient_width; - int vertical_coefficient_width; - int horizontal_filter_pixel_width; - int vertical_filter_pixel_width; - int horizontal_filter_pixel_margin; - int vertical_filter_pixel_margin; - int horizontal_num_contributors; - int vertical_num_contributors; - - int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) - int ring_buffer_num_entries; // Total number of entries in the ring buffer. - int ring_buffer_first_scanline; - int ring_buffer_last_scanline; - int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer - float* ring_buffer; - - float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. - - int horizontal_contributors_size; - int horizontal_coefficients_size; - int vertical_contributors_size; - int vertical_coefficients_size; - int decode_buffer_size; - int horizontal_buffer_size; - int ring_buffer_size; - int encode_buffer_size; -} stbir__info; - - -static const float stbir__max_uint8_as_float = 255.0f; -static const float stbir__max_uint16_as_float = 65535.0f; -static const double stbir__max_uint32_as_float = 4294967295.0; - - -static stbir__inline int stbir__min(int a, int b) -{ - return a < b ? a : b; -} - -static stbir__inline float stbir__saturate(float x) -{ - if (x < 0) - return 0; - - if (x > 1) - return 1; - - return x; -} - -#ifdef STBIR_SATURATE_INT -static stbir__inline stbir_uint8 stbir__saturate8(int x) -{ - if ((unsigned int) x <= 255) - return x; - - if (x < 0) - return 0; - - return 255; -} - -static stbir__inline stbir_uint16 stbir__saturate16(int x) -{ - if ((unsigned int) x <= 65535) - return x; - - if (x < 0) - return 0; - - return 65535; -} -#endif - -static float stbir__srgb_uchar_to_linear_float[256] = { - 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, - 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, - 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, - 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, - 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, - 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, - 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, - 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, - 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, - 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, - 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, - 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, - 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, - 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, - 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, - 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, - 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, - 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, - 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, - 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, - 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, - 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, - 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, - 0.982251f, 0.991102f, 1.0f -}; - -static float stbir__srgb_to_linear(float f) -{ - if (f <= 0.04045f) - return f / 12.92f; - else - return (float)pow((f + 0.055f) / 1.055f, 2.4f); -} - -static float stbir__linear_to_srgb(float f) -{ - if (f <= 0.0031308f) - return f * 12.92f; - else - return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; -} - -#ifndef STBIR_NON_IEEE_FLOAT -// From https://gist.github.com/rygorous/2203834 - -typedef union -{ - stbir_uint32 u; - float f; -} stbir__FP32; - -static const stbir_uint32 fp32_to_srgb8_tab4[104] = { - 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, - 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, - 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, - 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, - 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, - 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, - 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, - 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, - 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, - 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, - 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, - 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, - 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, -}; - -static stbir_uint8 stbir__linear_to_srgb_uchar(float in) -{ - static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps - static const stbir__FP32 minval = { (127-13) << 23 }; - stbir_uint32 tab,bias,scale,t; - stbir__FP32 f; - - // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. - // The tests are carefully written so that NaNs map to 0, same as in the reference - // implementation. - if (!(in > minval.f)) // written this way to catch NaNs - in = minval.f; - if (in > almostone.f) - in = almostone.f; - - // Do the table lookup and unpack bias, scale - f.f = in; - tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; - bias = (tab >> 16) << 9; - scale = tab & 0xffff; - - // Grab next-highest mantissa bits and perform linear interpolation - t = (f.u >> 12) & 0xff; - return (unsigned char) ((bias + scale*t) >> 16); -} - -#else -// sRGB transition values, scaled by 1<<28 -static int stbir__srgb_offset_to_linear_scaled[256] = -{ - 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, - 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, - 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, - 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, - 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, - 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, - 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, - 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, - 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, - 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, - 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, - 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, - 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, - 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, - 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, - 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, - 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, - 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, - 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, - 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, - 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, - 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, - 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, - 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, - 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, - 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, - 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, - 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, - 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, - 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, - 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, - 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, -}; - -static stbir_uint8 stbir__linear_to_srgb_uchar(float f) -{ - int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp - int v = 0; - int i; - - // Refine the guess with a short binary search. - i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - - return (stbir_uint8) v; -} -#endif - -static float stbir__filter_trapezoid(float x, float scale) -{ - float halfscale = scale / 2; - float t = 0.5f + halfscale; - STBIR_ASSERT(scale <= 1); - - x = (float)fabs(x); - - if (x >= t) - return 0; - else - { - float r = 0.5f - halfscale; - if (x <= r) - return 1; - else - return (t - x) / scale; - } -} - -static float stbir__support_trapezoid(float scale) -{ - STBIR_ASSERT(scale <= 1); - return 0.5f + scale / 2; -} - -static float stbir__filter_triangle(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x <= 1.0f) - return 1 - x; - else - return 0; -} - -static float stbir__filter_cubic(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x < 1.0f) - return (4 + x*x*(3*x - 6))/6; - else if (x < 2.0f) - return (8 + x*(-12 + x*(6 - x)))/6; - - return (0.0f); -} - -static float stbir__filter_catmullrom(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x < 1.0f) - return 1 - x*x*(2.5f - 1.5f*x); - else if (x < 2.0f) - return 2 - x*(4 + x*(0.5f*x - 2.5f)); - - return (0.0f); -} - -static float stbir__filter_mitchell(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x < 1.0f) - return (16 + x*x*(21 * x - 36))/18; - else if (x < 2.0f) - return (32 + x*(-60 + x*(36 - 7*x)))/18; - - return (0.0f); -} - -static float stbir__support_zero(float s) -{ - STBIR__UNUSED_PARAM(s); - return 0; -} - -static float stbir__support_one(float s) -{ - STBIR__UNUSED_PARAM(s); - return 1; -} - -static float stbir__support_two(float s) -{ - STBIR__UNUSED_PARAM(s); - return 2; -} - -static stbir__filter_info stbir__filter_info_table[] = { - { NULL, stbir__support_zero }, - { stbir__filter_trapezoid, stbir__support_trapezoid }, - { stbir__filter_triangle, stbir__support_one }, - { stbir__filter_cubic, stbir__support_two }, - { stbir__filter_catmullrom, stbir__support_two }, - { stbir__filter_mitchell, stbir__support_two }, -}; - -stbir__inline static int stbir__use_upsampling(float ratio) -{ - return ratio > 1; -} - -stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info) -{ - return stbir__use_upsampling(stbir_info->horizontal_scale); -} - -stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info) -{ - return stbir__use_upsampling(stbir_info->vertical_scale); -} - -// This is the maximum number of input samples that can affect an output sample -// with the given filter -static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) -{ - STBIR_ASSERT(filter != 0); - STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); - - if (stbir__use_upsampling(scale)) - return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); - else - return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); -} - -// This is how much to expand buffers to account for filters seeking outside -// the image boundaries. -static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) -{ - return stbir__get_filter_pixel_width(filter, scale) / 2; -} - -static int stbir__get_coefficient_width(stbir_filter filter, float scale) -{ - if (stbir__use_upsampling(scale)) - return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); - else - return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); -} - -static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) -{ - if (stbir__use_upsampling(scale)) - return output_size; - else - return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); -} - -static int stbir__get_total_horizontal_coefficients(stbir__info* info) -{ - return info->horizontal_num_contributors - * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); -} - -static int stbir__get_total_vertical_coefficients(stbir__info* info) -{ - return info->vertical_num_contributors - * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); -} - -static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) -{ - return &contributors[n]; -} - -// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, -// if you change it here change it there too. -static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) -{ - int width = stbir__get_coefficient_width(filter, scale); - return &coefficients[width*n + c]; -} - -static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) -{ - switch (edge) - { - case STBIR_EDGE_ZERO: - return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later - - case STBIR_EDGE_CLAMP: - if (n < 0) - return 0; - - if (n >= max) - return max - 1; - - return n; // NOTREACHED - - case STBIR_EDGE_REFLECT: - { - if (n < 0) - { - if (n < max) - return -n; - else - return max - 1; - } - - if (n >= max) - { - int max2 = max * 2; - if (n >= max2) - return 0; - else - return max2 - n - 1; - } - - return n; // NOTREACHED - } - - case STBIR_EDGE_WRAP: - if (n >= 0) - return (n % max); - else - { - int m = (-n) % max; - - if (m != 0) - m = max - m; - - return (m); - } - // NOTREACHED - - default: - STBIR_ASSERT(!"Unimplemented edge type"); - return 0; - } -} - -stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) -{ - // avoid per-pixel switch - if (n >= 0 && n < max) - return n; - return stbir__edge_wrap_slow(edge, n, max); -} - -// What input pixels contribute to this output pixel? -static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) -{ - float out_pixel_center = (float)n + 0.5f; - float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; - float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; - - float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; - float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; - - *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; - *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); - *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); -} - -// What output pixels does this input pixel contribute to? -static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) -{ - float in_pixel_center = (float)n + 0.5f; - float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; - float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; - - float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; - float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; - - *out_center_of_in = in_pixel_center * scale_ratio - out_shift; - *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); - *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); -} - -static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) -{ - int i; - float total_filter = 0; - float filter_scale; - - STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. - - contributor->n0 = in_first_pixel; - contributor->n1 = in_last_pixel; - - STBIR_ASSERT(contributor->n1 >= contributor->n0); - - for (i = 0; i <= in_last_pixel - in_first_pixel; i++) - { - float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; - coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); - - // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) - if (i == 0 && !coefficient_group[i]) - { - contributor->n0 = ++in_first_pixel; - i--; - continue; - } - - total_filter += coefficient_group[i]; - } - - // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be. - // It would be true in exact math but is at best approximately true in floating-point math, - // and it would not make sense to try and put actual bounds on this here because it depends - // on the image aspect ratio which can get pretty extreme. - //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); - - STBIR_ASSERT(total_filter > 0.9); - STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. - - // Make sure the sum of all coefficients is 1. - filter_scale = 1 / total_filter; - - for (i = 0; i <= in_last_pixel - in_first_pixel; i++) - coefficient_group[i] *= filter_scale; - - for (i = in_last_pixel - in_first_pixel; i >= 0; i--) - { - if (coefficient_group[i]) - break; - - // This line has no weight. We can skip it. - contributor->n1 = contributor->n0 + i - 1; - } -} - -static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) -{ - int i; - - STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. - - contributor->n0 = out_first_pixel; - contributor->n1 = out_last_pixel; - - STBIR_ASSERT(contributor->n1 >= contributor->n0); - - for (i = 0; i <= out_last_pixel - out_first_pixel; i++) - { - float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; - float x = out_pixel_center - out_center_of_in; - coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; - } - - // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be. - // It would be true in exact math but is at best approximately true in floating-point math, - // and it would not make sense to try and put actual bounds on this here because it depends - // on the image aspect ratio which can get pretty extreme. - //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); - - for (i = out_last_pixel - out_first_pixel; i >= 0; i--) - { - if (coefficient_group[i]) - break; - - // This line has no weight. We can skip it. - contributor->n1 = contributor->n0 + i - 1; - } -} - -static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) -{ - int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); - int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); - int i, j; - int skip; - - for (i = 0; i < output_size; i++) - { - float scale; - float total = 0; - - for (j = 0; j < num_contributors; j++) - { - if (i >= contributors[j].n0 && i <= contributors[j].n1) - { - float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); - total += coefficient; - } - else if (i < contributors[j].n0) - break; - } - - STBIR_ASSERT(total > 0.9f); - STBIR_ASSERT(total < 1.1f); - - scale = 1 / total; - - for (j = 0; j < num_contributors; j++) - { - if (i >= contributors[j].n0 && i <= contributors[j].n1) - *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; - else if (i < contributors[j].n0) - break; - } - } - - // Optimize: Skip zero coefficients and contributions outside of image bounds. - // Do this after normalizing because normalization depends on the n0/n1 values. - for (j = 0; j < num_contributors; j++) - { - int range, max, width; - - skip = 0; - while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) - skip++; - - contributors[j].n0 += skip; - - while (contributors[j].n0 < 0) - { - contributors[j].n0++; - skip++; - } - - range = contributors[j].n1 - contributors[j].n0 + 1; - max = stbir__min(num_coefficients, range); - - width = stbir__get_coefficient_width(filter, scale_ratio); - for (i = 0; i < max; i++) - { - if (i + skip >= width) - break; - - *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); - } - - continue; - } - - // Using min to avoid writing into invalid pixels. - for (i = 0; i < num_contributors; i++) - contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); -} - -// Each scan line uses the same kernel values so we should calculate the kernel -// values once and then we can use them for every scan line. -static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) -{ - int n; - int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); - - if (stbir__use_upsampling(scale_ratio)) - { - float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; - - // Looping through out pixels - for (n = 0; n < total_contributors; n++) - { - float in_center_of_out; // Center of the current out pixel in the in pixel space - int in_first_pixel, in_last_pixel; - - stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); - - stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); - } - } - else - { - float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; - - // Looping through in pixels - for (n = 0; n < total_contributors; n++) - { - float out_center_of_in; // Center of the current out pixel in the in pixel space - int out_first_pixel, out_last_pixel; - int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); - - stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); - - stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); - } - - stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); - } -} - -static float* stbir__get_decode_buffer(stbir__info* stbir_info) -{ - // The 0 index of the decode buffer starts after the margin. This makes - // it okay to use negative indexes on the decode buffer. - return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; -} - -#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace)) - -static void stbir__decode_scanline(stbir__info* stbir_info, int n) -{ - int c; - int channels = stbir_info->channels; - int alpha_channel = stbir_info->alpha_channel; - int type = stbir_info->type; - int colorspace = stbir_info->colorspace; - int input_w = stbir_info->input_w; - size_t input_stride_bytes = stbir_info->input_stride_bytes; - float* decode_buffer = stbir__get_decode_buffer(stbir_info); - stbir_edge edge_horizontal = stbir_info->edge_horizontal; - stbir_edge edge_vertical = stbir_info->edge_vertical; - size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; - const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; - int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; - int decode = STBIR__DECODE(type, colorspace); - - int x = -stbir_info->horizontal_filter_pixel_margin; - - // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, - // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO - if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) - { - for (; x < max_x; x++) - for (c = 0; c < channels; c++) - decode_buffer[x*channels + c] = 0; - return; - } - - switch (decode) - { - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; - } - - break; - - default: - STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); - break; - } - - if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) - { - for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) - { - int decode_pixel_index = x * channels; - - // If the alpha value is 0 it will clobber the color values. Make sure it's not. - float alpha = decode_buffer[decode_pixel_index + alpha_channel]; -#ifndef STBIR_NO_ALPHA_EPSILON - if (stbir_info->type != STBIR_TYPE_FLOAT) { - alpha += STBIR_ALPHA_EPSILON; - decode_buffer[decode_pixel_index + alpha_channel] = alpha; - } -#endif - for (c = 0; c < channels; c++) - { - if (c == alpha_channel) - continue; - - decode_buffer[decode_pixel_index + c] *= alpha; - } - } - } - - if (edge_horizontal == STBIR_EDGE_ZERO) - { - for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) - { - for (c = 0; c < channels; c++) - decode_buffer[x*channels + c] = 0; - } - for (x = input_w; x < max_x; x++) - { - for (c = 0; c < channels; c++) - decode_buffer[x*channels + c] = 0; - } - } -} - -static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) -{ - return &ring_buffer[index * ring_buffer_length]; -} - -static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n) -{ - int ring_buffer_index; - float* ring_buffer; - - stbir_info->ring_buffer_last_scanline = n; - - if (stbir_info->ring_buffer_begin_index < 0) - { - ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; - stbir_info->ring_buffer_first_scanline = n; - } - else - { - ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; - STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); - } - - ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); - memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); - - return ring_buffer; -} - - -static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer) -{ - int x, k; - int output_w = stbir_info->output_w; - int channels = stbir_info->channels; - float* decode_buffer = stbir__get_decode_buffer(stbir_info); - stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; - float* horizontal_coefficients = stbir_info->horizontal_coefficients; - int coefficient_width = stbir_info->horizontal_coefficient_width; - - for (x = 0; x < output_w; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int out_pixel_index = x * channels; - int coefficient_group = coefficient_width * x; - int coefficient_counter = 0; - - STBIR_ASSERT(n1 >= n0); - STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); - STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); - STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); - STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); - - switch (channels) { - case 1: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 1; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - } - break; - case 2: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 2; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - } - break; - case 3: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 3; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - } - break; - case 4: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 4; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; - } - break; - default: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * channels; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - int c; - STBIR_ASSERT(coefficient != 0); - for (c = 0; c < channels; c++) - output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; - } - break; - } - } -} - -static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer) -{ - int x, k; - int input_w = stbir_info->input_w; - int channels = stbir_info->channels; - float* decode_buffer = stbir__get_decode_buffer(stbir_info); - stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; - float* horizontal_coefficients = stbir_info->horizontal_coefficients; - int coefficient_width = stbir_info->horizontal_coefficient_width; - int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; - int max_x = input_w + filter_pixel_margin * 2; - - STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); - - switch (channels) { - case 1: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 1; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 1; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - } - } - break; - - case 2: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 2; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 2; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - } - } - break; - - case 3: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 3; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 3; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - } - } - break; - - case 4: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 4; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 4; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; - } - } - break; - - default: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * channels; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int c; - int out_pixel_index = k * channels; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - for (c = 0; c < channels; c++) - output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; - } - } - break; - } -} - -static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n) -{ - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline(stbir_info, n); - - // Now resample it into the ring buffer. - if (stbir__use_width_upsampling(stbir_info)) - stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); - else - stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); - - // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. -} - -static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n) -{ - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline(stbir_info, n); - - memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); - - // Now resample it into the horizontal buffer. - if (stbir__use_width_upsampling(stbir_info)) - stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); - else - stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); - - // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. -} - -// Get the specified scan line from the ring buffer. -static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) -{ - int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; - return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); -} - - -static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) -{ - int x; - int n; - int num_nonalpha; - stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) - { - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - float alpha = encode_buffer[pixel_index + alpha_channel]; - float reciprocal_alpha = alpha ? 1.0f / alpha : 0; - - // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb - for (n = 0; n < channels; n++) - if (n != alpha_channel) - encode_buffer[pixel_index + n] *= reciprocal_alpha; - - // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. - // Because we only add it for integer types, it will automatically be discarded on integer - // conversion, so we don't need to subtract it back out (which would be problematic for - // numeric precision reasons). - } - } - - // build a table of all channels that need colorspace correction, so - // we don't perform colorspace correction on channels that don't need it. - for (x = 0, num_nonalpha = 0; x < channels; ++x) - { - if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) - { - nonalpha[num_nonalpha++] = (stbir_uint16)x; - } - } - - #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) - #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) - - #ifdef STBIR__SATURATE_INT - #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) - #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) - #else - #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) - #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) - #endif - - switch (decode) - { - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); - } - - if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); - } - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); - } - - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); - } - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((float*)output_buffer)[index] = encode_buffer[index]; - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]); - } - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel]; - } - break; - - default: - STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); - break; - } -} - -static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n) -{ - int x, k; - int output_w = stbir_info->output_w; - stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; - float* vertical_coefficients = stbir_info->vertical_coefficients; - int channels = stbir_info->channels; - int alpha_channel = stbir_info->alpha_channel; - int type = stbir_info->type; - int colorspace = stbir_info->colorspace; - int ring_buffer_entries = stbir_info->ring_buffer_num_entries; - void* output_data = stbir_info->output_data; - float* encode_buffer = stbir_info->encode_buffer; - int decode = STBIR__DECODE(type, colorspace); - int coefficient_width = stbir_info->vertical_coefficient_width; - int coefficient_counter; - int contributor = n; - - float* ring_buffer = stbir_info->ring_buffer; - int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; - int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; - int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); - - int n0,n1, output_row_start; - int coefficient_group = coefficient_width * contributor; - - n0 = vertical_contributors[contributor].n0; - n1 = vertical_contributors[contributor].n1; - - output_row_start = n * stbir_info->output_stride_bytes; - - STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); - - memset(encode_buffer, 0, output_w * sizeof(float) * channels); - - // I tried reblocking this for better cache usage of encode_buffer - // (using x_outer, k, x_inner), but it lost speed. -- stb - - coefficient_counter = 0; - switch (channels) { - case 1: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 1; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - } - } - break; - case 2: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 2; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; - } - } - break; - case 3: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 3; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; - encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; - } - } - break; - case 4: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 4; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; - encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; - encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; - } - } - break; - default: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * channels; - int c; - for (c = 0; c < channels; c++) - encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; - } - } - break; - } - stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); -} - -static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n) -{ - int x, k; - int output_w = stbir_info->output_w; - stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; - float* vertical_coefficients = stbir_info->vertical_coefficients; - int channels = stbir_info->channels; - int ring_buffer_entries = stbir_info->ring_buffer_num_entries; - float* horizontal_buffer = stbir_info->horizontal_buffer; - int coefficient_width = stbir_info->vertical_coefficient_width; - int contributor = n + stbir_info->vertical_filter_pixel_margin; - - float* ring_buffer = stbir_info->ring_buffer; - int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; - int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; - int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); - int n0,n1; - - n0 = vertical_contributors[contributor].n0; - n1 = vertical_contributors[contributor].n1; - - STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); - - for (k = n0; k <= n1; k++) - { - int coefficient_index = k - n0; - int coefficient_group = coefficient_width * contributor; - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - - switch (channels) { - case 1: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 1; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - } - break; - case 2: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 2; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; - } - break; - case 3: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 3; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; - ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; - } - break; - case 4: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 4; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; - ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; - ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; - } - break; - default: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * channels; - - int c; - for (c = 0; c < channels; c++) - ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; - } - break; - } - } -} - -static void stbir__buffer_loop_upsample(stbir__info* stbir_info) -{ - int y; - float scale_ratio = stbir_info->vertical_scale; - float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; - - STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); - - for (y = 0; y < stbir_info->output_h; y++) - { - float in_center_of_out = 0; // Center of the current out scanline in the in scanline space - int in_first_scanline = 0, in_last_scanline = 0; - - stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); - - STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); - - if (stbir_info->ring_buffer_begin_index >= 0) - { - // Get rid of whatever we don't need anymore. - while (in_first_scanline > stbir_info->ring_buffer_first_scanline) - { - if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) - { - // We just popped the last scanline off the ring buffer. - // Reset it to the empty state. - stbir_info->ring_buffer_begin_index = -1; - stbir_info->ring_buffer_first_scanline = 0; - stbir_info->ring_buffer_last_scanline = 0; - break; - } - else - { - stbir_info->ring_buffer_first_scanline++; - stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; - } - } - } - - // Load in new ones. - if (stbir_info->ring_buffer_begin_index < 0) - stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); - - while (in_last_scanline > stbir_info->ring_buffer_last_scanline) - stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); - - // Now all buffers should be ready to write a row of vertical sampling. - stbir__resample_vertical_upsample(stbir_info, y); - - STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); - } -} - -static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline) -{ - int output_stride_bytes = stbir_info->output_stride_bytes; - int channels = stbir_info->channels; - int alpha_channel = stbir_info->alpha_channel; - int type = stbir_info->type; - int colorspace = stbir_info->colorspace; - int output_w = stbir_info->output_w; - void* output_data = stbir_info->output_data; - int decode = STBIR__DECODE(type, colorspace); - - float* ring_buffer = stbir_info->ring_buffer; - int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); - - if (stbir_info->ring_buffer_begin_index >= 0) - { - // Get rid of whatever we don't need anymore. - while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) - { - if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) - { - int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; - float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); - stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); - STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); - } - - if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) - { - // We just popped the last scanline off the ring buffer. - // Reset it to the empty state. - stbir_info->ring_buffer_begin_index = -1; - stbir_info->ring_buffer_first_scanline = 0; - stbir_info->ring_buffer_last_scanline = 0; - break; - } - else - { - stbir_info->ring_buffer_first_scanline++; - stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; - } - } - } -} - -static void stbir__buffer_loop_downsample(stbir__info* stbir_info) -{ - int y; - float scale_ratio = stbir_info->vertical_scale; - int output_h = stbir_info->output_h; - float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; - int pixel_margin = stbir_info->vertical_filter_pixel_margin; - int max_y = stbir_info->input_h + pixel_margin; - - STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); - - for (y = -pixel_margin; y < max_y; y++) - { - float out_center_of_in; // Center of the current out scanline in the in scanline space - int out_first_scanline, out_last_scanline; - - stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); - - STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); - - if (out_last_scanline < 0 || out_first_scanline >= output_h) - continue; - - stbir__empty_ring_buffer(stbir_info, out_first_scanline); - - stbir__decode_and_resample_downsample(stbir_info, y); - - // Load in new ones. - if (stbir_info->ring_buffer_begin_index < 0) - stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); - - while (out_last_scanline > stbir_info->ring_buffer_last_scanline) - stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); - - // Now the horizontal buffer is ready to write to all ring buffer rows. - stbir__resample_vertical_downsample(stbir_info, y); - } - - stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); -} - -static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) -{ - info->input_w = input_w; - info->input_h = input_h; - info->output_w = output_w; - info->output_h = output_h; - info->channels = channels; -} - -static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform) -{ - info->s0 = s0; - info->t0 = t0; - info->s1 = s1; - info->t1 = t1; - - if (transform) - { - info->horizontal_scale = transform[0]; - info->vertical_scale = transform[1]; - info->horizontal_shift = transform[2]; - info->vertical_shift = transform[3]; - } - else - { - info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); - info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); - - info->horizontal_shift = s0 * info->output_w / (s1 - s0); - info->vertical_shift = t0 * info->output_h / (t1 - t0); - } -} - -static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter) -{ - if (h_filter == 0) - h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; - if (v_filter == 0) - v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; - info->horizontal_filter = h_filter; - info->vertical_filter = v_filter; -} - -static stbir_uint32 stbir__calculate_memory(stbir__info *info) -{ - int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); - int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); - - info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); - info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); - - // One extra entry because floating point precision problems sometimes cause an extra to be necessary. - info->ring_buffer_num_entries = filter_height + 1; - - info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); - info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); - info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); - info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); - info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); - info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); - info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); - info->encode_buffer_size = info->output_w * info->channels * sizeof(float); - - STBIR_ASSERT(info->horizontal_filter != 0); - STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late - STBIR_ASSERT(info->vertical_filter != 0); - STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late - - if (stbir__use_height_upsampling(info)) - // The horizontal buffer is for when we're downsampling the height and we - // can't output the result of sampling the decode buffer directly into the - // ring buffers. - info->horizontal_buffer_size = 0; - else - // The encode buffer is to retain precision in the height upsampling method - // and isn't used when height downsampling. - info->encode_buffer_size = 0; - - return info->horizontal_contributors_size + info->horizontal_coefficients_size - + info->vertical_contributors_size + info->vertical_coefficients_size - + info->decode_buffer_size + info->horizontal_buffer_size - + info->ring_buffer_size + info->encode_buffer_size; -} - -static int stbir__resize_allocated(stbir__info *info, - const void* input_data, int input_stride_in_bytes, - void* output_data, int output_stride_in_bytes, - int alpha_channel, stbir_uint32 flags, stbir_datatype type, - stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, - void* tempmem, size_t tempmem_size_in_bytes) -{ - size_t memory_required = stbir__calculate_memory(info); - - int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; - int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; - -#ifdef STBIR_DEBUG_OVERWRITE_TEST -#define OVERWRITE_ARRAY_SIZE 8 - unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; - unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; - unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; - unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; - - size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; - memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); - memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); - memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); - memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); -#endif - - STBIR_ASSERT(info->channels >= 0); - STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); - - if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) - return 0; - - STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); - STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); - - if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) - return 0; - if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) - return 0; - - if (alpha_channel < 0) - flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; - - if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { - STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); - } - - if (alpha_channel >= info->channels) - return 0; - - STBIR_ASSERT(tempmem); - - if (!tempmem) - return 0; - - STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); - - if (tempmem_size_in_bytes < memory_required) - return 0; - - memset(tempmem, 0, tempmem_size_in_bytes); - - info->input_data = input_data; - info->input_stride_bytes = width_stride_input; - - info->output_data = output_data; - info->output_stride_bytes = width_stride_output; - - info->alpha_channel = alpha_channel; - info->flags = flags; - info->type = type; - info->edge_horizontal = edge_horizontal; - info->edge_vertical = edge_vertical; - info->colorspace = colorspace; - - info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); - info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); - info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); - info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); - info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); - info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); - - info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); - info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; - -#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) - - info->horizontal_contributors = (stbir__contributors *) tempmem; - info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); - info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); - info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); - info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); - - if (stbir__use_height_upsampling(info)) - { - info->horizontal_buffer = NULL; - info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); - info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); - - STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); - } - else - { - info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); - info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); - info->encode_buffer = NULL; - - STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); - } - -#undef STBIR__NEXT_MEMPTR - - // This signals that the ring buffer is empty - info->ring_buffer_begin_index = -1; - - stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); - stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); - - STBIR_PROGRESS_REPORT(0); - - if (stbir__use_height_upsampling(info)) - stbir__buffer_loop_upsample(info); - else - stbir__buffer_loop_downsample(info); - - STBIR_PROGRESS_REPORT(1); - -#ifdef STBIR_DEBUG_OVERWRITE_TEST - STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); - STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); - STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); - STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); -#endif - - return 1; -} - - -static int stbir__resize_arbitrary( - void *alloc_context, - const void* input_data, int input_w, int input_h, int input_stride_in_bytes, - void* output_data, int output_w, int output_h, int output_stride_in_bytes, - float s0, float t0, float s1, float t1, float *transform, - int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, - stbir_filter h_filter, stbir_filter v_filter, - stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) -{ - stbir__info info; - int result; - size_t memory_required; - void* extra_memory; - - stbir__setup(&info, input_w, input_h, output_w, output_h, channels); - stbir__calculate_transform(&info, s0,t0,s1,t1,transform); - stbir__choose_filter(&info, h_filter, v_filter); - memory_required = stbir__calculate_memory(&info); - extra_memory = STBIR_MALLOC(memory_required, alloc_context); - - if (!extra_memory) - return 0; - - result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, - output_data, output_stride_in_bytes, - alpha_channel, flags, type, - edge_horizontal, edge_vertical, - colorspace, extra_memory, memory_required); - - STBIR_FREE(extra_memory, alloc_context); - - return result; -} - -STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); -} - -STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); -} - -STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); -} - -STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); -} - -STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, - edge_wrap_mode, edge_wrap_mode, space); -} - -STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, - edge_wrap_mode, edge_wrap_mode, space); -} - - -STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, - edge_wrap_mode, edge_wrap_mode, space); -} - - -STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, - edge_mode_horizontal, edge_mode_vertical, space); -} - - -STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float x_scale, float y_scale, - float x_offset, float y_offset) -{ - float transform[4]; - transform[0] = x_scale; - transform[1] = y_scale; - transform[2] = x_offset; - transform[3] = y_offset; - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, - edge_mode_horizontal, edge_mode_vertical, space); -} - -STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float s0, float t0, float s1, float t1) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, - edge_mode_horizontal, edge_mode_vertical, space); -} - -#endif // STB_IMAGE_RESIZE_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ diff --git a/source/engine/thirdparty/stb/deprecated/stretch_test.c b/source/engine/thirdparty/stb/deprecated/stretch_test.c deleted file mode 100644 index 772237c..0000000 --- a/source/engine/thirdparty/stb/deprecated/stretch_test.c +++ /dev/null @@ -1,29 +0,0 @@ -// check that stb_truetype compiles with no stb_rect_pack.h -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" - -#define STB_DS_IMPLEMENTATION -#include "stb_ds.h" -#include - -int main(int arg, char **argv) -{ - int i; - int *arr = NULL; - - for (i=0; i < 1000000; ++i) - arrput(arr, i); - - assert(arrlen(arr) == 1000000); - for (i=0; i < 1000000; ++i) - assert(arr[i] == i); - - arrfree(arr); - arr = NULL; - - for (i=0; i < 1000; ++i) - arrput(arr, 1000); - assert(arrlen(arr) == 1000000); - - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/deprecated/stretchy_buffer.h b/source/engine/thirdparty/stb/deprecated/stretchy_buffer.h deleted file mode 100644 index c0880ff..0000000 --- a/source/engine/thirdparty/stb/deprecated/stretchy_buffer.h +++ /dev/null @@ -1,263 +0,0 @@ -// stretchy_buffer.h - v1.04 - public domain - nothings.org/stb -// a vector<>-like dynamic array for C -// -// version history: -// 1.04 - fix warning -// 1.03 - compile as C++ maybe -// 1.02 - tweaks to syntax for no good reason -// 1.01 - added a "common uses" documentation section -// 1.0 - fixed bug in the version I posted prematurely -// 0.9 - rewrite to try to avoid strict-aliasing optimization -// issues, but won't compile as C++ -// -// Will probably not work correctly with strict-aliasing optimizations. -// -// The idea: -// -// This implements an approximation to C++ vector<> for C, in that it -// provides a generic definition for dynamic arrays which you can -// still access in a typesafe way using arr[i] or *(arr+i). However, -// it is simply a convenience wrapper around the common idiom of -// of keeping a set of variables (in a struct or globals) which store -// - pointer to array -// - the length of the "in-use" part of the array -// - the current size of the allocated array -// -// I find it to be the single most useful non-built-in-structure when -// programming in C (hash tables a close second), but to be clear -// it lacks many of the capabilities of C++ vector<>: there is no -// range checking, the object address isn't stable (see next section -// for details), the set of methods available is small (although -// the file stb.h has another implementation of stretchy buffers -// called 'stb_arr' which provides more methods, e.g. for insertion -// and deletion). -// -// How to use: -// -// Unlike other stb header file libraries, there is no need to -// define an _IMPLEMENTATION symbol. Every #include creates as -// much implementation is needed. -// -// stretchy_buffer.h does not define any types, so you do not -// need to #include it to before defining data types that are -// stretchy buffers, only in files that *manipulate* stretchy -// buffers. -// -// If you want a stretchy buffer aka dynamic array containing -// objects of TYPE, declare such an array as: -// -// TYPE *myarray = NULL; -// -// (There is no typesafe way to distinguish between stretchy -// buffers and regular arrays/pointers; this is necessary to -// make ordinary array indexing work on these objects.) -// -// Unlike C++ vector<>, the stretchy_buffer has the same -// semantics as an object that you manually malloc and realloc. -// The pointer may relocate every time you add a new object -// to it, so you: -// -// 1. can't take long-term pointers to elements of the array -// 2. have to return the pointer from functions which might expand it -// (either as a return value or by storing it to a ptr-to-ptr) -// -// Now you can do the following things with this array: -// -// sb_free(TYPE *a) free the array -// sb_count(TYPE *a) the number of elements in the array -// sb_push(TYPE *a, TYPE v) adds v on the end of the array, a la push_back -// sb_add(TYPE *a, int n) adds n uninitialized elements at end of array & returns pointer to first added -// sb_last(TYPE *a) returns an lvalue of the last item in the array -// a[n] access the nth (counting from 0) element of the array -// -// #define STRETCHY_BUFFER_NO_SHORT_NAMES to only export -// names of the form 'stb_sb_' if you have a name that would -// otherwise collide. -// -// Note that these are all macros and many of them evaluate -// their arguments more than once, so the arguments should -// be side-effect-free. -// -// Note that 'TYPE *a' in sb_push and sb_add must be lvalues -// so that the library can overwrite the existing pointer if -// the object has to be reallocated. -// -// In an out-of-memory condition, the code will try to -// set up a null-pointer or otherwise-invalid-pointer -// exception to happen later. It's possible optimizing -// compilers could detect this write-to-null statically -// and optimize away some of the code, but it should only -// be along the failure path. Nevertheless, for more security -// in the face of such compilers, #define STRETCHY_BUFFER_OUT_OF_MEMORY -// to a statement such as assert(0) or exit(1) or something -// to force a failure when out-of-memory occurs. -// -// Common use: -// -// The main application for this is when building a list of -// things with an unknown quantity, either due to loading from -// a file or through a process which produces an unpredictable -// number. -// -// My most common idiom is something like: -// -// SomeStruct *arr = NULL; -// while (something) -// { -// SomeStruct new_one; -// new_one.whatever = whatever; -// new_one.whatup = whatup; -// new_one.foobar = barfoo; -// sb_push(arr, new_one); -// } -// -// and various closely-related factorings of that. For example, -// you might have several functions to create/init new SomeStructs, -// and if you use the above idiom, you might prefer to make them -// return structs rather than take non-const-pointers-to-structs, -// so you can do things like: -// -// SomeStruct *arr = NULL; -// while (something) -// { -// if (case_A) { -// sb_push(arr, some_func1()); -// } else if (case_B) { -// sb_push(arr, some_func2()); -// } else { -// sb_push(arr, some_func3()); -// } -// } -// -// Note that the above relies on the fact that sb_push doesn't -// evaluate its second argument more than once. The macros do -// evaluate the *array* argument multiple times, and numeric -// arguments may be evaluated multiple times, but you can rely -// on the second argument of sb_push being evaluated only once. -// -// Of course, you don't have to store bare objects in the array; -// if you need the objects to have stable pointers, store an array -// of pointers instead: -// -// SomeStruct **arr = NULL; -// while (something) -// { -// SomeStruct *new_one = malloc(sizeof(*new_one)); -// new_one->whatever = whatever; -// new_one->whatup = whatup; -// new_one->foobar = barfoo; -// sb_push(arr, new_one); -// } -// -// How it works: -// -// A long-standing tradition in things like malloc implementations -// is to store extra data before the beginning of the block returned -// to the user. The stretchy buffer implementation here uses the -// same trick; the current-count and current-allocation-size are -// stored before the beginning of the array returned to the user. -// (This means you can't directly free() the pointer, because the -// allocated pointer is different from the type-safe pointer provided -// to the user.) -// -// The details are trivial and implementation is straightforward; -// the main trick is in realizing in the first place that it's -// possible to do this in a generic, type-safe way in C. -// -// Contributors: -// -// Timothy Wright (github:ZenToad) -// -// LICENSE -// -// See end of file for license information. - -#ifndef STB_STRETCHY_BUFFER_H_INCLUDED -#define STB_STRETCHY_BUFFER_H_INCLUDED - -#ifndef NO_STRETCHY_BUFFER_SHORT_NAMES -#define sb_free stb_sb_free -#define sb_push stb_sb_push -#define sb_count stb_sb_count -#define sb_add stb_sb_add -#define sb_last stb_sb_last -#endif - -#define stb_sb_free(a) ((a) ? free(stb__sbraw(a)),0 : 0) -#define stb_sb_push(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v)) -#define stb_sb_count(a) ((a) ? stb__sbn(a) : 0) -#define stb_sb_add(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)]) -#define stb_sb_last(a) ((a)[stb__sbn(a)-1]) - -#define stb__sbraw(a) ((int *) (void *) (a) - 2) -#define stb__sbm(a) stb__sbraw(a)[0] -#define stb__sbn(a) stb__sbraw(a)[1] - -#define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a)) -#define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0) -#define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a)))) - -#include - -static void * stb__sbgrowf(void *arr, int increment, int itemsize) -{ - int dbl_cur = arr ? 2*stb__sbm(arr) : 0; - int min_needed = stb_sb_count(arr) + increment; - int m = dbl_cur > min_needed ? dbl_cur : min_needed; - int *p = (int *) realloc(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2); - if (p) { - if (!arr) - p[1] = 0; - p[0] = m; - return p+2; - } else { - #ifdef STRETCHY_BUFFER_OUT_OF_MEMORY - STRETCHY_BUFFER_OUT_OF_MEMORY ; - #endif - return (void *) (2*sizeof(int)); // try to force a NULL pointer exception later - } -} -#endif // STB_STRETCHY_BUFFER_H_INCLUDED - - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ diff --git a/source/engine/thirdparty/stb/deprecated/stretchy_buffer.txt b/source/engine/thirdparty/stb/deprecated/stretchy_buffer.txt deleted file mode 100644 index dcd747e..0000000 --- a/source/engine/thirdparty/stb/deprecated/stretchy_buffer.txt +++ /dev/null @@ -1,28 +0,0 @@ -// stretchy buffer // init: NULL // free: sbfree() // push_back: sbpush() // size: sbcount() // -#define sbfree(a) ((a) ? free(stb__sbraw(a)),0 : 0) -#define sbpush(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v)) -#define sbcount(a) ((a) ? stb__sbn(a) : 0) -#define sbadd(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)]) -#define sblast(a) ((a)[stb__sbn(a)-1]) - -#include -#define stb__sbraw(a) ((int *) (a) - 2) -#define stb__sbm(a) stb__sbraw(a)[0] -#define stb__sbn(a) stb__sbraw(a)[1] - -#define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+n >= stb__sbm(a)) -#define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0) -#define stb__sbgrow(a,n) stb__sbgrowf((void **) &(a), (n), sizeof(*(a))) - -static void stb__sbgrowf(void **arr, int increment, int itemsize) -{ - int m = *arr ? 2*stb__sbm(*arr)+increment : increment+1; - void *p = realloc(*arr ? stb__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2); - assert(p); - if (p) { - if (!*arr) ((int *) p)[1] = 0; - *arr = (void *) ((int *) p + 2); - stb__sbm(*arr) = m; - } -} - diff --git a/source/engine/thirdparty/stb/docs/other_libs.md b/source/engine/thirdparty/stb/docs/other_libs.md deleted file mode 100644 index 62f379c..0000000 --- a/source/engine/thirdparty/stb/docs/other_libs.md +++ /dev/null @@ -1 +0,0 @@ -Moved to https://github.com/nothings/single_file_libs \ No newline at end of file diff --git a/source/engine/thirdparty/stb/docs/stb_howto.txt b/source/engine/thirdparty/stb/docs/stb_howto.txt deleted file mode 100644 index a969b54..0000000 --- a/source/engine/thirdparty/stb/docs/stb_howto.txt +++ /dev/null @@ -1,185 +0,0 @@ -Lessons learned about how to make a header-file library -V1.0 -September 2013 Sean Barrett - -Things to do in an stb-style header-file library, -and rationales: - - -1. #define LIBRARYNAME_IMPLEMENTATION - -Use a symbol like the above to control creating -the implementation. (I used a far-less-clear name -in my first header-file library; it became -clear that was a mistake once I had multiple -libraries.) - -Include a "header-file" section with header-file -guards and declarations for all the functions, -but only guard the implementation with LIBRARYNAME_IMPLEMENTATION, -not the header-file guard. That way, if client's -header file X includes your header file for -declarations, they can still include header file X -in the source file that creates the implementation; -if you guard the implementation too, then the first -include (before the #define) creates the declarations, -and the second one (after the #define) does nothing. - - -2. AVOID DEPENDENCIES - -Don't rely on anything other than the C standard libraries. - -(If you're creating a library specifically to leverage/wrap -some other library, then obviously you can rely on that -library. But if that library is public domain, you might -be better off directly embedding the source, to reduce -dependencies for your clients. But of course now you have -to update whenever that library updates.) - -If you use stdlib, consider wrapping all stdlib calls in -macros, and then conditionally define those macros to the -stdlib function, allowing the user to replace them. - -For functions with side effects, like memory allocations, -consider letting the user pass in a context and pass -that in to the macros. (The stdlib versions will ignore -the parameter.) Otherwise, users may have to use global -or thread-local variables to achieve the same effect. - - -3. AVOID MALLOC - -You can't always do this, but when you can, embedded developers -will appreciate it. I almost never bother avoiding, as it's -too much work (and in some cases is pretty infeasible; -see http://nothings.org/gamedev/font_rendering_malloc.txt ). -But it's definitely something one of the things I've gotten -the most pushback on from potential users. - - -4. ALLOW STATIC IMPLEMENTATION - -Have a #define which makes function declarations and -function definitions static. This makes the implementation -private to the source file that creates it. This allows -people to use your library multiple times in their project -without collision. (This is only necessary if your library -has configuration macros or global state, or if your -library has multiple versions that are not backwards -compatible. I've run into both of those cases.) - - -5. MAKE ACCESSIBLE FROM C - -Making your code accessible from C instead of C++ (i.e. -either coding in C, or using extern "C") makes it more -straightforward to be used in C and in other languages, -which often only have support for C bindings, not C++. -(One of the earliest results I found in googling for -stb_image was a Haskell wrapper.) Otherwise, people -have to wrap it in another set of function calls, and -the whole point here is to make it convenient for people -to use, isn't it? (See below.) - -I prefer to code entirely in C, so the source file that -instantiates the implementation can be C itself, for -those crazy people out there who are programming in C. -But it's probably not a big hardship for a C programmer -to create a single C++ source file to instantiate your -library. - - -6. NAMESPACE PRIVATE FUNCTIONS - -Try to avoid having names in your source code that -will cause conflicts with identical names in client -code. You can do this either by namespacing in C++, -or prefixing with your library name in C. - -In C, generally, I use the same prefix for API -functions and private symbols, such as "stbtt_" -for stb_truetype; but private functions (and -static globals) use a second underscore as -in "stbtt__" to further minimize the chance of -additional collisions in the unlikely but not -impossible event that users write wrapper -functions that have names of the form "stbtt_". -(Consider the user that has used "stbtt_foo" -*successfully*, and then upgrades to a new -version of your library which has a new private -function named either "stbtt_foo" or "stbtt__foo".) - -Note that the double-underscore is reserved for -use by the compiler, but (1) there is nothing -reserved for "middleware", i.e. libraries -desiring to avoid conflicts with user symbols -have no other good options, and (2) in practice -no compilers use double-underscore in the middle -rather than the beginning/end. (Unfortunately, -there is at least one videogame-console compiler that -will warn about double-underscores by default.) - - -7. EASY-TO-COMPLY LICENSE - -I make my libraries public domain. You don't have to. -But my goal in releasing stb-style libraries is to -reduce friction for potential users as much as -possible. That means: - - a. easy to build (what this file is mostly about) - b. easy to invoke (which requires good API design) - c. easy to deploy (which is about licensing) - -I choose to place all my libraries in the public -domain, abjuring copyright, rather than license -the libraries. This has some benefits and some -drawbacks. - -Any license which is "viral" to modifications -causes worries for lawyers, even if their programmers -aren't modifying it. - -Any license which requires crediting in documentation -adds friction which can add up. Valve used to have -a page with a list of all of these on their web site, -and it was insane, and obviously nobody ever looked -at it so why would you care whether your credit appeared -there? - -Permissive licenses like zlib and BSD license are -perfectly reasonable, but they are very wordy and -have only two benefits over public domain: legally-mandated -attribution and liability-control. I do not believe these -are worth the excessive verbosity and user-unfriendliness -these licenses induce, especially in the single-file -case where those licenses tend to be at the top of -the file, the first thing you see. (To the specific -points, I have had no trouble receiving attribution -for my libraries; liability in the face of no explicit -disclaimer of liability is an open question.) - -However, public domain has frictions of its own, because -public domain declarations aren't necessary recognized -in the USA and some other locations. For that reason, -I recommend a declaration along these lines: - -// This software is dual-licensed to the public domain and under the following -// license: you are granted a perpetual, irrevocable license to copy, modify, -// publish, and distribute this file as you see fit. - -I typically place this declaration at the end of the initial -comment block of the file and just say 'public domain' -at the top. - -I have had people say they couldn't use one of my -libraries because it was only "public domain" and didn't -have the additional fallback clause, who asked if -I could dual-license it under a traditional license. - -My answer: they can create a derivative work by -modifying one character, and then license that however -they like. (Indeed, *adding* the zlib or BSD license -would be such a modification!) Unfortunately, their -lawyers reportedly didn't like that answer. :( diff --git a/source/engine/thirdparty/stb/docs/stb_voxel_render_interview.md b/source/engine/thirdparty/stb/docs/stb_voxel_render_interview.md deleted file mode 100644 index 7071466..0000000 --- a/source/engine/thirdparty/stb/docs/stb_voxel_render_interview.md +++ /dev/null @@ -1,173 +0,0 @@ -# An interview with STB about stb_voxel_render.h - -**Q:** -I suppose you really like Minecraft? - -**A:** -Not really. I mean, I do own it and play it some, and -I do watch YouTube videos of other people playing it -once in a while, but I'm not saying it's that great. - -But I do love voxels. I've been playing with voxel rendering -since the mid-late 90's when we were still doing software -rendering and thinking maybe polygons weren't the answer. -Once GPUs came along that kind of died off, at least until -Minecraft brought it back to attention. - -**Q:** -Do you expect people will make a lot of Minecraft clones -with this? - -**A:** -I hope not! - -For one thing, it's a terrible idea for the -developer. Remember before Minecraft was on the Xbox 360, -there were a ton of "indie" clones (some maybe making -decent money even), but then the real Minecraft came out -and just crushed them (as far as I know). It's just not -something you really want to compete with. - -The reason I made this library is because I'd like -to see more games with Minecraft's *art style*, not -necessary its *gameplay*. - -I can understand the urge to clone the gameplay. When -you have a world made of voxels/blocks, there are a -few things that become incredibly easy to do that would -otherwise be very hard (at least for an indie) to do in 3D. -One thing is that procedural generation becomes much easier. -Another is that destructible environments are easy. Another -is that you have a world where your average user can build -stuff that they find satisfactory. - -Minecraft is at a sort of local maximum, a sweet spot, where -it leverages all of those easy-to-dos. And so I'm sure it's -hard to look at the space of 'games using voxels' and move -away from that local maximum, to give up some of that. -But I think that's what people should do. - -**Q:** -So what else can people do with stb_voxel_render? - -**A:** -All of those benefits I mentioned above are still valid even -if you stay away from the sweet spot. You can make a 3D roguelike -without player-creation/destruction that uses procedural generation. -You could make a shooter with pre-designed maps but destructible -environments. - -And I'm sure there are other possible benefits to using voxels/blocks. -Hopefully this will make it easier for people to explore the space. - -The library has a pretty wide range of features to allow -people to come up with some distinctive looks. For example, -the art style of Continue?9876543210 was one of the inspirations -for trying to make the multitexturing capabilities flexible. -I'm terrible at art, so this isn't really something I can -come up with myself, but I tried to put in flexible -technology that could be used multiple ways. - -One thing I did intentionally was try to make it possible to -make nicer looking ground terrain, using the half-height -slopes and "weird slopes". There are Minecraft mods with -drivable cars and they just go up these blocky slopes and, -like, what? So I wanted you to be able to make smoother -terrain, either just for the look, or for vehicles etc. -Also, you can spatially cross-fade between two ground textures for -that classic bad dirt/grass transition that has shipped -in plenty of professional games. Of course, you could -just use a separate non-voxel ground renderer for all of -this. But this way, you can seamlessly integrate everything -else with it. E.g. in your authoring tool (or procedural -generation) you can make smooth ground and then cut a -sharp-edged hole in it for a building's basement or whatever. - -Another thing you can do is work at a very different scale. -In Minecraft, a person is just under 2 blocks tall. In -Ace of Spades, a person is just under 3 blocks tall. Why -not 4 or 6? Well, partly because you just need a lot more -voxels; if a meter is 2 voxels in Mineraft and 4 voxels in -your game, and you draw the same number of voxels due to -hardware limits, then your game has half the view distance -of Minecraft. Since stb_voxel_render is designed to keep -the meshes small and render efficiently, you can push the -view distance out further than Minecraft--or use a similar -view distance and a higher voxel resolution. You could also -stop making infinite worlds and work at entirely different -scales; where Minecraft is 1 voxel per meter, you could -have 20 voxels per meter and make a small arena that's -50 meters wide and 5 meters tall. - -Back when the voxel game Voxatron was announced, the weekend -after the trailer came out I wrote my own little GPU-accelerated -version of the engine and thought that was pretty cool. I've -been tempted many times to extract that and release it -as a library, but -I don't want to steal Voxatron's thunder so I've avoided -it. You could use this engine to do the same kind of thing, -although it won't be as efficient as an engine dedicated to -that style of thing would be. - -**Q:** -What one thing would you really like to see somebody do? - -**A:** -Before Unity, 3D has seemed deeply problematic in the indie -space. Software like GameMaker has tried to support 3D but -it seems like little of note has been done with it. - -Minecraft has shown that people can build worlds with the -Minecraft toolset far more easily than we've ever seen from those -other tools. Obviously people have done great things with -Unity, but those people are much closer to professional -developers; typically they still need real 3D modelling -and all of that stuff. - -So what I'd really like to see is someone build some kind -of voxel-game-construction-set. Start with stb_voxel_render, -maybe expose all the flexibility of stb_voxel_render (so -people can do different things). Thrown in lua or something -else for scripting, make some kind of editor that feels -at least as good as Minecraft and Infinifactory, and see -where that gets you. - -**Q:** -Why'd you make this library? - -**A:** -Mainly as a way of releasing this technology I've been working -on since 2011 and seemed unlikely to ever ship myself. In 2011 -I was playing the voxel shooter Ace of Spades. One of the maps -that we played on was a partial port of Broville (which is the -first Minecraft map in stb_voxel_render release trailer). I'd -made a bunch of procedural level generators for the game, and -I started trying to make a city generator inspired by Broville. - -But I realized it would be a lot of work, and of very little -value (most of my maps didn't get much play because people -preferred to play on maps where they could charge straight -at the enemies and shoot them as fast as possible). So I -wrote my own voxel engine and started working on a procedural -city game. But I got bogged down after I finally got the road -generator working and never got anywhere with building -generation or gameplay. - -stb_voxel_render is actually a complete rewrite from scratch, -but it's based a lot on what I learned from that previous work. - -**Q:** -About the release video... how long did that take to edit? - -**A:** -About seven or eight hours. I had the first version done in -maybe six or seven hours, but then I realized I'd left out -one clip, and when I went back to add it I also gussied up -a couple other moments in the video. But there was something -basically identical to it that was done in around six. - -**Q:** -Ok, that's it. Thanks, me. - -**A:** -Thanks *me!* diff --git a/source/engine/thirdparty/stb/docs/why_public_domain.md b/source/engine/thirdparty/stb/docs/why_public_domain.md deleted file mode 100644 index fd3f887..0000000 --- a/source/engine/thirdparty/stb/docs/why_public_domain.md +++ /dev/null @@ -1,117 +0,0 @@ -My collected rationales for placing these libraries -in the public domain: - -1. Public domain vs. viral licenses - - Why is this library public domain? - Because more people will use it. Because it's not viral, people are - not obligated to give back, so you could argue that it hurts the - development of it, and then because it doesn't develop as well it's - not as good, and then because it's not as good, in the long run - maybe fewer people will use it. I have total respect for that - opinion, but I just don't believe it myself for most software. - -2. Public domain vs. attribution-required licenses - - The primary difference between public domain and, say, a Creative Commons - commercial / non-share-alike / attribution license is solely the - requirement for attribution. (Similarly the BSD license and such.) - While I would *appreciate* acknowledgement and attribution, I believe - that it is foolish to place a legal encumberment (i.e. a license) on - the software *solely* to get attribution. - - In other words, I'm arguing that PD is superior to the BSD license and - the Creative Commons 'Attribution' license. If the license offers - anything besides attribution -- as does, e.g., CC NonCommercial-ShareAlike, - or the GPL -- that's a separate discussion. - -3. Other aspects of BSD-style licenses besides attribution - - Permissive licenses like zlib and BSD license are perfectly reasonable - in their requirements, but they are very wordy and - have only two benefits over public domain: legally-mandated - attribution and liability-control. I do not believe these - are worth the excessive verbosity and user-unfriendliness - these licenses induce, especially in the single-file - case where those licenses tend to be at the top of - the file, the first thing you see. - - To the specific points, I have had no trouble receiving - attribution for my libraries; liability in the face of - no explicit disclaimer of liability is an open question, - but one I have a lot of difficulty imagining there being - any actual doubt about in court. Sometimes I explicitly - note in my libraries that I make no guarantees about them - being fit for purpose, but it's pretty absurd to do this; - as a whole, it comes across as "here is a library to decode - vorbis audio files, but it may not actually work and if - you have problems it's not my fault, but also please - report bugs so I can fix them"--so dumb! - -4. full discussion from stb_howto.txt on what YOU should do for YOUR libs - -``` -EASY-TO-COMPLY LICENSE - -I make my libraries public domain. You don't have to. -But my goal in releasing stb-style libraries is to -reduce friction for potential users as much as -possible. That means: - - a. easy to build (what this file is mostly about) - b. easy to invoke (which requires good API design) - c. easy to deploy (which is about licensing) - -I choose to place all my libraries in the public -domain, abjuring copyright, rather than license -the libraries. This has some benefits and some -drawbacks. - -Any license which is "viral" to modifications -causes worries for lawyers, even if their programmers -aren't modifying it. - -Any license which requires crediting in documentation -adds friction which can add up. Valve has a huge list -(http://nothings.org/remote/ThirdPartyLegalNotices_steam_2019.html) -of all of these included in each game they ship, -and it's insane, and obviously nobody ever looks -at it so why would you care whether your credit -appeared there? - -Permissive licenses like zlib and BSD license are -perfectly reasonable, but they are very wordy and -have only two benefits over public domain: legally-mandated -attribution and liability-control. I do not believe these -are worth the excessive verbosity and user-unfriendliness -these licenses induce, especially in the single-file -case where those licenses tend to be at the top of -the file, the first thing you see. (To the specific -points, I have had no trouble receiving attribution -for my libraries; liability in the face of no explicit -disclaimer of liability is an open question.) - -However, public domain has frictions of its own, because -public domain declarations aren't necessary recognized -in the USA and some other locations. For that reason, -I recommend a declaration along these lines: - -// This software is dual-licensed to the public domain and under the following -// license: you are granted a perpetual, irrevocable license to copy, modify, -// publish, and distribute this file as you see fit. - -I typically place this declaration at the end of the initial -comment block of the file and just say 'public domain' -at the top. - -I have had people say they couldn't use one of my -libraries because it was only "public domain" and didn't -have the additional fallback clause, who asked if -I could dual-license it under a traditional license. - -My answer: they can create a derivative work by -modifying one character, and then license that however -they like. (Indeed, *adding* the zlib or BSD license -would be such a modification!) Unfortunately, their -lawyers reportedly didn't like that answer. :( -``` diff --git a/source/engine/thirdparty/stb/stb_image_resize_test/dotimings.c b/source/engine/thirdparty/stb/stb_image_resize_test/dotimings.c deleted file mode 100644 index 515c5d5..0000000 --- a/source/engine/thirdparty/stb/stb_image_resize_test/dotimings.c +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include -#include - -#ifdef _MSC_VER - -#define stop() __debugbreak() -#include -#define int64 __int64 -#pragma warning(disable:4127) - -#define get_milliseconds GetTickCount - -#else - -#define stop() __builtin_trap() -#define int64 long long - -typedef unsigned int U32; -typedef unsigned long long U64; - -#include -static int get_milliseconds() -{ - struct timespec ts; - clock_gettime( CLOCK_MONOTONIC, &ts ); - return (U32) ( ( ((U64)(U32)ts.tv_sec) * 1000LL ) + (U64)(((U32)ts.tv_nsec+500000)/1000000) ); -} - -#endif - -#if defined(TIME_SIMD) - // default for most platforms -#elif defined(TIME_SCALAR) - #define STBIR_NO_SIMD -#else - #error You must define TIME_SIMD or TIME_SCALAR when compiling this file. -#endif - -#define STBIR_PROFILE -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#define STBIR__V_FIRST_INFO_BUFFER v_info -#include "stb_image_resize2.h" // new one! - -#if defined(TIME_SIMD) && !defined(STBIR_SIMD) -#error Timing SIMD, but scalar was ON! -#endif - -#if defined(TIME_SCALAR) && defined(STBIR_SIMD) -#error Timing scalar, but SIMD was ON! -#endif - -#define HEADER 32 - - -static int file_write( const char *filename, void * buffer, size_t size ) -{ - FILE * f = fopen( filename, "wb" ); - if ( f == 0 ) return 0; - if ( fwrite( buffer, 1, size, f) != size ) return 0; - fclose(f); - return 1; -} - -int64 nresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt ) -{ - STBIR_RESIZE resize; - int t; - int64 b; - - stbir_resize_init( &resize, i, ix, iy, ip, o, ox, oy, op, buf, type ); - stbir_set_edgemodes( &resize, edg, edg ); - stbir_set_filters( &resize, flt, flt ); - - stbir_build_samplers_with_splits( &resize, 1 ); - - b = 0x7fffffffffffffffULL; - for( t = 0 ; t < 16 ; t++ ) - { - STBIR_PROFILE_INFO profile; - int64 v; - if(!stbir_resize_extended( &resize ) ) - stop(); - stbir_resize_extended_profile_info( &profile, &resize ); - v = profile.clocks[1]+profile.clocks[2]; - if ( v < b ) - { - b = v; - t = 0; - } - } - - stbir_free_samplers( &resize ); - - return b; -} - - -#define INSIZES 5 -#define TYPESCOUNT 5 -#define NUM 64 - -static const int sizes[INSIZES]={63,126,252,520,772}; -static const int types[TYPESCOUNT]={STBIR_1CHANNEL,STBIR_2CHANNEL,STBIR_RGB,STBIR_4CHANNEL,STBIR_RGBA}; -static const int effective[TYPESCOUNT]={1,2,3,4,7}; - -int main( int argc, char ** argv ) -{ - unsigned char * input; - unsigned char * output; - int dimensionx, dimensiony; - int scalex, scaley; - int totalms; - int timing_count; - int ir; - int * file; - int * ts; - int64 totalcycles; - - if ( argc != 6 ) - { - printf("command: dotimings x_samps y_samps x_scale y_scale outfilename\n"); - exit(1); - } - - input = malloc( 4*1200*1200 ); - memset( input, 0x80, 4*1200*1200 ); - output = malloc( 4*10000*10000ULL ); - - dimensionx = atoi( argv[1] ); - dimensiony = atoi( argv[2] ); - scalex = atoi( argv[3] ); - scaley = atoi( argv[4] ); - - timing_count = dimensionx * dimensiony * INSIZES * TYPESCOUNT; - - file = malloc( sizeof(int) * ( 2 * timing_count + HEADER ) ); - ts = file + HEADER; - - totalms = get_milliseconds(); - totalcycles = STBIR_PROFILE_FUNC(); - for( ir = 0 ; ir < INSIZES ; ir++ ) - { - int ix, iy, ty; - ix = iy = sizes[ir]; - - for( ty = 0 ; ty < TYPESCOUNT ; ty++ ) - { - int h, hh; - - h = 1; - for( hh = 0 ; hh < dimensiony; hh++ ) - { - int ww, w = 1; - for( ww = 0 ; ww < dimensionx; ww++ ) - { - int64 VF, HF; - int good; - - v_info.control_v_first = 2; // vertical first - VF = nresize( output, w, h, (w*4*1)&~3, input, ix, iy, ix*4*1, types[ty], STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL ); - v_info.control_v_first = 1; // horizonal first - HF = nresize( output, w, h, (w*4*1)&~3, input, ix, iy, ix*4*1, types[ty], STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL ); - - good = ( ((HF<=VF) && (!v_info.v_first)) || ((VF<=HF) && (v_info.v_first))); - -// printf("\r%d,%d, %d,%d, %d, %I64d,%I64d, // Good: %c(%c-%d) CompEst: %.1f %.1f\n", ix, iy, w, h, ty, VF, HF, good?'y':'n', v_info.v_first?'v':'h', v_info.v_resize_classification, v_info.v_cost,v_info.h_cost ); - ts[0] = (int)VF; - ts[1] = (int)HF; - - ts += 2; - - w += scalex; - } - printf("."); - h += scaley; - } - } - } - totalms = get_milliseconds() - totalms; - totalcycles = STBIR_PROFILE_FUNC() - totalcycles; - - printf("\n"); - - file[0] = 'VFT1'; - - #if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ ) - file[1] = 1; // x64 - #elif defined( _M_AMD64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__arm__) || defined( _M_ARM ) - file[1] = 2; // arm - #else - file[1] = 99; // who knows??? - #endif - - #ifdef STBIR_SIMD8 - file[2] = 2; // simd-8 - #elif defined( STBIR_SIMD ) - file[2] = 1; // simd-4 - #else - file[2] = 0; // nosimd - #endif - - file[3] = dimensionx; // dimx - file[4] = dimensiony; // dimy - file[5] = TYPESCOUNT; // channel types - file[ 6] = types[0]; file[7] = types[1]; file[8] = types[2]; file[9] = types[3]; file[10] = types[4]; // buffer_type - file[11] = effective[0]; file[12] = effective[1]; file[13] = effective[2]; file[14] = effective[3]; file[15] = effective[4]; // effective channels - file[16] = INSIZES; // resizes - file[17] = sizes[0]; file[18] = sizes[0]; // input sizes (w x h) - file[19] = sizes[1]; file[20] = sizes[1]; - file[21] = sizes[2]; file[22] = sizes[2]; - file[23] = sizes[3]; file[24] = sizes[3]; - file[25] = sizes[4]; file[26] = sizes[4]; - file[27] = scalex; file[28] = scaley; // scale the dimx and dimy amount ( for(i=0;i2GB) images - 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions - 0.90 (2014-09-17) first released version - - LICENSE - See end of file for license information. - - TODO - Don't decode all of the image data when only processing a partial tile - Don't use full-width decode buffers when only processing a partial tile - When processing wide images, break processing into tiles so data fits in L1 cache - Installable filters? - Resize that respects alpha test coverage - (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: - https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) -*/ - -#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H -#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H - -#ifdef _MSC_VER -typedef unsigned char stbir_uint8; -typedef unsigned short stbir_uint16; -typedef unsigned int stbir_uint32; -typedef unsigned __int64 stbir_uint64; -#else -#include -typedef uint8_t stbir_uint8; -typedef uint16_t stbir_uint16; -typedef uint32_t stbir_uint32; -typedef uint64_t stbir_uint64; -#endif - -#ifndef STBIRDEF -#ifdef STB_IMAGE_RESIZE_STATIC -#define STBIRDEF static -#else -#ifdef __cplusplus -#define STBIRDEF extern "C" -#else -#define STBIRDEF extern -#endif -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Easy-to-use API: -// -// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) -// * input_w is input image width (x-axis), input_h is input image height (y-axis) -// * stride is the offset between successive rows of image data in memory, in bytes. you can -// specify 0 to mean packed continuously in memory -// * alpha channel is treated identically to other channels. -// * colorspace is linear or sRGB as specified by function name -// * returned result is 1 for success or 0 in case of an error. -// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. -// * Memory required grows approximately linearly with input and output size, but with -// discontinuities at input_w == output_w and input_h == output_h. -// * These functions use a "default" resampling filter defined at compile time. To change the filter, -// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE -// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. - -STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels); - -STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels); - - -// The following functions interpret image data as gamma-corrected sRGB. -// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, -// or otherwise provide the index of the alpha channel. Flags value -// of 0 will probably do the right thing if you're not sure what -// the flags mean. - -#define STBIR_ALPHA_CHANNEL_NONE -1 - -// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will -// use alpha-weighted resampling (effectively premultiplying, resampling, -// then unpremultiplying). -#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) -// The specified alpha channel should be handled as gamma-corrected value even -// when doing sRGB operations. -#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) - -#define STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED (1 << 2) - -STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags); - - -typedef enum -{ - STBIR_EDGE_CLAMP = 1, - STBIR_EDGE_REFLECT = 2, - STBIR_EDGE_WRAP = 3, - STBIR_EDGE_ZERO = 4, -} stbir_edge; - -// This function adds the ability to specify how requests to sample off the edge of the image are handled. -STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode); - -////////////////////////////////////////////////////////////////////////////// -// -// Medium-complexity API -// -// This extends the easy-to-use API as follows: -// -// * Alpha-channel can be processed separately -// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE -// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) -// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) -// * Filter can be selected explicitly -// * uint16 image type -// * sRGB colorspace available for all types -// * context parameter for passing to STBIR_MALLOC - -typedef enum -{ - STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses - STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios - STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering - STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque - STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline - STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 -} stbir_filter; - -typedef enum -{ - STBIR_COLORSPACE_LINEAR, - STBIR_COLORSPACE_SRGB, - - STBIR_MAX_COLORSPACES, -} stbir_colorspace; - -// The following functions are all identical except for the type of the image data - -STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context); - -STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context); - -STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context); - - - -////////////////////////////////////////////////////////////////////////////// -// -// Full-complexity API -// -// This extends the medium API as follows: -// -// * uint32 image type -// * not typesafe -// * separate filter types for each axis -// * separate edge modes for each axis -// * can specify scale explicitly for subpixel correctness -// * can specify image source tile using texture coordinates - -typedef enum -{ - STBIR_TYPE_UINT8 , - STBIR_TYPE_UINT16, - STBIR_TYPE_FLOAT , - STBIR_TYPE_UINT32, - - STBIR_MAX_TYPES -} stbir_datatype; - -STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context); - -STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float x_scale, float y_scale, - float x_offset, float y_offset); - -STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float s0, float t0, float s1, float t1); -// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H - - - - - -#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION - -#ifndef STBIR_ASSERT -#include -#define STBIR_ASSERT(x) assert(x) -#endif - -// For memset -#include - -#include - -#ifndef STBIR_MALLOC -#include -// use comma operator to evaluate c, to avoid "unused parameter" warnings -#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) -#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) -#endif - -#ifndef _MSC_VER -#ifdef __cplusplus -#define stbir__inline inline -#else -#define stbir__inline -#endif -#else -#define stbir__inline __forceinline -#endif - -#ifdef STBIR_PROFILE - -union -{ - struct { stbir_uint64 total, setup, filters, looping, vertical, horizontal, decode, encode, alpha, unalpha; } named; - stbir_uint64 array[10]; -} oldprofile; -stbir_uint64 * current_zone_excluded_ptr; - -#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ ) - -#ifdef _MSC_VER - - STBIRDEF stbir_uint64 __rdtsc(); - #define STBIR_PROFILE_FUNC() __rdtsc() - -#else // non msvc - - static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() - { - stbir_uint32 lo, hi; - asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) ); - return ( ( (stbir_uint64) hi ) << 32 ) | ( (stbir_uint64) lo ); - } - -#endif // msvc - -#elif defined( _M_AMD64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) || defined(__ARM_NEON) - -#ifdef _MSC_VER - - #error Not sure what the intrinsic for cntvct_el0 is on MSVC - -#else // no msvc - - static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() - { - stbir_uint64 tsc; - asm volatile("mrs %0, cntvct_el0" : "=r" (tsc)); - return tsc; - } - -#endif - -#elif // x64, arm - -#error Unknown platform for profiling. - -#endif //x64 and - -#define STBIR_PROFILE_START() { stbir_uint64 thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * save_parent_excluded_ptr = current_zone_excluded_ptr; stbir_uint64 current_zone_excluded = 0; current_zone_excluded_ptr = ¤t_zone_excluded; -#define STBIR_PROFILE_END( wh ) thiszonetime = STBIR_PROFILE_FUNC() - thiszonetime; oldprofile.named.wh += thiszonetime - current_zone_excluded; *save_parent_excluded_ptr += thiszonetime; current_zone_excluded_ptr = save_parent_excluded_ptr; } -#define STBIR_PROFILE_FIRST_START() { int i; current_zone_excluded_ptr = &oldprofile.named.total; for(i=0;i 65536 -#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." -// because we store the indices in 16-bit variables -#endif - -// This value is added to alpha just before premultiplication to avoid -// zeroing out color values. It is equivalent to 2^-80. If you don't want -// that behavior (it may interfere if you have floating point images with -// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to -// disable it. -#ifndef STBIR_ALPHA_EPSILON -#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) -#endif - - - -#ifdef _MSC_VER -#define STBIR__UNUSED_PARAM(v) (void)(v) -#else -#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) -#endif - -// must match stbir_datatype -static unsigned char stbir__type_size[] = { - 1, // STBIR_TYPE_UINT8 - 2, // STBIR_TYPE_UINT16 - 4, // STBIR_TYPE_UINT32 - 4, // STBIR_TYPE_FLOAT -}; - -// Kernel function centered at 0 -typedef float (stbir__kernel_fn)(float x, float scale); -typedef float (stbir__support_fn)(float scale); - -typedef struct -{ - stbir__kernel_fn* kernel; - stbir__support_fn* support; -} stbir__filter_info; - -// When upsampling, the contributors are which source pixels contribute. -// When downsampling, the contributors are which destination pixels are contributed to. -typedef struct -{ - int n0; // First contributing pixel - int n1; // Last contributing pixel -} stbir__contributors; - -typedef struct -{ - const void* input_data; - int input_w; - int input_h; - int input_stride_bytes; - - void* output_data; - int output_w; - int output_h; - int output_stride_bytes; - - float s0, t0, s1, t1; - - float horizontal_shift; // Units: output pixels - float vertical_shift; // Units: output pixels - float horizontal_scale; - float vertical_scale; - - int channels; - int alpha_channel; - stbir_uint32 flags; - stbir_datatype type; - stbir_filter horizontal_filter; - stbir_filter vertical_filter; - stbir_edge edge_horizontal; - stbir_edge edge_vertical; - stbir_colorspace colorspace; - - stbir__contributors* horizontal_contributors; - float* horizontal_coefficients; - - stbir__contributors* vertical_contributors; - float* vertical_coefficients; - - int decode_buffer_pixels; - float* decode_buffer; - - float* horizontal_buffer; - - // cache these because ceil/floor are inexplicably showing up in profile - int horizontal_coefficient_width; - int vertical_coefficient_width; - int horizontal_filter_pixel_width; - int vertical_filter_pixel_width; - int horizontal_filter_pixel_margin; - int vertical_filter_pixel_margin; - int horizontal_num_contributors; - int vertical_num_contributors; - - int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) - int ring_buffer_num_entries; // Total number of entries in the ring buffer. - int ring_buffer_first_scanline; - int ring_buffer_last_scanline; - int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer - float* ring_buffer; - - float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. - - int horizontal_contributors_size; - int horizontal_coefficients_size; - int vertical_contributors_size; - int vertical_coefficients_size; - int decode_buffer_size; - int horizontal_buffer_size; - int ring_buffer_size; - int encode_buffer_size; -} ostbir__info; - - -static const float stbir__max_uint8_as_float = 255.0f; -static const float stbir__max_uint16_as_float = 65535.0f; -static const double stbir__max_uint32_as_float = 4294967295.0; - - -static stbir__inline int stbir__min(int a, int b) -{ - return a < b ? a : b; -} - -static stbir__inline float stbir__saturate(float x) -{ - if (x < 0) - return 0; - - if (x > 1) - return 1; - - return x; -} - -#ifdef STBIR_SATURATE_INT -static stbir__inline stbir_uint8 stbir__saturate8(int x) -{ - if ((unsigned int) x <= 255) - return (stbir_uint8) x; - - if (x < 0) - return 0; - - return 255; -} - -static stbir__inline stbir_uint16 stbir__saturate16(int x) -{ - if ((unsigned int) x <= 65535) - return (stbir_uint16) x; - - if (x < 0) - return 0; - - return 65535; -} -#endif - -static float stbir__srgb_uchar_to_linear_float[256] = { - 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, - 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, - 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, - 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, - 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, - 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, - 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, - 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, - 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, - 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, - 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, - 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, - 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, - 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, - 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, - 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, - 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, - 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, - 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, - 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, - 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, - 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, - 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, - 0.982251f, 0.991102f, 1.0f -}; - -static float stbir__srgb_to_linear(float f) -{ - if (f <= 0.04045f) - return f / 12.92f; - else - return (float)pow((f + 0.055f) / 1.055f, 2.4f); -} - -static float stbir__linear_to_srgb(float f) -{ - if (f <= 0.0031308f) - return f * 12.92f; - else - return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; -} - -#ifndef STBIR_NON_IEEE_FLOAT -// From https://gist.github.com/rygorous/2203834 - -typedef union -{ - stbir_uint32 u; - float f; -} stbir__FP32; - -static const stbir_uint32 fp32_to_srgb8_tab4[104] = { - 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, - 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, - 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, - 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, - 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, - 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, - 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, - 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, - 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, - 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, - 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, - 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, - 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, -}; - -static stbir_uint8 stbir__linear_to_srgb_uchar(float in) -{ - static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps - static const stbir__FP32 minval = { (127-13) << 23 }; - stbir_uint32 tab,bias,scale,t; - stbir__FP32 f; - - // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. - // The tests are carefully written so that NaNs map to 0, same as in the reference - // implementation. - if (!(in > minval.f)) // written this way to catch NaNs - in = minval.f; - if (in > almostone.f) - in = almostone.f; - - // Do the table lookup and unpack bias, scale - f.f = in; - tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; - bias = (tab >> 16) << 9; - scale = tab & 0xffff; - - // Grab next-highest mantissa bits and perform linear interpolation - t = (f.u >> 12) & 0xff; - return (unsigned char) ((bias + scale*t) >> 16); -} - -#else -// sRGB transition values, scaled by 1<<28 -static int stbir__srgb_offset_to_linear_scaled[256] = -{ - 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, - 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, - 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, - 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, - 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, - 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, - 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, - 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, - 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, - 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, - 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, - 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, - 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, - 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, - 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, - 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, - 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, - 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, - 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, - 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, - 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, - 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, - 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, - 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, - 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, - 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, - 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, - 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, - 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, - 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, - 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, - 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, -}; - -static stbir_uint8 stbir__linear_to_srgb_uchar(float f) -{ - int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp - int v = 0; - int i; - - // Refine the guess with a short binary search. - i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; - - return (stbir_uint8) v; -} -#endif - -static float stbir__filter_trapezoid(float x, float scale) -{ - float halfscale = scale / 2; - float t = 0.5f + halfscale; - STBIR_ASSERT(scale <= 1); - - x = (float)fabs(x); - - if (x >= t) - return 0; - else - { - float r = 0.5f - halfscale; - if (x <= r) - return 1; - else - return (t - x) / scale; - } -} - -static float stbir__support_trapezoid(float scale) -{ - STBIR_ASSERT(scale <= 1); - return 0.5f + scale / 2; -} - -static float stbir__filter_triangle(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x <= 1.0f) - return 1 - x; - else - return 0; -} - -static float stbir__filter_cubic(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x < 1.0f) - return (4 + x*x*(3*x - 6))/6; - else if (x < 2.0f) - return (8 + x*(-12 + x*(6 - x)))/6; - - return (0.0f); -} - -static float stbir__filter_catmullrom(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x < 1.0f) - return 1 - x*x*(2.5f - 1.5f*x); - else if (x < 2.0f) - return 2 - x*(4 + x*(0.5f*x - 2.5f)); - - return (0.0f); -} - -static float stbir__filter_mitchell(float x, float s) -{ - STBIR__UNUSED_PARAM(s); - - x = (float)fabs(x); - - if (x < 1.0f) - return (16 + x*x*(21 * x - 36))/18; - else if (x < 2.0f) - return (32 + x*(-60 + x*(36 - 7*x)))/18; - - return (0.0f); -} - -static float stbir__support_zero(float s) -{ - STBIR__UNUSED_PARAM(s); - return 0; -} - -static float stbir__support_one(float s) -{ - STBIR__UNUSED_PARAM(s); - return 1; -} - -static float stbir__support_two(float s) -{ - STBIR__UNUSED_PARAM(s); - return 2; -} - -static stbir__filter_info stbir__filter_info_table[] = { - { NULL, stbir__support_zero }, - { stbir__filter_trapezoid, stbir__support_trapezoid }, - { stbir__filter_triangle, stbir__support_one }, - { stbir__filter_cubic, stbir__support_two }, - { stbir__filter_catmullrom, stbir__support_two }, - { stbir__filter_mitchell, stbir__support_two }, -}; - -stbir__inline static int stbir__use_upsampling(float ratio) -{ - return ratio > 1; -} - -stbir__inline static int stbir__use_width_upsampling(ostbir__info* stbir_info) -{ - return stbir__use_upsampling(stbir_info->horizontal_scale); -} - -stbir__inline static int stbir__use_height_upsampling(ostbir__info* stbir_info) -{ - return stbir__use_upsampling(stbir_info->vertical_scale); -} - -// This is the maximum number of input samples that can affect an output sample -// with the given filter -static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) -{ - STBIR_ASSERT(filter != 0); - STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); - - if (stbir__use_upsampling(scale)) - return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); - else - return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); -} - -// This is how much to expand buffers to account for filters seeking outside -// the image boundaries. -static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) -{ - return stbir__get_filter_pixel_width(filter, scale) / 2; -} - -static int stbir__get_coefficient_width(stbir_filter filter, float scale) -{ - if (stbir__use_upsampling(scale)) - return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); - else - return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); -} - -static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) -{ - if (stbir__use_upsampling(scale)) - return output_size; - else - return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); -} - -static int stbir__get_total_horizontal_coefficients(ostbir__info* info) -{ - return info->horizontal_num_contributors - * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); -} - -static int stbir__get_total_vertical_coefficients(ostbir__info* info) -{ - return info->vertical_num_contributors - * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); -} - -static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) -{ - return &contributors[n]; -} - -// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, -// if you change it here change it there too. -static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) -{ - int width = stbir__get_coefficient_width(filter, scale); - return &coefficients[width*n + c]; -} - -static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) -{ - switch (edge) - { - case STBIR_EDGE_ZERO: - return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later - - case STBIR_EDGE_CLAMP: - if (n < 0) - return 0; - - if (n >= max) - return max - 1; - - return n; // NOTREACHED - - case STBIR_EDGE_REFLECT: - { - if (n < 0) - { - if (n > -max) - return -n; - else - return max - 1; - } - - if (n >= max) - { - int max2 = max * 2; - if (n >= max2) - return 0; - else - return max2 - n - 1; - } - - return n; // NOTREACHED - } - - case STBIR_EDGE_WRAP: - if (n >= 0) - return (n % max); - else - { - int m = (-n) % max; - - if (m != 0) - m = max - m; - - return (m); - } - // NOTREACHED - - default: - STBIR_ASSERT(!"Unimplemented edge type"); - return 0; - } -} - -stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) -{ - // avoid per-pixel switch - if (n >= 0 && n < max) - return n; - return stbir__edge_wrap_slow(edge, n, max); -} - -// What input pixels contribute to this output pixel? -static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) -{ - float out_pixel_center = (float)n + 0.5f; - float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; - float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; - - float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; - float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; - - *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; - *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); - *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); -} - -// What output pixels does this input pixel contribute to? -static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) -{ - float in_pixel_center = (float)n + 0.5f; - float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; - float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; - - float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; - float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; - - *out_center_of_in = in_pixel_center * scale_ratio - out_shift; - *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); - *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); -} - -static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) -{ - int i; - float total_filter = 0; - float filter_scale; - - STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. - - contributor->n0 = in_first_pixel; - contributor->n1 = in_last_pixel; - - STBIR_ASSERT(contributor->n1 >= contributor->n0); - - for (i = 0; i <= in_last_pixel - in_first_pixel; i++) - { - float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; - coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); - - // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) - if (i == 0 && !coefficient_group[i]) - { - contributor->n0 = ++in_first_pixel; - i--; - continue; - } - - total_filter += coefficient_group[i]; - } - - STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); - - STBIR_ASSERT(total_filter > 0.9); - STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. - - // Make sure the sum of all coefficients is 1. - filter_scale = 1 / total_filter; - - for (i = 0; i <= in_last_pixel - in_first_pixel; i++) - coefficient_group[i] *= filter_scale; - - for (i = in_last_pixel - in_first_pixel; i >= 0; i--) - { - if (coefficient_group[i]) - break; - - // This line has no weight. We can skip it. - contributor->n1 = contributor->n0 + i - 1; - } -} - -static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) -{ - int i; - - STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. - - contributor->n0 = out_first_pixel; - contributor->n1 = out_last_pixel; - - STBIR_ASSERT(contributor->n1 >= contributor->n0); - - for (i = 0; i <= out_last_pixel - out_first_pixel; i++) - { - float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; - float x = out_pixel_center - out_center_of_in; - coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; - } - - STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); - - for (i = out_last_pixel - out_first_pixel; i >= 0; i--) - { - if (coefficient_group[i]) - break; - - // This line has no weight. We can skip it. - contributor->n1 = contributor->n0 + i - 1; - } -} - -static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) -{ - int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); - int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); - int i, j; - int skip; - - for (i = 0; i < output_size; i++) - { - float scale; - float total = 0; - - for (j = 0; j < num_contributors; j++) - { - if (i >= contributors[j].n0 && i <= contributors[j].n1) - { - float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); - total += coefficient; - } - else if (i < contributors[j].n0) - break; - } - - //STBIR_ASSERT(total > 0.9f); - //STBIR_ASSERT(total < 1.5f); - - scale = 1 / total; - - for (j = 0; j < num_contributors; j++) - { - if (i >= contributors[j].n0 && i <= contributors[j].n1) - *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; - else if (i < contributors[j].n0) - break; - } - } - - // Optimize: Skip zero coefficients and contributions outside of image bounds. - // Do this after normalizing because normalization depends on the n0/n1 values. - for (j = 0; j < num_contributors; j++) - { - int range, max, width; - - skip = 0; - while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) - skip++; - - contributors[j].n0 += skip; - - while (contributors[j].n0 < 0) - { - contributors[j].n0++; - skip++; - } - - range = contributors[j].n1 - contributors[j].n0 + 1; - max = stbir__min(num_coefficients, range); - - width = stbir__get_coefficient_width(filter, scale_ratio); - for (i = 0; i < max; i++) - { - if (i + skip >= width) - break; - - *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); - } - - continue; - } - - // Using min to avoid writing into invalid pixels. - for (i = 0; i < num_contributors; i++) - contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); -} - -// Each scan line uses the same kernel values so we should calculate the kernel -// values once and then we can use them for every scan line. -static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) -{ - int n; - int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); - - if (stbir__use_upsampling(scale_ratio)) - { - float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; - - // Looping through out pixels - for (n = 0; n < total_contributors; n++) - { - float in_center_of_out; // Center of the current out pixel in the in pixel space - int in_first_pixel, in_last_pixel; - - stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); - - stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); - } - } - else - { - float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; - - // Looping through in pixels - for (n = 0; n < total_contributors; n++) - { - float out_center_of_in; // Center of the current out pixel in the in pixel space - int out_first_pixel, out_last_pixel; - int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); - - stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); - - stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); - } - - stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); - } -} - -static float* stbir__get_decode_buffer(ostbir__info* stbir_info) -{ - // The 0 index of the decode buffer starts after the margin. This makes - // it okay to use negative indexes on the decode buffer. - return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; -} - -#define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace)) - -static void stbir__decode_scanline(ostbir__info* stbir_info, int n) -{ - int c; - int channels = stbir_info->channels; - int alpha_channel = stbir_info->alpha_channel; - int type = stbir_info->type; - int colorspace = stbir_info->colorspace; - int input_w = stbir_info->input_w; - size_t input_stride_bytes = stbir_info->input_stride_bytes; - float* decode_buffer = stbir__get_decode_buffer(stbir_info); - stbir_edge edge_horizontal = stbir_info->edge_horizontal; - stbir_edge edge_vertical = stbir_info->edge_vertical; - size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; - const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; - int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; - int decode = STBIR__DECODE(type, colorspace); - - int x = -stbir_info->horizontal_filter_pixel_margin; - - // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, - // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO - if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) - { - for (; x < max_x; x++) - for (c = 0; c < channels; c++) - decode_buffer[x*channels + c] = 0; - return; - } - - STBIR_PROFILE_START( ); - switch (decode) - { - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): - for (; x < max_x; x++) - { - int decode_pixel_index = x * channels; - int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; - for (c = 0; c < channels; c++) - decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; - } - - break; - - default: - STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); - break; - } - STBIR_PROFILE_END( decode ); - - if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) - { - STBIR_PROFILE_START(); - - for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) - { - int decode_pixel_index = x * channels; - - // If the alpha value is 0 it will clobber the color values. Make sure it's not. - float alpha = decode_buffer[decode_pixel_index + alpha_channel]; -#ifndef STBIR_NO_ALPHA_EPSILON - if (stbir_info->type != STBIR_TYPE_FLOAT) { - alpha += STBIR_ALPHA_EPSILON; - decode_buffer[decode_pixel_index + alpha_channel] = alpha; - } -#endif - for (c = 0; c < channels; c++) - { - if (c == alpha_channel) - continue; - - decode_buffer[decode_pixel_index + c] *= alpha; - } - } - STBIR_PROFILE_END( alpha ); - } - - if (edge_horizontal == STBIR_EDGE_ZERO) - { - for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) - { - for (c = 0; c < channels; c++) - decode_buffer[x*channels + c] = 0; - } - for (x = input_w; x < max_x; x++) - { - for (c = 0; c < channels; c++) - decode_buffer[x*channels + c] = 0; - } - } -} - -static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) -{ - return &ring_buffer[index * ring_buffer_length]; -} - -static float* stbir__add_empty_ring_buffer_entry(ostbir__info* stbir_info, int n) -{ - int ring_buffer_index; - float* ring_buffer; - - stbir_info->ring_buffer_last_scanline = n; - - if (stbir_info->ring_buffer_begin_index < 0) - { - ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; - stbir_info->ring_buffer_first_scanline = n; - } - else - { - ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; - STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); - } - - ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); - - memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); - - return ring_buffer; -} - - -static void stbir__resample_horizontal_upsample(ostbir__info* stbir_info, float* output_buffer) -{ - int x, k; - int output_w = stbir_info->output_w; - int channels = stbir_info->channels; - float* decode_buffer = stbir__get_decode_buffer(stbir_info); - stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; - float* horizontal_coefficients = stbir_info->horizontal_coefficients; - int coefficient_width = stbir_info->horizontal_coefficient_width; - - STBIR_PROFILE_START( ); - for (x = 0; x < output_w; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int out_pixel_index = x * channels; - int coefficient_group = coefficient_width * x; - int coefficient_counter = 0; - - STBIR_ASSERT(n1 >= n0); - STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); - STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); - STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); - STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); - - switch (channels) { - case 1: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 1; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - } - break; - case 2: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 2; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - } - break; - case 3: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 3; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - } - break; - case 4: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * 4; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; - } - break; - default: - for (k = n0; k <= n1; k++) - { - int in_pixel_index = k * channels; - float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; - int c; - STBIR_ASSERT(coefficient != 0); - for (c = 0; c < channels; c++) - output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; - } - break; - } - } - STBIR_PROFILE_END( horizontal ); -} - -static void stbir__resample_horizontal_downsample(ostbir__info* stbir_info, float* output_buffer) -{ - int x, k; - int input_w = stbir_info->input_w; - int channels = stbir_info->channels; - float* decode_buffer = stbir__get_decode_buffer(stbir_info); - stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; - float* horizontal_coefficients = stbir_info->horizontal_coefficients; - int coefficient_width = stbir_info->horizontal_coefficient_width; - int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; - int max_x = input_w + filter_pixel_margin * 2; - - STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); - - STBIR_PROFILE_START( ); - switch (channels) { - case 1: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 1; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 1; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - } - } - break; - - case 2: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 2; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 2; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - } - } - break; - - case 3: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 3; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 3; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - //STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - } - } - break; - - case 4: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * 4; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int out_pixel_index = k * 4; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); - output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; - output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; - output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; - output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; - } - } - break; - - default: - for (x = 0; x < max_x; x++) - { - int n0 = horizontal_contributors[x].n0; - int n1 = horizontal_contributors[x].n1; - - int in_x = x - filter_pixel_margin; - int in_pixel_index = in_x * channels; - int max_n = n1; - int coefficient_group = coefficient_width * x; - - for (k = n0; k <= max_n; k++) - { - int c; - int out_pixel_index = k * channels; - float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); - for (c = 0; c < channels; c++) - output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; - } - } - break; - } - STBIR_PROFILE_END( horizontal ); -} - -static void stbir__decode_and_resample_upsample(ostbir__info* stbir_info, int n) -{ - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline(stbir_info, n); - - // Now resample it into the ring buffer. - if (stbir__use_width_upsampling(stbir_info)) - stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); - else - stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); - - // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. -} - -static void stbir__decode_and_resample_downsample(ostbir__info* stbir_info, int n) -{ - // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline(stbir_info, n); - - memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); - - // Now resample it into the horizontal buffer. - if (stbir__use_width_upsampling(stbir_info)) - stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); - else - stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); - - // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. -} - -// Get the specified scan line from the ring buffer. -static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) -{ - int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; - return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); -} - - -static void stbir__encode_scanline(ostbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) -{ - int x; - int n; - int num_nonalpha; - stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; - - if ((!(stbir_info->flags&STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED))&&(alpha_channel!=-1)) - { - STBIR_PROFILE_START( ); - - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - float alpha = encode_buffer[pixel_index + alpha_channel]; - float reciprocal_alpha = alpha ? 1.0f / alpha : 0; - - // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb - for (n = 0; n < channels; n++) - if (n != alpha_channel) - encode_buffer[pixel_index + n] *= reciprocal_alpha; - - // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. - // Because we only add it for integer types, it will automatically be discarded on integer - // conversion, so we don't need to subtract it back out (which would be problematic for - // numeric precision reasons). - } - STBIR_PROFILE_END( unalpha ); - } - - // build a table of all channels that need colorspace correction, so - // we don't perform colorspace correction on channels that don't need it. - for (x = 0, num_nonalpha = 0; x < channels; ++x) - { - if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) - { - nonalpha[num_nonalpha++] = (stbir_uint16)x; - } - } - - #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) - #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) - - #ifdef STBIR__SATURATE_INT - #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) - #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) - #else - #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) - #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) - #endif - - STBIR_PROFILE_START( ); - - switch (decode) - { - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); - } - - if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); - } - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); - } - - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); - } - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < channels; n++) - { - int index = pixel_index + n; - ((float*)output_buffer)[index] = encode_buffer[index]; - } - } - break; - - case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): - for (x=0; x < num_pixels; ++x) - { - int pixel_index = x*channels; - - for (n = 0; n < num_nonalpha; n++) - { - int index = pixel_index + nonalpha[n]; - float p = encode_buffer[index]; - if ( p <= 0 ) p = 0; if ( p >= 1.0 ) p = 1.0; - ((float*)output_buffer)[index] = stbir__linear_to_srgb(p); - } - - if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) - { - float p = encode_buffer[pixel_index + alpha_channel]; - if ( p <= 0 ) p = 0; if ( p >= 1.0 ) p = 1.0; - ((float*)output_buffer)[pixel_index + alpha_channel] = p; - } - } - break; - - default: - STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); - break; - } - STBIR_PROFILE_END( encode ); -} - -static void stbir__resample_vertical_upsample(ostbir__info* stbir_info, int n) -{ - int x, k; - int output_w = stbir_info->output_w; - stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; - float* vertical_coefficients = stbir_info->vertical_coefficients; - int channels = stbir_info->channels; - int alpha_channel = stbir_info->alpha_channel; - int type = stbir_info->type; - int colorspace = stbir_info->colorspace; - int ring_buffer_entries = stbir_info->ring_buffer_num_entries; - void* output_data = stbir_info->output_data; - float* encode_buffer = stbir_info->encode_buffer; - int decode = STBIR__DECODE(type, colorspace); - int coefficient_width = stbir_info->vertical_coefficient_width; - int coefficient_counter; - int contributor = n; - - float* ring_buffer = stbir_info->ring_buffer; - int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; - int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; - int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); - - int n0,n1, output_row_start; - int coefficient_group = coefficient_width * contributor; - - n0 = vertical_contributors[contributor].n0; - n1 = vertical_contributors[contributor].n1; - - output_row_start = n * stbir_info->output_stride_bytes; - - STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); - - STBIR_PROFILE_START( ); - - memset(encode_buffer, 0, output_w * sizeof(float) * channels); - - // I tried reblocking this for better cache usage of encode_buffer - // (using x_outer, k, x_inner), but it lost speed. -- stb - - coefficient_counter = 0; - switch (channels) { - case 1: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 1; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - } - } - break; - case 2: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 2; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; - } - } - break; - case 3: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 3; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; - encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; - } - } - break; - case 4: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * 4; - encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; - encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; - encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; - encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; - } - } - break; - default: - for (k = n0; k <= n1; k++) - { - int coefficient_index = coefficient_counter++; - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - for (x = 0; x < output_w; ++x) - { - int in_pixel_index = x * channels; - int c; - for (c = 0; c < channels; c++) - encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; - } - } - break; - } - STBIR_PROFILE_END( vertical ); - stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); -} - -static void stbir__resample_vertical_downsample(ostbir__info* stbir_info, int n) -{ - int x, k; - int output_w = stbir_info->output_w; - stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; - float* vertical_coefficients = stbir_info->vertical_coefficients; - int channels = stbir_info->channels; - int ring_buffer_entries = stbir_info->ring_buffer_num_entries; - float* horizontal_buffer = stbir_info->horizontal_buffer; - int coefficient_width = stbir_info->vertical_coefficient_width; - int contributor = n + stbir_info->vertical_filter_pixel_margin; - - float* ring_buffer = stbir_info->ring_buffer; - int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; - int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; - int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); - int n0,n1; - - n0 = vertical_contributors[contributor].n0; - n1 = vertical_contributors[contributor].n1; - - STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); - - STBIR_PROFILE_START( ); - for (k = n0; k <= n1; k++) - { - int coefficient_index = k - n0; - int coefficient_group = coefficient_width * contributor; - float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; - - float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); - - switch (channels) { - case 1: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 1; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - } - break; - case 2: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 2; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; - } - break; - case 3: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 3; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; - ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; - } - break; - case 4: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * 4; - ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; - ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; - ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; - ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; - } - break; - default: - for (x = 0; x < output_w; x++) - { - int in_pixel_index = x * channels; - - int c; - for (c = 0; c < channels; c++) - ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; - } - break; - } - } - STBIR_PROFILE_END( vertical ); -} - -static void stbir__buffer_loop_upsample(ostbir__info* stbir_info) -{ - int y; - float scale_ratio = stbir_info->vertical_scale; - float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; - - STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); - - for (y = 0; y < stbir_info->output_h; y++) - { - float in_center_of_out = 0; // Center of the current out scanline in the in scanline space - int in_first_scanline = 0, in_last_scanline = 0; - - stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); - - STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); - - if (stbir_info->ring_buffer_begin_index >= 0) - { - // Get rid of whatever we don't need anymore. - while (in_first_scanline > stbir_info->ring_buffer_first_scanline) - { - if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) - { - // We just popped the last scanline off the ring buffer. - // Reset it to the empty state. - stbir_info->ring_buffer_begin_index = -1; - stbir_info->ring_buffer_first_scanline = 0; - stbir_info->ring_buffer_last_scanline = 0; - break; - } - else - { - stbir_info->ring_buffer_first_scanline++; - stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; - } - } - } - - // Load in new ones. - if (stbir_info->ring_buffer_begin_index < 0) - stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); - - while (in_last_scanline > stbir_info->ring_buffer_last_scanline) - stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); - - // Now all buffers should be ready to write a row of vertical sampling. - stbir__resample_vertical_upsample(stbir_info, y); - - STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); - } -} - -static void stbir__empty_ring_buffer(ostbir__info* stbir_info, int first_necessary_scanline) -{ - int output_stride_bytes = stbir_info->output_stride_bytes; - int channels = stbir_info->channels; - int alpha_channel = stbir_info->alpha_channel; - int type = stbir_info->type; - int colorspace = stbir_info->colorspace; - int output_w = stbir_info->output_w; - void* output_data = stbir_info->output_data; - int decode = STBIR__DECODE(type, colorspace); - - float* ring_buffer = stbir_info->ring_buffer; - int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); - - if (stbir_info->ring_buffer_begin_index >= 0) - { - // Get rid of whatever we don't need anymore. - while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) - { - if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) - { - int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; - float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); - stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); - STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); - } - - if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) - { - // We just popped the last scanline off the ring buffer. - // Reset it to the empty state. - stbir_info->ring_buffer_begin_index = -1; - stbir_info->ring_buffer_first_scanline = 0; - stbir_info->ring_buffer_last_scanline = 0; - break; - } - else - { - stbir_info->ring_buffer_first_scanline++; - stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; - } - } - } -} - -static void stbir__buffer_loop_downsample(ostbir__info* stbir_info) -{ - int y; - float scale_ratio = stbir_info->vertical_scale; - int output_h = stbir_info->output_h; - float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; - int pixel_margin = stbir_info->vertical_filter_pixel_margin; - int max_y = stbir_info->input_h + pixel_margin; - - STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); - - for (y = -pixel_margin; y < max_y; y++) - { - float out_center_of_in; // Center of the current out scanline in the in scanline space - int out_first_scanline, out_last_scanline; - - stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); - - STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); - - if (out_last_scanline < 0 || out_first_scanline >= output_h) - continue; - - stbir__empty_ring_buffer(stbir_info, out_first_scanline); - - stbir__decode_and_resample_downsample(stbir_info, y); - - // Load in new ones. - if (stbir_info->ring_buffer_begin_index < 0) - stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); - - while (out_last_scanline > stbir_info->ring_buffer_last_scanline) - stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); - - // Now the horizontal buffer is ready to write to all ring buffer rows. - stbir__resample_vertical_downsample(stbir_info, y); - } - - stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); -} - -static void stbir__setup(ostbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) -{ - info->input_w = input_w; - info->input_h = input_h; - info->output_w = output_w; - info->output_h = output_h; - info->channels = channels; -} - -static void stbir__calculate_transform(ostbir__info *info, float s0, float t0, float s1, float t1, float *transform) -{ - info->s0 = s0; - info->t0 = t0; - info->s1 = s1; - info->t1 = t1; - - if (transform) - { - info->horizontal_scale = transform[0]; - info->vertical_scale = transform[1]; - info->horizontal_shift = transform[2]; - info->vertical_shift = transform[3]; - } - else - { - info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); - info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); - - info->horizontal_shift = s0 * info->output_w / (s1 - s0); - info->vertical_shift = t0 * info->output_h / (t1 - t0); - } -} - -static void stbir__choose_filter(ostbir__info *info, stbir_filter h_filter, stbir_filter v_filter) -{ - if (h_filter == 0) - h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; - if (v_filter == 0) - v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; - info->horizontal_filter = h_filter; - info->vertical_filter = v_filter; -} - -static stbir_uint32 stbir__calculate_memory(ostbir__info *info) -{ - int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); - int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); - - info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); - info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); - - // One extra entry because floating point precision problems sometimes cause an extra to be necessary. - info->ring_buffer_num_entries = filter_height + 1; - - info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); - info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); - info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); - info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); - info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); - info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); - info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); - info->encode_buffer_size = info->output_w * info->channels * sizeof(float); - - STBIR_ASSERT(info->horizontal_filter != 0); - STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late - STBIR_ASSERT(info->vertical_filter != 0); - STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late - - if (stbir__use_height_upsampling(info)) - // The horizontal buffer is for when we're downsampling the height and we - // can't output the result of sampling the decode buffer directly into the - // ring buffers. - info->horizontal_buffer_size = 0; - else - // The encode buffer is to retain precision in the height upsampling method - // and isn't used when height downsampling. - info->encode_buffer_size = 0; - - return info->horizontal_contributors_size + info->horizontal_coefficients_size - + info->vertical_contributors_size + info->vertical_coefficients_size - + info->decode_buffer_size + info->horizontal_buffer_size - + info->ring_buffer_size + info->encode_buffer_size; -} - -static int stbir__resize_allocated(ostbir__info *info, - const void* input_data, int input_stride_in_bytes, - void* output_data, int output_stride_in_bytes, - int alpha_channel, stbir_uint32 flags, stbir_datatype type, - stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, - void* tempmem, size_t tempmem_size_in_bytes) -{ - size_t memory_required = stbir__calculate_memory(info); - - int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; - int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; - -#ifdef STBIR_DEBUG_OVERWRITE_TEST -#define OVERWRITE_ARRAY_SIZE 8 - unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; - unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; - unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; - unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; - - size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; - memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); - memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); - memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); - memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); -#endif - - STBIR_ASSERT(info->channels >= 0); - STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); - - if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) - return 0; - - STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); - STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); - - if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) - return 0; - if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) - return 0; - - if (alpha_channel < 0) - flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; - - if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { - STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); - } - - if (alpha_channel >= info->channels) - return 0; - - STBIR_ASSERT(tempmem); - - if (!tempmem) - return 0; - - STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); - - if (tempmem_size_in_bytes < memory_required) - return 0; - - memset(tempmem, 0, tempmem_size_in_bytes); - - info->input_data = input_data; - info->input_stride_bytes = width_stride_input; - - info->output_data = output_data; - info->output_stride_bytes = width_stride_output; - - info->alpha_channel = alpha_channel; - info->flags = flags; - info->type = type; - info->edge_horizontal = edge_horizontal; - info->edge_vertical = edge_vertical; - info->colorspace = colorspace; - - STBIR_PROFILE_START(); - - info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); - info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); - info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); - info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); - info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); - info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); - - info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); - info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; - -#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) - - info->horizontal_contributors = (stbir__contributors *) tempmem; - info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); - info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); - info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); - info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); - - if (stbir__use_height_upsampling(info)) - { - info->horizontal_buffer = NULL; - info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); - info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); - - STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); - } - else - { - info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); - info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); - info->encode_buffer = NULL; - - STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); - } - -#undef STBIR__NEXT_MEMPTR - - // This signals that the ring buffer is empty - info->ring_buffer_begin_index = -1; - - stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); - stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); - STBIR_PROFILE_END( filters ); - - STBIR_PROGRESS_REPORT(0); - - STBIR_PROFILE_START(); - if (stbir__use_height_upsampling(info)) - { - stbir__buffer_loop_upsample(info); - } - else - { - stbir__buffer_loop_downsample(info); - } - STBIR_PROFILE_END( looping ); - - - STBIR_PROGRESS_REPORT(1); - -#ifdef STBIR_DEBUG_OVERWRITE_TEST - STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); - STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); - STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); - STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); -#endif - - return 1; -} - - -static int stbir__resize_arbitrary( - void *alloc_context, - const void* input_data, int input_w, int input_h, int input_stride_in_bytes, - void* output_data, int output_w, int output_h, int output_stride_in_bytes, - float s0, float t0, float s1, float t1, float *transform, - int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, - stbir_filter h_filter, stbir_filter v_filter, - stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) -{ - ostbir__info info; - int result; - size_t memory_required; - void* extra_memory; - - STBIR_PROFILE_FIRST_START(); - - stbir__setup(&info, input_w, input_h, output_w, output_h, channels); - stbir__calculate_transform(&info, s0,t0,s1,t1,transform); - stbir__choose_filter(&info, h_filter, v_filter); - memory_required = stbir__calculate_memory(&info); - extra_memory = STBIR_MALLOC(memory_required, alloc_context); - - if (!extra_memory) - { - return 0; - } - - result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, - output_data, output_stride_in_bytes, - alpha_channel, flags, type, - edge_horizontal, edge_vertical, - colorspace, extra_memory, memory_required); - - STBIR_PROFILE_END( setup); - - STBIR_FREE(extra_memory, alloc_context); - - return result; -} - -STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); -} - -STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); -} - -STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); -} - -STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode) -{ - return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, - edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); -} - -STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, - edge_wrap_mode, edge_wrap_mode, space); -} - -STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, - edge_wrap_mode, edge_wrap_mode, space); -} - - -STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, - void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, - edge_wrap_mode, edge_wrap_mode, space); -} - - -STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, - edge_mode_horizontal, edge_mode_vertical, space); -} - - -STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float x_scale, float y_scale, - float x_offset, float y_offset) -{ - float transform[4]; - transform[0] = x_scale; - transform[1] = y_scale; - transform[2] = x_offset; - transform[3] = y_offset; - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, - edge_mode_horizontal, edge_mode_vertical, space); -} - -STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, - void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_datatype datatype, - int num_channels, int alpha_channel, int flags, - stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, - stbir_filter filter_horizontal, stbir_filter filter_vertical, - stbir_colorspace space, void *alloc_context, - float s0, float t0, float s1, float t1) -{ - return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, - output_pixels, output_w, output_h, output_stride_in_bytes, - s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, - edge_mode_horizontal, edge_mode_vertical, space); -} - -#endif // STB_IMAGE_RESIZE_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ diff --git a/source/engine/thirdparty/stb/stb_image_resize_test/oldir.c b/source/engine/thirdparty/stb/stb_image_resize_test/oldir.c deleted file mode 100644 index e1f3505..0000000 --- a/source/engine/thirdparty/stb/stb_image_resize_test/oldir.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include - -#ifdef _MSC_VER -#define stop() __debugbreak() -#else -#define stop() __builtin_trap() -#endif - -//#define HEAVYTM -#include "tm.h" - -#define STBIR_SATURATE_INT -#define STB_IMAGE_RESIZE_STATIC -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "old_image_resize.h" - - -static int types[4] = { STBIR_TYPE_UINT8, STBIR_TYPE_UINT8, STBIR_TYPE_UINT16, STBIR_TYPE_FLOAT }; -static int edges[4] = { STBIR_EDGE_CLAMP, STBIR_EDGE_REFLECT, STBIR_EDGE_ZERO, STBIR_EDGE_WRAP }; -static int flts[5] = { STBIR_FILTER_BOX, STBIR_FILTER_TRIANGLE, STBIR_FILTER_CUBICBSPLINE, STBIR_FILTER_CATMULLROM, STBIR_FILTER_MITCHELL }; -static int channels[20] = { 1, 2, 3, 4, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2 }; -static int alphapos[20] = { -1, -1, -1, -1, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0 }; - - -void oresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt ) -{ - int t = types[type]; - int ic = channels[buf]; - int alpha = alphapos[buf]; - int e = edges[edg]; - int f = flts[flt]; - int space = ( type == 1 ) ? STBIR_COLORSPACE_SRGB : 0; - int flags = ( buf >= 16 ) ? STBIR_FLAG_ALPHA_PREMULTIPLIED : ( ( buf >= 12 ) ? STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED : ( ( buf >= 8 ) ? (STBIR_FLAG_ALPHA_PREMULTIPLIED|STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED) : 0 ) ); - stbir_uint64 start; - - ENTER( "Resize (old)" ); - start = tmGetAccumulationStart( tm_mask ); - - if(!stbir_resize( i, ix, iy, ip, o, ox, oy, op, t, ic, alpha, flags, e, e, f, f, space, 0 ) ) - stop(); - - #ifdef STBIR_PROFILE - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.setup, "Setup (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.filters, "Filters (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.looping, "Looping (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.vertical, "Vertical (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.horizontal, "Horizontal (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.decode, "Scanline input (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.encode, "Scanline output (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.alpha, "Alpha weighting (old)" ); - tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.unalpha, "Alpha unweighting (old)" ); - #endif - - LEAVE(); -} diff --git a/source/engine/thirdparty/stb/stb_image_resize_test/stbirtest.c b/source/engine/thirdparty/stb/stb_image_resize_test/stbirtest.c deleted file mode 100644 index 22e1b82..0000000 --- a/source/engine/thirdparty/stb/stb_image_resize_test/stbirtest.c +++ /dev/null @@ -1,992 +0,0 @@ -#include -#include -#include - -//#define HEAVYTM -#include "tm.h" - -#ifdef RADUSETM3 -tm_api * g_tm_api; -//#define PROFILE_MODE -#endif - -#include - -#ifdef _MSC_VER -#define stop() __debugbreak() -#include -#define int64 __int64 -#define uint64 unsigned __int64 -#else -#define stop() __builtin_trap() -#define int64 long long -#define uint64 unsigned long long -#endif - -#ifdef _MSC_VER -#pragma warning(disable:4127) -#endif - -//#define NOCOMP - - -//#define PROFILE_NEW_ONLY -//#define PROFILE_MODE - - -#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ ) - -#ifdef _MSC_VER - - uint64 __rdtsc(); - #define __cycles() __rdtsc() - -#else // non msvc - - static inline uint64 __cycles() - { - unsigned int lo, hi; - asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) ); - return ( ( (uint64) hi ) << 32 ) | ( (uint64) lo ); - } - -#endif // msvc - -#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) - -#ifdef _MSC_VER - - #define __cycles() _ReadStatusReg(ARM64_CNTVCT) - -#else - - static inline uint64 __cycles() - { - uint64 tsc; - asm volatile("mrs %0, cntvct_el0" : "=r" (tsc)); - return tsc; - } - -#endif - -#else // x64, arm - -#error Unknown platform for timing. - -#endif //x64 and - - -#ifdef PROFILE_MODE - -#define STBIR_ASSERT(cond) - -#endif - -#ifdef _DEBUG -#undef STBIR_ASSERT -#define STBIR_ASSERT(cond) { if (!(cond)) stop(); } -#endif - - -#define SHRINKBYW 2 -#define ZOOMBYW 2 -#define SHRINKBYH 2 -#define ZOOMBYH 2 - - -int mem_count = 0; - -#ifdef TEST_WITH_VALLOC - -#define STBIR__SEPARATE_ALLOCATIONS - -#if TEST_WITH_LIMIT_AT_FRONT - - void * wmalloc(SIZE_T size) - { - static unsigned int pagesize=0; - void* p; - SIZE_T s; - - // get the page size, if we haven't yet - if (pagesize==0) - { - SYSTEM_INFO si; - GetSystemInfo(&si); - pagesize=si.dwPageSize; - } - - // we need room for the size, 8 bytes to hide the original pointer and a - // validation dword, and enough data to completely fill one page - s=(size+(pagesize-1))&~(pagesize-1); - - // allocate the size plus a page (for the guard) - p=VirtualAlloc(0,(SIZE_T)s,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE); - - return p; - } - - void wfree(void * ptr) - { - if (ptr) - { - if ( ((ptrdiff_t)ptr) & 4095 ) stop(); - if ( VirtualFree(ptr,0,MEM_RELEASE) == 0 ) stop(); - } - } - -#else - - void * wmalloc(SIZE_T size) - { - static unsigned int pagesize=0; - void* p; - SIZE_T s; - - // get the page size, if we haven't yet - if (pagesize==0) - { - SYSTEM_INFO si; - GetSystemInfo(&si); - pagesize=si.dwPageSize; - } - - // we need room for the size, 8 bytes to hide the original pointer and a - // validation dword, and enough data to completely fill one page - s=(size+16+(pagesize-1))&~(pagesize-1); - - // allocate the size plus a page (for the guard) - p=VirtualAlloc(0,(SIZE_T)(s+pagesize+pagesize),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE); - - if (p) - { - DWORD oldprot; - void* orig=p; - - // protect the first page - VirtualProtect(((char*)p),pagesize,PAGE_NOACCESS,&oldprot); - - // protect the final page - VirtualProtect(((char*)p)+s+pagesize,pagesize,PAGE_NOACCESS,&oldprot); - - // now move the returned pointer so that it bumps right up against the - // the next (protected) page (this may result in unaligned return - // addresses - pre-align the sizes if you always want aligned ptrs) -//#define ERROR_ON_FRONT -#ifdef ERROR_ON_FRONT - p=((char*)p)+pagesize+16; -#else - p=((char*)p)+(s-size)+pagesize; -#endif - - // hide the validation value and the original pointer (which we'll - // need used for freeing) right behind the returned pointer - ((unsigned int*)p)[-1]=0x98765432; - ((void**)p)[-2]=orig; - ++mem_count; -//printf("aloc: %p bytes: %d\n",p,(int)size); - return(p); - } - - return 0; - } - - void wfree(void * ptr) - { - if (ptr) - { - int err=0; - - // is this one of our allocations? - if (((((unsigned int*)ptr)[-1])!=0x98765432) || ((((void**)ptr)[-2])==0)) - { - err=1; - } - - if (err) - { - __debugbreak(); - } - else - { - - // back up to find the original pointer - void* p=((void**)ptr)[-2]; - - // clear the validation value and the original pointer - ((unsigned int*)ptr)[-1]=0; - ((void**)ptr)[-2]=0; - -//printf("free: %p\n",ptr); - - --mem_count; - - // now free the pages - if (p) - VirtualFree(p,0,MEM_RELEASE); - - } - } - } - -#endif - -#define STBIR_MALLOC(size,user_data) ((void)(user_data), wmalloc(size)) -#define STBIR_FREE(ptr,user_data) ((void)(user_data), wfree(ptr)) - -#endif - -#define STBIR_PROFILE -//#define STBIR_NO_SIMD -//#define STBIR_AVX -//#define STBIR_AVX2 -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "stb_image_resize2.h" // new one! - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -int tsizes[5] = { 1, 1, 2, 4, 2 }; -int ttypes[5] = { STBIR_TYPE_UINT8, STBIR_TYPE_UINT8_SRGB, STBIR_TYPE_UINT16, STBIR_TYPE_FLOAT, STBIR_TYPE_HALF_FLOAT }; - -int cedges[4] = { STBIR_EDGE_CLAMP, STBIR_EDGE_REFLECT, STBIR_EDGE_ZERO, STBIR_EDGE_WRAP }; -int flts[5] = { STBIR_FILTER_BOX, STBIR_FILTER_TRIANGLE, STBIR_FILTER_CUBICBSPLINE, STBIR_FILTER_CATMULLROM, STBIR_FILTER_MITCHELL }; -int buffers[20] = { STBIR_1CHANNEL, STBIR_2CHANNEL, STBIR_RGB, STBIR_4CHANNEL, - STBIR_BGRA, STBIR_ARGB, STBIR_RA, STBIR_AR, - STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM, - STBIR_RGBA, STBIR_ARGB, STBIR_RA, STBIR_AR, - STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM, - }; -int obuffers[20] = { STBIR_1CHANNEL, STBIR_2CHANNEL, STBIR_RGB, STBIR_4CHANNEL, - STBIR_BGRA, STBIR_ARGB, STBIR_RA, STBIR_AR, - STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM, - STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM, - STBIR_RGBA, STBIR_ARGB, STBIR_RA, STBIR_AR, - }; - -int bchannels[20] = { 1, 2, 3, 4, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2 }; -int alphapos[20] = { -1, -1, -1, -1, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0,3,0, 1,0 }; - - -char const * buffstrs[20] = { "1ch", "2ch", "3ch", "4ch", "RGBA", "ARGB", "RA", "AR", "RGBA_both_pre", "ARGB_both_pre", "RA_both_pre", "AR_both_pre", "RGBA_out_pre", "ARGB_out_pre", "RA_out_pre", "AR_out_pre", "RGBA_in_pre", "ARGB_in_pre", "RA_in_pre", "AR_in_pre" }; -char const * typestrs[5] = { "Bytes", "BytesSRGB", "Shorts", "Floats", "Half Floats"}; -char const * edgestrs[4] = { "Clamp", "Reflect", "Zero", "Wrap" }; -char const * fltstrs[5] = { "Box", "Triangle", "Cubic", "Catmullrom", "Mitchell" }; - -#ifdef STBIR_PROFILE - static void do_acc_zones( STBIR_PROFILE_INFO * profile ) - { - stbir_uint32 j; - stbir_uint64 start = tmGetAccumulationStart( tm_mask ); start=start; - - for( j = 0 ; j < profile->count ; j++ ) - { - if ( profile->clocks[j] ) - tmEmitAccumulationZone( 0, 0, (tm_uint64*)&start, 0, profile->clocks[j], profile->descriptions[j] ); - } - } -#else - #define do_acc_zones(...) -#endif - -int64 vert; - -//#define WINTHREADTEST -#ifdef WINTHREADTEST - -static STBIR_RESIZE * thread_resize; -static LONG which; -static int threads_started = 0; -static HANDLE threads[32]; -static HANDLE starts,stops; - -static DWORD resize_shim( LPVOID p ) -{ - for(;;) - { - LONG wh; - - WaitForSingleObject( starts, INFINITE ); - - wh = InterlockedAdd( &which, 1 ) - 1; - - ENTER( "Split %d", wh ); - stbir_resize_split( thread_resize, wh, 1 ); - #ifdef STBIR_PROFILE - { STBIR_PROFILE_INFO profile; stbir_resize_split_profile_info( &profile, thread_resize, wh, 1 ); do_acc_zones( &profile ); vert = profile.clocks[1]; } - #endif - LEAVE(); - - ReleaseSemaphore( stops, 1, 0 ); - } -} - -#endif - -void nresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt ) -{ - STBIR_RESIZE resize; - - stbir_resize_init( &resize, i, ix, iy, ip, o, ox, oy, op, buffers[buf], ttypes[type] ); - stbir_set_pixel_layouts( &resize, buffers[buf], obuffers[buf] ); - stbir_set_edgemodes( &resize, cedges[edg], cedges[edg] ); - stbir_set_filters( &resize, flts[flt], /*STBIR_FILTER_POINT_SAMPLE */ flts[flt] ); - //stbir_set_input_subrect( &resize, 0.55f,0.333f,0.75f,0.50f); - //stbir_set_output_pixel_subrect( &resize, 00, 00, ox/2,oy/2); - //stbir_set_pixel_subrect(&resize, 1430,1361,30,30); - - ENTER( "Resize" ); - - #ifndef WINTHREADTEST - - ENTER( "Filters" ); - stbir_build_samplers_with_splits( &resize, 1 ); - #ifdef STBIR_PROFILE - { STBIR_PROFILE_INFO profile; stbir_resize_build_profile_info( &profile, &resize ); do_acc_zones( &profile ); } - #endif - LEAVE(); - - ENTER( "Resize" ); - if(!stbir_resize_extended( &resize ) ) - stop(); - #ifdef STBIR_PROFILE - { STBIR_PROFILE_INFO profile; stbir_resize_extended_profile_info( &profile, &resize ); do_acc_zones( &profile ); vert = profile.clocks[1]; } - #endif - LEAVE(); - - #else - { - int c, cnt; - - ENTER( "Filters" ); - cnt = stbir_build_samplers_with_splits( &resize, 4 ); - #ifdef STBIR_PROFILE - { STBIR_PROFILE_INFO profile; stbir_resize_build_profile_info( &profile, &resize ); do_acc_zones( &profile ); } - #endif - LEAVE(); - - ENTER( "Thread start" ); - if ( threads_started == 0 ) - { - starts = CreateSemaphore( 0, 0, 32, 0 ); - stops = CreateSemaphore( 0, 0, 32, 0 ); - } - for( c = threads_started ; c < cnt ; c++ ) - threads[ c ] = CreateThread( 0, 2048*1024, resize_shim, 0, 0, 0 ); - - threads_started = cnt; - thread_resize = &resize; - which = 0; - LEAVE(); - - // starts the threads - ReleaseSemaphore( starts, cnt, 0 ); - - ENTER( "Wait" ); - for( c = 0 ; c < cnt; c++ ) - WaitForSingleObject( stops, INFINITE ); - LEAVE(); - } - #endif - - ENTER( "Free" ); - stbir_free_samplers( &resize ); - LEAVE(); - LEAVE(); -} - - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -extern void oresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt ); - - - -#define TYPESTART 0 -#define TYPEEND 4 - -#define LAYOUTSTART 0 -#define LAYOUTEND 19 - -#define SIZEWSTART 0 -#define SIZEWEND 2 - -#define SIZEHSTART 0 -#define SIZEHEND 2 - -#define EDGESTART 0 -#define EDGEEND 3 - -#define FILTERSTART 0 -#define FILTEREND 4 - -#define HEIGHTSTART 0 -#define HEIGHTEND 2 - -#define WIDTHSTART 0 -#define WIDTHEND 2 - - - - -static void * convert8to16( unsigned char * i, int w, int h, int c ) -{ - unsigned short * ret; - int p; - - ret = malloc( w*h*c*sizeof(short) ); - for(p = 0 ; p < (w*h*c) ; p++ ) - { - ret[p]=(short)((((int)i[p])<<8)+i[p]); - } - - return ret; -} - -static void * convert8tof( unsigned char * i, int w, int h, int c ) -{ - float * ret; - int p; - - ret = malloc( w*h*c*sizeof(float) ); - for(p = 0 ; p < (w*h*c) ; p++ ) - { - ret[p]=((float)i[p])*(1.0f/255.0f); - } - - return ret; -} - -static void * convert8tohf( unsigned char * i, int w, int h, int c ) -{ - stbir__FP16 * ret; - int p; - - ret = malloc( w*h*c*sizeof(stbir__FP16) ); - for(p = 0 ; p < (w*h*c) ; p++ ) - { - ret[p]=stbir__float_to_half(((float)i[p])*(1.0f/255.0f)); - } - - return ret; -} - -static void * convert8tohff( unsigned char * i, int w, int h, int c ) -{ - float * ret; - int p; - - ret = malloc( w*h*c*sizeof(float) ); - for(p = 0 ; p < (w*h*c) ; p++ ) - { - ret[p]=stbir__half_to_float(stbir__float_to_half(((float)i[p])*(1.0f/255.0f))); - } - - return ret; -} - -static int isprime( int v ) -{ - int i; - - if ( v <= 3 ) - return ( v > 1 ); - if ( ( v & 1 ) == 0 ) - return 0; - if ( ( v % 3 ) == 0 ) - return 0; - i = 5; - while ( (i*i) <= v ) - { - if ( ( v % i ) == 0 ) - return 0; - if ( ( v % ( i + 2 ) ) == 0 ) - return 0; - i += 6; - } - - return 1; -} - -static int getprime( int v ) -{ - int i; - i = 0; - for(;;) - { - if ( i >= v ) - return v; // can't find any, just return orig - if (isprime(v - i)) - return v - i; - if (isprime(v + i)) - return v + i; - ++i; - } -} - - -int main( int argc, char ** argv ) -{ - int ix, iy, ic; - unsigned char * input[6]; - char * ir1; - char * ir2; - int szhs[3]; - int szws[3]; - int aw, ah, ac; - unsigned char * correctalpha; - int layouts, types, heights, widths, edges, filters; - - if ( argc != 2 ) - { - printf("command: stbirtest [imagefile]\n"); - exit(1); - } - - SetupTM( "127.0.0.1" ); - - correctalpha = stbi_load( "correctalpha.png", &aw, &ah, &ac, 0 ); - - input[0] = stbi_load( argv[1], &ix, &iy, &ic, 0 ); - input[1] = input[0]; - input[2] = convert8to16( input[0], ix, iy, ic ); - input[3] = convert8tof( input[0], ix, iy, ic ); - input[4] = convert8tohf( input[0], ix, iy, ic ); - input[5] = convert8tohff( input[0], ix, iy, ic ); - - printf("Input %dx%d (%d channels)\n",ix,iy,ic); - - ir1 = malloc( 4 * 4 * 3000 * 3000ULL ); - ir2 = malloc( 4 * 4 * 3000 * 3000ULL ); - - szhs[0] = getprime( iy/SHRINKBYH ); - szhs[1] = iy; - szhs[2] = getprime( iy*ZOOMBYH ); - - szws[0] = getprime( ix/SHRINKBYW ); - szws[1] = ix; - szws[2] = getprime( ix*ZOOMBYW ); - - #if 1 - for( types = TYPESTART ; types <= TYPEEND ; types++ ) - #else - for( types = 1 ; types <= 1 ; types++ ) - #endif - { - ENTER( "Test type: %s",typestrs[types]); - #if 1 - for( layouts = LAYOUTSTART ; layouts <= LAYOUTEND ; layouts++ ) - #else - for( layouts = 16; layouts <= 16 ; layouts++ ) - #endif - { - ENTER( "Test layout: %s",buffstrs[layouts]); - - #if 0 - for( heights = HEIGHTSTART ; heights <= HEIGHTEND ; heights++ ) - { - int w, h = szhs[heights]; - #else - for( heights = 0 ; heights <= 11 ; heights++ ) - { - static int szhsz[12]={32, 200, 350, 400, 450, 509, 532, 624, 700, 824, 1023, 2053 }; - int w, h = szhsz[heights]; - #endif - - ENTER( "Test height: %d %s %d",iy,(hiy)?"Up":"Same"),h); - - #if 0 - for( widths = WIDTHSTART ; widths <= WIDTHEND ; widths++ ) - { - w = szws[widths]; - #else - for( widths = 0 ; widths <= 12 ; widths++ ) - { - static int szwsz[13]={2, 32, 200, 350, 400, 450, 509, 532, 624, 700, 824, 1023, 2053 }; - w = szwsz[widths]; - #endif - - ENTER( "Test width: %d %s %d",ix, (wix)?"Up":"Same"), w); - - #if 0 - for( edges = EDGESTART ; edges <= EDGEEND ; edges++ ) - #else - for( edges = 0 ; edges <= 0 ; edges++ ) - #endif - { - ENTER( "Test edge: %s",edgestrs[edges]); - #if 0 - for( filters = FILTERSTART ; filters <= FILTEREND ; filters++ ) - #else - for( filters = 3 ; filters <= 3 ; filters++ ) - #endif - { - int op, opw, np,npw, c, a; - #ifdef COMPARE_SAME - int oldtypes = types; - #else - int oldtypes = (types==4)?3:types; - #endif - - ENTER( "Test filter: %s",fltstrs[filters]); - { - c = bchannels[layouts]; - a = alphapos[layouts]; - - op = w*tsizes[oldtypes]*c + 60; - opw = w*tsizes[oldtypes]*c; - - np = w*tsizes[types]*c + 60; - npw = w*tsizes[types]*c; - - printf( "%s:layout: %s w: %d h: %d edge: %s filt: %s\n", typestrs[types],buffstrs[layouts], w, h, edgestrs[edges], fltstrs[filters] ); - - - // clear pixel area to different, right edge to zero - #ifndef NOCLEAR - ENTER( "Test clear padding" ); - { - int d; - for( d = 0 ; d < h ; d++ ) - { - int oofs = d * op; - int nofs = d * np; - memset( ir1 + oofs, 192, opw ); - memset( ir1 + oofs+opw, 79, op-opw ); - memset( ir2 + nofs, 255, npw ); - memset( ir2 + nofs+npw, 79, np-npw ); - } - } - LEAVE(); - - #endif - - #ifdef COMPARE_SAME - #define TIMINGS 1 - #else - #define TIMINGS 1 - #endif - ENTER( "Test both" ); - { - #ifndef PROFILE_NEW_ONLY - { - int ttt, max = 0x7fffffff; - ENTER( "Test old" ); - for( ttt = 0 ; ttt < TIMINGS ; ttt++ ) - { - int64 m = __cycles(); - - oresize( ir1, w, h, op, - #ifdef COMPARE_SAME - input[types], - #else - input[(types==4)?5:types], - #endif - ix, iy, ix*ic*tsizes[oldtypes], layouts, oldtypes, edges, filters ); - - m = __cycles() - m; - if ( ( (int)m ) < max ) - max = (int) m; - } - LEAVE(); - printf("old: %d\n", max ); - } - #endif - - { - int ttt, max = 0x7fffffff, maxv = 0x7fffffff; - ENTER( "Test new" ); - for( ttt = 0 ; ttt < TIMINGS ; ttt++ ) - { - int64 m = __cycles(); - - nresize( ir2, w, h, np, input[types], ix, iy, ix*ic*tsizes[types], layouts, types, edges, filters ); - - m = __cycles() - m; - if ( ( (int)m ) < max ) - max = (int) m; - if ( ( (int)vert ) < maxv ) - maxv = (int) vert; - } - LEAVE(); // test new - printf("new: %d (v: %d)\n", max, maxv ); - } - } - LEAVE(); // test both - - if ( mem_count!= 0 ) - stop(); - - #ifndef NOCOMP - ENTER( "Test compare" ); - { - int x,y,ch; - int nums = 0; - for( y = 0 ; y < h ; y++ ) - { - for( x = 0 ; x < w ; x++ ) - { - switch(types) - { - case 0: - case 1: //SRGB - { - unsigned char * p1 = (unsigned char *)&ir1[y*op+x*c]; - unsigned char * p2 = (unsigned char *)&ir2[y*np+x*c]; - for( ch = 0 ; ch < c ; ch++ ) - { - float pp1,pp2,d; - float av = (a==-1)?1.0f:((float)p1[a]/255.0f); - - pp1 = p1[ch]; - pp2 = p2[ch]; - - // compare in premult space - #ifndef COMPARE_SAME - if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >=16 ) && ( layouts <= 19 ) ) ) - { - pp1 *= av; - pp2 *= av; - } - #endif - - d = pp1 - pp2; - if ( d < 0 ) d = -d; - - #ifdef COMPARE_SAME - if ( d > 0 ) - #else - if ( d > 1 ) - #endif - { - printf("Error at %d x %d (chan %d) (d: %g a: %g) [%d %d %d %d] [%d %d %d %d]\n",x,y,ch, d,av, p1[0],p1[1],p1[2],p1[3], p2[0],p2[1],p2[2],p2[3]); - ++nums; - if ( nums > 16 ) goto ex; - //if (d) exit(1); - //goto ex; - } - } - } - break; - - case 2: - { - unsigned short * p1 = (unsigned short *)&ir1[y*op+x*c*sizeof(short)]; - unsigned short * p2 = (unsigned short *)&ir2[y*np+x*c*sizeof(short)]; - for( ch = 0 ; ch < c ; ch++ ) - { - float thres,pp1,pp2,d; - float av = (a==-1)?1.0f:((float)p1[a]/65535.0f); - - pp1 = p1[ch]; - pp2 = p2[ch]; - - // compare in premult space - #ifndef COMPARE_SAME - if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) ) - { - pp1 *= av; - pp2 *= av; - } - #endif - - d = pp1 - pp2; - if ( d < 0 ) d = -d; - - thres=((float)p1[ch]*0.007f)+2.0f; - if (thres<4) thres = 4; - - #ifdef COMPARE_SAME - if ( d > 0 ) - #else - if ( d > thres) - #endif - { - printf("Error at %d x %d (chan %d) %d %d [df: %g th: %g al: %g] (%d %d %d %d) (%d %d %d %d)\n",x,y,ch, p1[ch],p2[ch],d,thres,av,p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]); - ++nums; - if ( nums > 16 ) goto ex; - //if (d) exit(1); - //goto ex; - } - } - } - break; - - case 3: - { - float * p1 = (float *)&ir1[y*op+x*c*sizeof(float)]; - float * p2 = (float *)&ir2[y*np+x*c*sizeof(float)]; - for( ch = 0 ; ch < c ; ch++ ) - { - float pp1 = p1[ch], pp2 = p2[ch]; - float av = (a==-1)?1.0f:p1[a]; - float thres, d; - - // clamp - if (pp1<=0.0f) pp1 = 0; - if (pp2<=0.0f) pp2 = 0; - if (av<=0.0f) av = 0; - if (pp1>1.0f) pp1 = 1.0f; - if (pp2>1.0f) pp2 = 1.0f; - if (av>1.0f) av = 1.0f; - - // compare in premult space - #ifndef COMPARE_SAME - if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) ) - { - pp1 *= av; - pp2 *= av; - } - #endif - - d = pp1 - pp2; - if ( d < 0 ) d = -d; - - thres=(p1[ch]*0.002f)+0.0002f; - if ( thres < 0 ) thres = -thres; - - #ifdef COMPARE_SAME - if ( d != 0.0f ) - #else - if ( d > thres ) - #endif - { - printf("Error at %d x %d (chan %d) %g %g [df: %g th: %g al: %g] (%g %g %g %g) (%g %g %g %g)\n",x,y,ch, p1[ch],p2[ch],d,thres,av,p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]); - ++nums; - if ( nums > 16 ) goto ex; - //if (d) exit(1); - //goto ex; - } - } - } - break; - - case 4: - { - #ifdef COMPARE_SAME - stbir__FP16 * p1 = (stbir__FP16 *)&ir1[y*op+x*c*sizeof(stbir__FP16)]; - #else - float * p1 = (float *)&ir1[y*op+x*c*sizeof(float)]; - #endif - stbir__FP16 * p2 = (stbir__FP16 *)&ir2[y*np+x*c*sizeof(stbir__FP16)]; - for( ch = 0 ; ch < c ; ch++ ) - { - #ifdef COMPARE_SAME - float pp1 = stbir__half_to_float(p1[ch]); - float av = (a==-1)?1.0f:stbir__half_to_float(p1[a]); - #else - float pp1 = stbir__half_to_float(stbir__float_to_half(p1[ch])); - float av = (a==-1)?1.0f:stbir__half_to_float(stbir__float_to_half(p1[a])); - #endif - float pp2 = stbir__half_to_float(p2[ch]); - float d, thres; - - // clamp - if (pp1<=0.0f) pp1 = 0; - if (pp2<=0.0f) pp2 = 0; - if (av<=0.0f) av = 0; - if (pp1>1.0f) pp1 = 1.0f; - if (pp2>1.0f) pp2 = 1.0f; - if (av>1.0f) av = 1.0f; - - thres=(pp1*0.002f)+0.0002f; - - // compare in premult space - #ifndef COMPARE_SAME - if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) ) - { - pp1 *= av; - pp2 *= av; - } - #endif - - d = pp1 - pp2; - if ( d < 0 ) d = -d; - - - #ifdef COMPARE_SAME - if ( d != 0.0f ) - #else - if ( d > thres ) - #endif - { - printf("Error at %d x %d (chan %d) %g %g [df: %g th: %g al: %g] (%g %g %g %g) (%g %g %g %g)\n",x,y,ch, - #ifdef COMPARE_SAME - stbir__half_to_float(p1[ch]), - #else - p1[ch], - #endif - stbir__half_to_float(p2[ch]), - d,thres,av, - #ifdef COMPARE_SAME - stbir__half_to_float(p1[0]),stbir__half_to_float(p1[1]),stbir__half_to_float(p1[2]),stbir__half_to_float(p1[3]), - #else - p1[0],p1[1],p1[2],p1[3], - #endif - stbir__half_to_float(p2[0]),stbir__half_to_float(p2[1]),stbir__half_to_float(p2[2]),stbir__half_to_float(p2[3]) ); - ++nums; - if ( nums > 16 ) goto ex; - //if (d) exit(1); - //goto ex; - } - } - } - break; - } - } - - for( x = (w*c)*tsizes[oldtypes]; x < op; x++ ) - { - if ( ir1[y*op+x] != 79 ) - { - printf("Margin error at %d x %d %d (should be 79) OLD!\n",x,y,(unsigned char)ir1[y*op+x]); - goto ex; - } - } - - for( x = (w*c)*tsizes[types]; x < np; x++ ) - { - if ( ir2[y*np+x] != 79 ) - { - printf("Margin error at %d x %d %d (should be 79) NEW\n",x,y,(unsigned char)ir2[y*np+x]); - goto ex; - } - } - } - - ex: - ENTER( "OUTPUT IMAGES" ); - printf(" tot pix: %d, errs: %d\n", w*h*c,nums ); - - if (nums) - { - stbi_write_png("old.png", w, h, c, ir1, op); - stbi_write_png("new.png", w, h, c, ir2, np); - exit(1); - } - - LEAVE(); // output images - } - LEAVE(); //test compare - #endif - - - - } - LEAVE(); // test filter - } - LEAVE(); // test edge - } - LEAVE(); // test width - } - LEAVE(); // test height - } - LEAVE(); // test type - } - LEAVE(); // test layout - } - - CloseTM(); - return 0; -} diff --git a/source/engine/thirdparty/stb/stb_image_resize_test/vf_train.c b/source/engine/thirdparty/stb/stb_image_resize_test/vf_train.c deleted file mode 100644 index 0fdbe27..0000000 --- a/source/engine/thirdparty/stb/stb_image_resize_test/vf_train.c +++ /dev/null @@ -1,999 +0,0 @@ -#include -#include -#include - -#define stop() __debugbreak() -#include -#define int64 __int64 - -#pragma warning(disable:4127) - -#define STBIR__WEIGHT_TABLES -#define STBIR_PROFILE -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "stb_image_resize2.h" - -static int * file_read( char const * filename ) -{ - size_t s; - int * m; - FILE * f = fopen( filename, "rb" ); - if ( f == 0 ) return 0; - - fseek( f, 0, SEEK_END); - s = ftell( f ); - fseek( f, 0, SEEK_SET); - m = malloc( s + 4 ); - m[0] = (int)s; - fread( m+1, 1, s, f); - fclose(f); - - return( m ); -} - -typedef struct fileinfo -{ - int * timings; - int timing_count; - int dimensionx, dimensiony; - int numtypes; - int * types; - int * effective; - int cpu; - int simd; - int numinputrects; - int * inputrects; - int outputscalex, outputscaley; - int milliseconds; - int64 cycles; - double scale_time; - int bitmapx, bitmapy; - char const * filename; -} fileinfo; - -int numfileinfo; -fileinfo fi[256]; -unsigned char * bitmap; -int bitmapw, bitmaph, bitmapp; - -static int use_timing_file( char const * filename, int index ) -{ - int * base = file_read( filename ); - int * file = base; - - if ( base == 0 ) return 0; - - ++file; // skip file image size; - if ( *file++ != 'VFT1' ) return 0; - fi[index].cpu = *file++; - fi[index].simd = *file++; - fi[index].dimensionx = *file++; - fi[index].dimensiony = *file++; - fi[index].numtypes = *file++; - fi[index].types = file; file += fi[index].numtypes; - fi[index].effective = file; file += fi[index].numtypes; - fi[index].numinputrects = *file++; - fi[index].inputrects = file; file += fi[index].numinputrects * 2; - fi[index].outputscalex = *file++; - fi[index].outputscaley = *file++; - fi[index].milliseconds = *file++; - fi[index].cycles = ((int64*)file)[0]; file += 2; - fi[index].filename = filename; - - fi[index].timings = file; - fi[index].timing_count = (int) ( ( base[0] - ( ((char*)file - (char*)base - sizeof(int) ) ) ) / (sizeof(int)*2) ); - - fi[index].scale_time = (double)fi[index].milliseconds / (double)fi[index].cycles; - - return 1; -} - -static int vert_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int ox, int oy, int ix, int iy, int filter, STBIR__V_FIRST_INFO * v_info ) -{ - float h_scale=(float)ox/(float)(ix); - float v_scale=(float)oy/(float)(iy); - stbir__support_callback * support = stbir__builtin_supports[filter]; - int vertical_filter_width = stbir__get_filter_pixel_width(support,v_scale,0); - int vertical_gather = ( v_scale >= ( 1.0f - stbir__small_float ) ) || ( vertical_filter_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ); - - return stbir__should_do_vertical_first( weights_table, stbir__get_filter_pixel_width(support,h_scale,0), h_scale, ox, vertical_filter_width, v_scale, oy, vertical_gather, v_info ); -} - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -static void alloc_bitmap() -{ - int findex; - int x = 0, y = 0; - int w = 0, h = 0; - - for( findex = 0 ; findex < numfileinfo ; findex++ ) - { - int nx, ny; - int thisw, thish; - - thisw = ( fi[findex].dimensionx * fi[findex].numtypes ) + ( fi[findex].numtypes - 1 ); - thish = ( fi[findex].dimensiony * fi[findex].numinputrects ) + ( fi[findex].numinputrects - 1 ); - - for(;;) - { - nx = x + ((x)?4:0) + thisw; - ny = y + ((y)?4:0) + thish; - if ( ( nx <= 3600 ) || ( x == 0 ) ) - { - fi[findex].bitmapx = x + ((x)?4:0); - fi[findex].bitmapy = y + ((y)?4:0); - x = nx; - if ( x > w ) w = x; - if ( ny > h ) h = ny; - break; - } - else - { - x = 0; - y = h; - } - } - } - - w = (w+3) & ~3; - bitmapw = w; - bitmaph = h; - bitmapp = w * 3; // RGB - bitmap = malloc( bitmapp * bitmaph ); - - memset( bitmap, 0, bitmapp * bitmaph ); -} - -static void build_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index, int findex ) -{ - static int colors[STBIR_RESIZE_CLASSIFICATIONS]; - STBIR__V_FIRST_INFO v_info = {0}; - - int * ts; - int ir; - unsigned char * bitm = bitmap + ( fi[findex].bitmapx*3 ) + ( fi[findex].bitmapy*bitmapp) ; - - for( ir = 0; ir < STBIR_RESIZE_CLASSIFICATIONS ; ir++ ) colors[ ir ] = 127*ir/STBIR_RESIZE_CLASSIFICATIONS+128; - - ts = fi[findex].timings; - - for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ ) - { - int ix, iy, chanind; - ix = fi[findex].inputrects[ir*2]; - iy = fi[findex].inputrects[ir*2+1]; - - for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ ) - { - int ofs, h, hh; - - // just do the type that we're on - if ( chanind != do_channel_count_index ) - { - ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony; - continue; - } - - // bitmap offset - ofs=chanind*(fi[findex].dimensionx+1)*3+ir*(fi[findex].dimensiony+1)*bitmapp; - - h = 1; - for( hh = 0 ; hh < fi[findex].dimensiony; hh++ ) - { - int ww, w = 1; - for( ww = 0 ; ww < fi[findex].dimensionx; ww++ ) - { - int good, v_first, VF, HF; - - VF = ts[0]; - HF = ts[1]; - - v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); - - good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first))); - - if ( good ) - { - bitm[ofs+2] = 0; - bitm[ofs+1] = (unsigned char)colors[v_info.v_resize_classification]; - } - else - { - double r; - - if ( HF < VF ) - r = (double)(VF-HF)/(double)HF; - else - r = (double)(HF-VF)/(double)VF; - - if ( r > 0.4f) r = 0.4; - r *= 1.0f/0.4f; - - bitm[ofs+2] = (char)(255.0f*r); - bitm[ofs+1] = (char)(((float)colors[v_info.v_resize_classification])*(1.0f-r)); - } - bitm[ofs] = 0; - - ofs += 3; - ts += 2; - w += fi[findex].outputscalex; - } - ofs += bitmapp - fi[findex].dimensionx*3; - h += fi[findex].outputscaley; - } - } - } -} - -static void build_comp_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index ) -{ - int * ts0; - int * ts1; - int ir; - unsigned char * bitm = bitmap + ( fi[0].bitmapx*3 ) + ( fi[0].bitmapy*bitmapp) ; - - ts0 = fi[0].timings; - ts1 = fi[1].timings; - - for( ir = 0 ; ir < fi[0].numinputrects ; ir++ ) - { - int ix, iy, chanind; - ix = fi[0].inputrects[ir*2]; - iy = fi[0].inputrects[ir*2+1]; - - for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ ) - { - int ofs, h, hh; - - // just do the type that we're on - if ( chanind != do_channel_count_index ) - { - ts0 += 2 * fi[0].dimensionx * fi[0].dimensiony; - ts1 += 2 * fi[0].dimensionx * fi[0].dimensiony; - continue; - } - - // bitmap offset - ofs=chanind*(fi[0].dimensionx+1)*3+ir*(fi[0].dimensiony+1)*bitmapp; - - h = 1; - for( hh = 0 ; hh < fi[0].dimensiony; hh++ ) - { - int ww, w = 1; - for( ww = 0 ; ww < fi[0].dimensionx; ww++ ) - { - int v_first, time0, time1; - - v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, 0 ); - - time0 = ( v_first ) ? ts0[0] : ts0[1]; - time1 = ( v_first ) ? ts1[0] : ts1[1]; - - if ( time0 < time1 ) - { - double r = (double)(time1-time0)/(double)time0; - if ( r > 0.4f) r = 0.4; - r *= 1.0f/0.4f; - bitm[ofs+2] = 0; - bitm[ofs+1] = (char)(255.0f*r); - bitm[ofs] = (char)(64.0f*(1.0f-r)); - } - else - { - double r = (double)(time0-time1)/(double)time1; - if ( r > 0.4f) r = 0.4; - r *= 1.0f/0.4f; - bitm[ofs+2] = (char)(255.0f*r); - bitm[ofs+1] = 0; - bitm[ofs] = (char)(64.0f*(1.0f-r)); - } - ofs += 3; - ts0 += 2; - ts1 += 2; - w += fi[0].outputscalex; - } - ofs += bitmapp - fi[0].dimensionx*3; - h += fi[0].outputscaley; - } - } - } -} - -static void write_bitmap() -{ - stbi_write_png( "results.png", bitmapp / 3, bitmaph, 3|STB_IMAGE_BGR, bitmap, bitmapp ); -} - - -static void calc_errors( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int * curtot, double * curerr, int do_channel_count_index ) -{ - int th, findex; - STBIR__V_FIRST_INFO v_info = {0}; - - for(th=0;th 200 ) - { - int findex; - - do_bitmap: - lasttick = t; - newbest = 0; - - for( findex = 0 ; findex < numfileinfo ; findex++ ) - build_bitmap( best_output_weights, channel_count_index, findex ); - - lasttick = GetTickCount(); - } - } - } - - windowranges[ channel_count_index ] = range; - - // advance all the weights and loop - --range; - } while( ( range >= 0 ) && ( !windowstatus ) ); - - // if we hit here, then we tried all weights for this opt, so save them -} - -static void print_struct( float weight[5][STBIR_RESIZE_CLASSIFICATIONS][4], char const * name ) -{ - printf("\n\nstatic float %s[5][STBIR_RESIZE_CLASSIFICATIONS][4]=\n{", name ); - { - int i; - for(i=0;i<5;i++) - { - int th; - for(th=0;th 60000) - sprintf( time, "%dm %ds",ms/60000, (ms/1000)%60 ); - else - sprintf( time, "%ds",ms/1000 ); - return time; -} - -static BITMAPINFOHEADER bmiHeader; -static DWORD extrawindoww, extrawindowh; -static HINSTANCE instance; -static int curzoom = 1; - -static LRESULT WINAPI WindowProc( HWND window, - UINT message, - WPARAM wparam, - LPARAM lparam ) -{ - switch( message ) - { - case WM_CHAR: - if ( wparam != 27 ) - break; - // falls through - - case WM_CLOSE: - { - int i; - int max = 0; - - for( i = 0 ; i < fi[0].numtypes ; i++ ) - if( windowranges[i] > max ) max = windowranges[i]; - - if ( ( max == 0 ) || ( MessageBox( window, "Cancel before training is finished?", "Vertical First Training", MB_OKCANCEL|MB_ICONSTOP ) == IDOK ) ) - { - for( i = 0 ; i < fi[0].numtypes ; i++ ) - if( windowranges[i] > max ) max = windowranges[i]; - if ( max ) - windowstatus = 1; - DestroyWindow( window ); - } - } - return 0; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC dc; - - dc = BeginPaint( window, &ps ); - StretchDIBits( dc, - 0, 0, bitmapw*curzoom, bitmaph*curzoom, - 0, 0, bitmapw, bitmaph, - bitmap, (BITMAPINFO*)&bmiHeader, DIB_RGB_COLORS, SRCCOPY ); - - PatBlt( dc, bitmapw*curzoom, 0, 4096, 4096, WHITENESS ); - PatBlt( dc, 0, bitmaph*curzoom, 4096, 4096, WHITENESS ); - - SetTextColor( dc, RGB(0,0,0) ); - SetBkColor( dc, RGB(255,255,255) ); - SetBkMode( dc, OPAQUE ); - - { - int i, l = 0, max = 0; - char buf[1024]; - RECT rc; - POINT p; - - for( i = 0 ; i < fi[0].numtypes ; i++ ) - { - l += sprintf( buf + l, "channels: %d %s\n", fi[0].effective[i], windowranges[i] ? expand_to_string( windowranges[i] ) : "Done." ); - if ( windowranges[i] > max ) max = windowranges[i]; - } - - rc.left = 32; rc.top = bitmaph*curzoom+10; - rc.right = 512; rc.bottom = rc.top + 512; - DrawText( dc, buf, -1, &rc, DT_TOP ); - - l = 0; - if ( max == 0 ) - { - static DWORD traindone = 0; - if ( traindone == 0 ) traindone = GetTickCount(); - l = sprintf( buf, "Finished in %s.", gettime( traindone - trainstart ) ); - } - else if ( max != MAXRANGE ) - l = sprintf( buf, "Done in %s...", gettime( (int) ( ( ( (int64)max * ( (int64)GetTickCount() - (int64)trainstart ) ) ) / (int64) ( MAXRANGE - max ) ) ) ); - - GetCursorPos( &p ); - ScreenToClient( window, &p ); - - if ( ( p.x >= 0 ) && ( p.y >= 0 ) && ( p.x < (bitmapw*curzoom) ) && ( p.y < (bitmaph*curzoom) ) ) - { - int findex; - int x, y, w, h, sx, sy, ix, iy, ox, oy; - int ir, chanind; - int * ts; - char badstr[64]; - STBIR__V_FIRST_INFO v_info={0}; - - p.x /= curzoom; - p.y /= curzoom; - - for( findex = 0 ; findex < numfileinfo ; findex++ ) - { - x = fi[findex].bitmapx; - y = fi[findex].bitmapy; - w = x + ( fi[findex].dimensionx + 1 ) * fi[findex].numtypes; - h = y + ( fi[findex].dimensiony + 1 ) * fi[findex].numinputrects; - - if ( ( p.x >= x ) && ( p.y >= y ) && ( p.x < w ) && ( p.y < h ) ) - goto found; - } - goto nope; - - found: - - ir = ( p.y - y ) / ( fi[findex].dimensiony + 1 ); - sy = ( p.y - y ) % ( fi[findex].dimensiony + 1 ); - if ( sy >= fi[findex].dimensiony ) goto nope; - - chanind = ( p.x - x ) / ( fi[findex].dimensionx + 1 ); - sx = ( p.x - x ) % ( fi[findex].dimensionx + 1 ); - if ( sx >= fi[findex].dimensionx ) goto nope; - - ix = fi[findex].inputrects[ir*2]; - iy = fi[findex].inputrects[ir*2+1]; - - ts = fi[findex].timings + ( ( fi[findex].dimensionx * fi[findex].dimensiony * fi[findex].numtypes * ir ) + ( fi[findex].dimensionx * fi[findex].dimensiony * chanind ) + ( fi[findex].dimensionx * sy ) + sx ) * 2; - - ox = 1+fi[findex].outputscalex*sx; - oy = 1+fi[findex].outputscaley*sy; - - if ( windowstatus != 2 ) - { - int VF, HF, v_first, good; - VF = ts[0]; - HF = ts[1]; - - v_first = vert_first( retrain_weights[chanind], ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); - - good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first))); - - if ( good ) - badstr[0] = 0; - else - { - double r; - - if ( HF < VF ) - r = (double)(VF-HF)/(double)HF; - else - r = (double)(HF-VF)/(double)VF; - sprintf( badstr, " %.1f%% off", r*100 ); - } - sprintf( buf + l, "\n\n%s\nCh: %d Resize: %dx%d to %dx%d\nV: %d H: %d Order: %c (%s%s)\nClass: %d Scale: %.2f %s", fi[findex].filename,fi[findex].effective[chanind], ix,iy,ox,oy, VF, HF, v_first?'V':'H', good?"Good":"Wrong", badstr, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter" ); - } - else - { - int v_first, time0, time1; - float (* weights)[4] = stbir__compute_weights[chanind]; - int * ts1; - char b0[32], b1[32]; - - ts1 = fi[1].timings + ( ts - fi[0].timings ); - - v_first = vert_first( weights, ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); - - time0 = ( v_first ) ? ts[0] : ts[1]; - time1 = ( v_first ) ? ts1[0] : ts1[1]; - - b0[0] = b1[0] = 0; - if ( time0 < time1 ) - sprintf( b0," (%.f%% better)", ((double)time1-(double)time0)*100.0f/(double)time0); - else - sprintf( b1," (%.f%% better)", ((double)time0-(double)time1)*100.0f/(double)time1); - - sprintf( buf + l, "\n\n0: %s\n1: %s\nCh: %d Resize: %dx%d to %dx%d\nClass: %d Scale: %.2f %s\nTime0: %d%s\nTime1: %d%s", fi[0].filename, fi[1].filename, fi[0].effective[chanind], ix,iy,ox,oy, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter", time0, b0, time1, b1 ); - } - } - nope: - - rc.left = 32+320; rc.right = 512+320; - SetTextColor( dc, RGB(0,0,128) ); - DrawText( dc, buf, -1, &rc, DT_TOP ); - - } - EndPaint( window, &ps ); - return 0; - } - - case WM_TIMER: - InvalidateRect( window, 0, 0 ); - return 0; - - case WM_DESTROY: - PostQuitMessage( 0 ); - return 0; - } - - - return DefWindowProc( window, message, wparam, lparam ); -} - -static void SetHighDPI(void) -{ - typedef HRESULT WINAPI setdpitype(int v); - HMODULE h=LoadLibrary("Shcore.dll"); - if (h) - { - setdpitype * sd = (setdpitype*)GetProcAddress(h,"SetProcessDpiAwareness"); - if (sd ) - sd(1); - } -} - -static void draw_window() -{ - WNDCLASS wc; - HWND w; - MSG msg; - - instance = GetModuleHandle(NULL); - - wc.style = 0; - wc.lpfnWndProc = WindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = instance; - wc.hIcon = 0; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = 0; - wc.lpszMenuName = 0; - wc.lpszClassName = "WHTrain"; - - if ( !RegisterClass( &wc ) ) - exit(1); - - SetHighDPI(); - - bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmiHeader.biWidth = bitmapp/3; - bmiHeader.biHeight = -bitmaph; - bmiHeader.biPlanes = 1; - bmiHeader.biBitCount = 24; - bmiHeader.biCompression = BI_RGB; - - w = CreateWindow( "WHTrain", - "Vertical First Training", - WS_CAPTION | WS_POPUP| WS_CLIPCHILDREN | - WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX, - CW_USEDEFAULT,CW_USEDEFAULT, - CW_USEDEFAULT,CW_USEDEFAULT, - 0, 0, instance, 0 ); - - { - RECT r, c; - GetWindowRect( w, &r ); - GetClientRect( w, &c ); - extrawindoww = ( r.right - r.left ) - ( c.right - c.left ); - extrawindowh = ( r.bottom - r.top ) - ( c.bottom - c.top ); - SetWindowPos( w, 0, 0, 0, bitmapw * curzoom + extrawindoww, bitmaph * curzoom + extrawindowh + 164, SWP_NOMOVE ); - } - - ShowWindow( w, SW_SHOWNORMAL ); - SetTimer( w, 1, 250, 0 ); - - { - BOOL ret; - while( ( ret = GetMessage( &msg, w, 0, 0 ) ) != 0 ) - { - if ( ret == -1 ) - break; - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - } -} - -static void retrain() -{ - HANDLE threads[ 16 ]; - int chanind; - - trainstart = GetTickCount(); - for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ ) - threads[ chanind ] = CreateThread( 0, 2048*1024, retrain_shim, (LPVOID)(size_t)chanind, 0, 0 ); - - draw_window(); - - for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ ) - { - WaitForSingleObject( threads[ chanind ], INFINITE ); - CloseHandle( threads[ chanind ] ); - } - - write_bitmap(); - - print_struct( retrain_weights, "retained_weights" ); - if ( windowstatus ) printf( "CANCELLED!\n" ); -} - -static void info() -{ - int findex; - - // display info about each input file - for( findex = 0 ; findex < numfileinfo ; findex++ ) - { - int i, h,m,s; - if ( findex ) printf( "\n" ); - printf( "Timing file: %s\n", fi[findex].filename ); - printf( "CPU type: %d %s\n", fi[findex].cpu, fi[findex].simd?(fi[findex].simd==2?"SIMD8":"SIMD4"):"Scalar" ); - h = fi[findex].milliseconds/3600000; - m = (fi[findex].milliseconds-h*3600000)/60000; - s = (fi[findex].milliseconds-h*3600000-m*60000)/1000; - printf( "Total time in test: %dh %dm %ds Cycles/sec: %.f\n", h,m,s, 1000.0/fi[findex].scale_time ); - printf( "Each tile of samples is %dx%d, and is scaled by %dx%d.\n", fi[findex].dimensionx,fi[findex].dimensiony, fi[findex].outputscalex,fi[findex].outputscaley ); - printf( "So the x coords are: " ); - for( i=0; i < fi[findex].dimensionx ; i++ ) printf( "%d ",1+i*fi[findex].outputscalex ); - printf( "\n" ); - printf( "And the y coords are: " ); - for( i=0; i < fi[findex].dimensiony ; i++ ) printf( "%d ",1+i*fi[findex].outputscaley ); - printf( "\n" ); - printf( "There are %d channel counts and they are: ", fi[findex].numtypes ); - for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%d ",fi[findex].effective[i] ); - printf( "\n" ); - printf( "There are %d input rect sizes and they are: ", fi[findex].numinputrects ); - for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%dx%d ",fi[findex].inputrects[i*2],fi[findex].inputrects[i*2+1] ); - printf( "\n" ); - } -} - -static void current( int do_win, int do_bitmap ) -{ - int i, findex; - - trainstart = GetTickCount(); - - // clear progress - memset( windowranges, 0, sizeof( windowranges ) ); - // copy in appropriate weights - memcpy( retrain_weights, stbir__compute_weights, sizeof( retrain_weights ) ); - - // build and print current errors and build current bitmap - for( i = 0 ; i < fi[0].numtypes ; i++ ) - { - double curerr[STBIR_RESIZE_CLASSIFICATIONS]; - int curtot[STBIR_RESIZE_CLASSIFICATIONS]; - float (* weights)[4] = retrain_weights[i]; - - calc_errors( weights, curtot, curerr, i ); - if ( !do_bitmap ) - print_weights( weights, i, curtot, curerr ); - - for( findex = 0 ; findex < numfileinfo ; findex++ ) - build_bitmap( weights, i, findex ); - } - - if ( do_win ) - draw_window(); - - if ( do_bitmap ) - write_bitmap(); -} - -static void compare() -{ - int i; - - trainstart = GetTickCount(); - windowstatus = 2; // comp mode - - // clear progress - memset( windowranges, 0, sizeof( windowranges ) ); - - if ( ( fi[0].numtypes != fi[1].numtypes ) || ( fi[0].numinputrects != fi[1].numinputrects ) || - ( fi[0].dimensionx != fi[1].dimensionx ) || ( fi[0].dimensiony != fi[1].dimensiony ) || - ( fi[0].outputscalex != fi[1].outputscalex ) || ( fi[0].outputscaley != fi[1].outputscaley ) ) - { - err: - printf( "Timing files don't match.\n" ); - exit(5); - } - - for( i=0; i < fi[0].numtypes ; i++ ) - { - if ( fi[0].effective[i] != fi[1].effective[i] ) goto err; - if ( fi[0].inputrects[i*2] != fi[1].inputrects[i*2] ) goto err; - if ( fi[0].inputrects[i*2+1] != fi[1].inputrects[i*2+1] ) goto err; - } - - alloc_bitmap( 1 ); - - for( i = 0 ; i < fi[0].numtypes ; i++ ) - { - float (* weights)[4] = stbir__compute_weights[i]; - build_comp_bitmap( weights, i ); - } - - draw_window(); -} - -static void load_files( char ** args, int count ) -{ - int i; - - if ( count == 0 ) - { - printf( "No timing files listed!" ); - exit(3); - } - - for ( i = 0 ; i < count ; i++ ) - { - if ( !use_timing_file( args[i], i ) ) - { - printf( "Bad timing file %s\n", args[i] ); - exit(2); - } - } - numfileinfo = count; -} - -int main( int argc, char ** argv ) -{ - int check; - if ( argc < 3 ) - { - err: - printf( "vf_train retrain [timing_filenames....] - recalcs weights for all the files on the command line.\n"); - printf( "vf_train info [timing_filenames....] - shows info about each timing file.\n"); - printf( "vf_train check [timing_filenames...] - show results for the current weights for all files listed.\n"); - printf( "vf_train compare - compare two timing files (must only be two files and same resolution).\n"); - printf( "vf_train bitmap [timing_filenames...] - write out results.png, comparing against the current weights for all files listed.\n"); - exit(1); - } - - check = ( strcmp( argv[1], "check" ) == 0 ); - if ( ( check ) || ( strcmp( argv[1], "bitmap" ) == 0 ) ) - { - load_files( argv + 2, argc - 2 ); - alloc_bitmap( numfileinfo ); - current( check, !check ); - } - else if ( strcmp( argv[1], "info" ) == 0 ) - { - load_files( argv + 2, argc - 2 ); - info(); - } - else if ( strcmp( argv[1], "compare" ) == 0 ) - { - if ( argc != 4 ) - { - printf( "You must specify two files to compare.\n" ); - exit(4); - } - - load_files( argv + 2, argc - 2 ); - compare(); - } - else if ( strcmp( argv[1], "retrain" ) == 0 ) - { - load_files( argv + 2, argc - 2 ); - alloc_bitmap( numfileinfo ); - retrain(); - } - else - { - goto err; - } - - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/Makefile b/source/engine/thirdparty/stb/tests/Makefile deleted file mode 100644 index 1782ea6..0000000 --- a/source/engine/thirdparty/stb/tests/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -INCLUDES = -I.. -CFLAGS = -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DSTB_DIVIDE_TEST -CPPFLAGS = -Wno-write-strings -DSTB_DIVIDE_TEST - -# Uncomment this line for reproducing OSS-Fuzz bugs with image_fuzzer -#CFLAGS += -O -fsanitize=address - -all: - $(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c test_c_lexer.c test_dxt.c test_easyfont.c test_image.c test_image_write.c test_perlin.c test_sprintf.c test_truetype.c test_voxel.c -lm - $(CC) $(INCLUDES) $(CPPFLAGS) -std=c++0x test_cpp_compilation.cpp -lm -lstdc++ - $(CC) $(INCLUDES) $(CFLAGS) -DIWT_TEST image_write_test.c -lm -o image_write_test - $(CC) $(INCLUDES) $(CFLAGS) fuzz_main.c stbi_read_fuzzer.c -lm -o image_fuzzer diff --git a/source/engine/thirdparty/stb/tests/c_lexer_test.c b/source/engine/thirdparty/stb/tests/c_lexer_test.c deleted file mode 100644 index a919b6c..0000000 --- a/source/engine/thirdparty/stb/tests/c_lexer_test.c +++ /dev/null @@ -1,50 +0,0 @@ -#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit -#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit -#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit -#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit -#define STB_C_LEX_C99_HEX_FLOATS Y // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit -#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id -#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring -#define STB_C_LEX_C_SQ_STRINGS Y // single-quote-delimited strings with escapes CLEX_ssstring -#define STB_C_LEX_C_CHARS Y // single-quote-delimited character with escape CLEX_charlits -#define STB_C_LEX_C_COMMENTS Y // "/* comment */" -#define STB_C_LEX_CPP_COMMENTS Y // "// comment to end of line\n" -#define STB_C_LEX_C_COMPARISONS Y // "==" CLEX_eq "!=" CLEX_noteq "<=" CLEX_lesseq ">=" CLEX_greatereq -#define STB_C_LEX_C_LOGICAL Y // "&&" CLEX_andand "||" CLEX_oror -#define STB_C_LEX_C_SHIFTS Y // "<<" CLEX_shl ">>" CLEX_shr -#define STB_C_LEX_C_INCREMENTS Y // "++" CLEX_plusplus "--" CLEX_minusminus -#define STB_C_LEX_C_ARROW Y // "->" CLEX_arrow -#define STB_C_LEX_EQUAL_ARROW Y // "=>" CLEX_eqarrow -#define STB_C_LEX_C_BITWISEEQ Y // "&=" CLEX_andeq "|=" CLEX_oreq "^=" CLEX_xoreq -#define STB_C_LEX_C_ARITHEQ Y // "+=" CLEX_pluseq "-=" CLEX_minuseq - // "*=" CLEX_muleq "/=" CLEX_diveq "%=" CLEX_modeq - // if both STB_C_LEX_SHIFTS & STB_C_LEX_ARITHEQ: - // "<<=" CLEX_shleq ">>=" CLEX_shreq - -#define STB_C_LEX_PARSE_SUFFIXES Y // letters after numbers are parsed as part of those numbers, and must be in suffix list below -#define STB_C_LEX_DECIMAL_SUFFIXES "uUlL" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage -#define STB_C_LEX_HEX_SUFFIXES "lL" // e.g. "uUlL" -#define STB_C_LEX_OCTAL_SUFFIXES "lL" // e.g. "uUlL" -#define STB_C_LEX_FLOAT_SUFFIXES "uulL" // - -#define STB_C_LEX_0_IS_EOF N // if Y, ends parsing at '\0'; if N, returns '\0' as token -#define STB_C_LEX_INTEGERS_AS_DOUBLES N // parses integers as doubles so they can be larger than 'int', but only if STB_C_LEX_STDLIB==N -#define STB_C_LEX_MULTILINE_DSTRINGS Y // allow newlines in double-quoted strings -#define STB_C_LEX_MULTILINE_SSTRINGS Y // allow newlines in single-quoted strings -#define STB_C_LEX_USE_STDLIB N // use strtod,strtol for parsing #s; otherwise inaccurate hack -#define STB_C_LEX_DOLLAR_IDENTIFIER Y // allow $ as an identifier character -#define STB_C_LEX_FLOAT_NO_DECIMAL Y // allow floats that have no decimal point if they have an exponent - -#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES Y // if Y, all CLEX_ token names are defined, even if never returned - // leaving it as N should help you catch config bugs - -#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess - // still have #line, #pragma, etc) - -#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions - - - -#define STB_C_LEXER_IMPLEMENTATION -#define STB_C_LEXER_SELF_TEST -#include "../stb_c_lexer.h" diff --git a/source/engine/thirdparty/stb/tests/c_lexer_test.dsp b/source/engine/thirdparty/stb/tests/c_lexer_test.dsp deleted file mode 100644 index 13f8758..0000000 --- a/source/engine/thirdparty/stb/tests/c_lexer_test.dsp +++ /dev/null @@ -1,89 +0,0 @@ -# Microsoft Developer Studio Project File - Name="c_lexer_test" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=c_lexer_test - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "c_lexer_test.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "c_lexer_test.mak" CFG="c_lexer_test - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "c_lexer_test - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "c_lexer_test - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "c_lexer_test - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "c_lexer_test - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug\c_lexer_test" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "c_lexer_test - Win32 Release" -# Name "c_lexer_test - Win32 Debug" -# Begin Source File - -SOURCE=.\c_lexer_test.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/caveview/README.md b/source/engine/thirdparty/stb/tests/caveview/README.md deleted file mode 100644 index 10da838..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# FAQ - -### How to run it? - -There's no GUI. Find a directory with Minecraft Anvil files (.mca). -Copy a Minecraft "terrain.png" into that directory (do a google -image search). Run from that directory. - -### How accurate is this as a Minecraft viewer? - -Not very. Many Minecraft blocks are not handled correctly: - -* No redstone, rails, or other "flat" blocks -* No signs, doors, fences, carpets, or other complicated geometry -* Stairs are turned into ramps -* Upper slabs turn into lower slabs -* Wood types only for blocks, not stairs, slabs, etc -* Colored glass becomes regular glass -* Glass panes become glass blocks -* Water is opaque -* Water level is incorrect -* No biome coloration -* Cactus is not shrunk, shows holes -* Chests are not shrunk -* Double-chests draw as two chests -* Pumpkins etc. are not rotated properly -* Torches are drawn hackily, do not attach to walls -* Incorrect textures for blocks that postdate terrain.png -* Transparent textures have black fringes due to non-premultiplied-alpha -* Skylight and block light are combined in a single value -* Only blocks at y=1..255 are shown (not y=0) -* If a 32x32x256 "quad-chunk" needs more than 800K quads, isn't handled (very unlikely) - -Some of these are due to engine limitations, and some of -these are because I didn't make the effort since my -goal was to make a demo for stb_voxel_render.h, not -to make a proper Minecraft viewer. - - -### Could this be turned into a proper Minecraft viewer? - -Yes and no. Yes, you could do it, but no, it wouldn't -really resemble this code that much anymore. - -You could certainly use this engine to -render the parts of Minecraft it works for, but many -of the things it doesn't handle it can't handle at all -(stairs, water, fences, carpets, etc) because it uses -low-precision coordinates to store voxel data. - -You would have to render all of the stuff it doesn't -handle through another rendering path. In a game (not -a viewer) you would need such a path for movable entities -like doors and carts anyway, so possibly handling other -things that way wouldn't be so bad. - -Rails, ladders, and redstone lines could be implemented by -using tex2 to overlay those effects, but you can't rotate -tex1 and tex2 independently, so there may be cases where -the underlying texture needs a different rotation from the -overlaid texture, which would require separate rendering. -Handling redstone's brightness being different from underlying -block's brightness would require separate rendering. - -You can use the face-color effect to do biome coloration, -but the change won't be smooth the way it is in Minecraft. - - -### Why isn't building the mesh data faster? - -Partly because converting from minecraft data is expensive. - -Here is the approximate breakdown of an older version -of this executable and lib that did the building single-threaded. - -* 25% loading & parsing minecraft files (4/5ths of this is my crappy zlib) -* 18% converting from minecraft blockids & lighting to stb blockids & lighting -* 10% reordering from data[z][y]\[x] (minecraft-style) to data[y][x]\[z] (stb-style) -* 40% building mesh data -* 7% uploading mesh data to OpenGL - -I did do significant optimizations after the above, so the -final breakdown is different, but it should give you some -sense of the costs. - diff --git a/source/engine/thirdparty/stb/tests/caveview/cave_main.c b/source/engine/thirdparty/stb/tests/caveview/cave_main.c deleted file mode 100644 index d345cf1..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/cave_main.c +++ /dev/null @@ -1,598 +0,0 @@ -#define _WIN32_WINNT 0x400 - -#include -#include - -// stb.h -#define STB_DEFINE -#include "stb.h" - -// stb_gl.h -#define STB_GL_IMPLEMENTATION -#define STB_GLEXT_DEFINE "glext_list.h" -#include "stb_gl.h" - -// SDL -#include "sdl.h" -#include "SDL_opengl.h" - -// stb_glprog.h -#define STB_GLPROG_IMPLEMENTATION -#define STB_GLPROG_ARB_DEFINE_EXTENSIONS -#include "stb_glprog.h" - -// stb_image.h -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -// stb_easy_font.h -#include "stb_easy_font.h" // doesn't require an IMPLEMENTATION - -#include "caveview.h" - -char *game_name = "caveview"; - - -#define REVERSE_DEPTH - - - -static void print_string(float x, float y, char *text, float r, float g, float b) -{ - static char buffer[99999]; - int num_quads; - - num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer)); - - glColor3f(r,g,b); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 16, buffer); - glDrawArrays(GL_QUADS, 0, num_quads*4); - glDisableClientState(GL_VERTEX_ARRAY); -} - -static float text_color[3]; -static float pos_x = 10; -static float pos_y = 10; - -static void print(char *text, ...) -{ - char buffer[999]; - va_list va; - va_start(va, text); - vsprintf(buffer, text, va); - va_end(va); - print_string(pos_x, pos_y, buffer, text_color[0], text_color[1], text_color[2]); - pos_y += 10; -} - -float camang[3], camloc[3] = { 60,22,77 }; -float player_zoom = 1.0; -float rotate_view = 0.0; - - -void camera_to_worldspace(float world[3], float cam_x, float cam_y, float cam_z) -{ - float vec[3] = { cam_x, cam_y, cam_z }; - float t[3]; - float s,c; - s = (float) sin(camang[0]*3.141592/180); - c = (float) cos(camang[0]*3.141592/180); - - t[0] = vec[0]; - t[1] = c*vec[1] - s*vec[2]; - t[2] = s*vec[1] + c*vec[2]; - - s = (float) sin(camang[2]*3.141592/180); - c = (float) cos(camang[2]*3.141592/180); - world[0] = c*t[0] - s*t[1]; - world[1] = s*t[0] + c*t[1]; - world[2] = t[2]; -} - -// camera worldspace velocity -float cam_vel[3]; - -int controls; - -#define MAX_VEL 150.0f // blocks per second -#define ACCEL 6.0f -#define DECEL 3.0f - -#define STATIC_FRICTION DECEL -#define EFFECTIVE_ACCEL (ACCEL+DECEL) - -// dynamic friction: -// -// if going at MAX_VEL, ACCEL and friction must cancel -// EFFECTIVE_ACCEL = DECEL + DYNAMIC_FRIC*MAX_VEL -#define DYNAMIC_FRICTION (ACCEL/(float)MAX_VEL) - -float view_x_vel = 0; -float view_z_vel = 0; -float pending_view_x; -float pending_view_z; -float pending_view_x; -float pending_view_z; - -void process_tick_raw(float dt) -{ - int i; - float thrust[3] = { 0,0,0 }; - float world_thrust[3]; - - // choose direction to apply thrust - - thrust[0] = (controls & 3)== 1 ? EFFECTIVE_ACCEL : (controls & 3)== 2 ? -EFFECTIVE_ACCEL : 0; - thrust[1] = (controls & 12)== 4 ? EFFECTIVE_ACCEL : (controls & 12)== 8 ? -EFFECTIVE_ACCEL : 0; - thrust[2] = (controls & 48)==16 ? EFFECTIVE_ACCEL : (controls & 48)==32 ? -EFFECTIVE_ACCEL : 0; - - // @TODO clamp thrust[0] & thrust[1] vector length to EFFECTIVE_ACCEL - - camera_to_worldspace(world_thrust, thrust[0], thrust[1], 0); - world_thrust[2] += thrust[2]; - - for (i=0; i < 3; ++i) { - float acc = world_thrust[i]; - cam_vel[i] += acc*dt; - } - - if (cam_vel[0] || cam_vel[1] || cam_vel[2]) - { - float vel = (float) sqrt(cam_vel[0]*cam_vel[0] + cam_vel[1]*cam_vel[1] + cam_vel[2]*cam_vel[2]); - float newvel = vel; - float dec = STATIC_FRICTION + DYNAMIC_FRICTION*vel; - newvel = vel - dec*dt; - if (newvel < 0) - newvel = 0; - cam_vel[0] *= newvel/vel; - cam_vel[1] *= newvel/vel; - cam_vel[2] *= newvel/vel; - } - - camloc[0] += cam_vel[0] * dt; - camloc[1] += cam_vel[1] * dt; - camloc[2] += cam_vel[2] * dt; - - view_x_vel *= (float) pow(0.75, dt); - view_z_vel *= (float) pow(0.75, dt); - - view_x_vel += (pending_view_x - view_x_vel)*dt*60; - view_z_vel += (pending_view_z - view_z_vel)*dt*60; - - pending_view_x -= view_x_vel * dt; - pending_view_z -= view_z_vel * dt; - camang[0] += view_x_vel * dt; - camang[2] += view_z_vel * dt; - camang[0] = stb_clamp(camang[0], -90, 90); - camang[2] = (float) fmod(camang[2], 360); -} - -void process_tick(float dt) -{ - while (dt > 1.0f/60) { - process_tick_raw(1.0f/60); - dt -= 1.0f/60; - } - process_tick_raw(dt); -} - -void update_view(float dx, float dy) -{ - // hard-coded mouse sensitivity, not resolution independent? - pending_view_z -= dx*300; - pending_view_x -= dy*700; -} - -extern int screen_x, screen_y; -extern int is_synchronous_debug; -float render_time; - -extern int chunk_locations, chunks_considered, chunks_in_frustum; -extern int quads_considered, quads_rendered; -extern int chunk_storage_rendered, chunk_storage_considered, chunk_storage_total; -extern int view_dist_in_chunks; -extern int num_threads_active, num_meshes_started, num_meshes_uploaded; -extern float chunk_server_activity; - -static Uint64 start_time, end_time; // render time - -float chunk_server_status[32]; -int chunk_server_pos; - -void draw_stats(void) -{ - int i; - - static Uint64 last_frame_time; - Uint64 cur_time = SDL_GetPerformanceCounter(); - float chunk_server=0; - float frame_time = (cur_time - last_frame_time) / (float) SDL_GetPerformanceFrequency(); - last_frame_time = cur_time; - - chunk_server_status[chunk_server_pos] = chunk_server_activity; - chunk_server_pos = (chunk_server_pos+1) %32; - - for (i=0; i < 32; ++i) - chunk_server += chunk_server_status[i] / 32.0f; - - stb_easy_font_spacing(-0.75); - pos_y = 10; - text_color[0] = text_color[1] = text_color[2] = 1.0f; - print("Frame time: %6.2fms, CPU frame render time: %5.2fms", frame_time*1000, render_time*1000); - print("Tris: %4.1fM drawn of %4.1fM in range", 2*quads_rendered/1000000.0f, 2*quads_considered/1000000.0f); - print("Vbuf storage: %dMB in frustum of %dMB in range of %dMB in cache", chunk_storage_rendered>>20, chunk_storage_considered>>20, chunk_storage_total>>20); - print("Num mesh builds started this frame: %d; num uploaded this frame: %d\n", num_meshes_started, num_meshes_uploaded); - print("QChunks: %3d in frustum of %3d valid of %3d in range", chunks_in_frustum, chunks_considered, chunk_locations); - print("Mesh worker threads active: %d", num_threads_active); - print("View distance: %d blocks", view_dist_in_chunks*16); - print("%s", glGetString(GL_RENDERER)); - - if (is_synchronous_debug) { - text_color[0] = 1.0; - text_color[1] = 0.5; - text_color[2] = 0.5; - print("SLOWNESS: Synchronous debug output is enabled!"); - } -} - -void draw_main(void) -{ - glEnable(GL_CULL_FACE); - glDisable(GL_TEXTURE_2D); - glDisable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); - #ifdef REVERSE_DEPTH - glDepthFunc(GL_GREATER); - glClearDepth(0); - #else - glDepthFunc(GL_LESS); - glClearDepth(1); - #endif - glDepthMask(GL_TRUE); - glDisable(GL_SCISSOR_TEST); - glClearColor(0.6f,0.7f,0.9f,0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor3f(1,1,1); - glFrontFace(GL_CW); - glEnable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - #ifdef REVERSE_DEPTH - stbgl_Perspective(player_zoom, 90, 70, 3000, 1.0/16); - #else - stbgl_Perspective(player_zoom, 90, 70, 1.0/16, 3000); - #endif - - // now compute where the camera should be - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - stbgl_initCamera_zup_facing_y(); - - glRotatef(-camang[0],1,0,0); - glRotatef(-camang[2],0,0,1); - glTranslatef(-camloc[0], -camloc[1], -camloc[2]); - - start_time = SDL_GetPerformanceCounter(); - render_caves(camloc); - end_time = SDL_GetPerformanceCounter(); - - render_time = (end_time - start_time) / (float) SDL_GetPerformanceFrequency(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(0,screen_x/2,screen_y/2,0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); - draw_stats(); -} - - - -#pragma warning(disable:4244; disable:4305; disable:4018) - -#define SCALE 2 - -void error(char *s) -{ - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", s, NULL); - exit(0); -} - -void ods(char *fmt, ...) -{ - char buffer[1000]; - va_list va; - va_start(va, fmt); - vsprintf(buffer, fmt, va); - va_end(va); - SDL_Log("%s", buffer); -} - -#define TICKS_PER_SECOND 60 - -static SDL_Window *window; - -extern void draw_main(void); -extern void process_tick(float dt); -extern void editor_init(void); - -void draw(void) -{ - draw_main(); - SDL_GL_SwapWindow(window); -} - - -static int initialized=0; -static float last_dt; - -int screen_x,screen_y; - -float carried_dt = 0; -#define TICKRATE 60 - -float tex2_alpha = 1.0; - -int raw_level_time; - -float global_timer; -int global_hack; - -int loopmode(float dt, int real, int in_client) -{ - if (!initialized) return 0; - - if (!real) - return 0; - - // don't allow more than 6 frames to update at a time - if (dt > 0.075) dt = 0.075; - - global_timer += dt; - - carried_dt += dt; - while (carried_dt > 1.0/TICKRATE) { - if (global_hack) { - tex2_alpha += global_hack / 60.0f; - if (tex2_alpha < 0) tex2_alpha = 0; - if (tex2_alpha > 1) tex2_alpha = 1; - } - //update_input(); - // if the player is dead, stop the sim - carried_dt -= 1.0/TICKRATE; - } - - process_tick(dt); - draw(); - - return 0; -} - -static int quit; - -extern int controls; - -void active_control_set(int key) -{ - controls |= 1 << key; -} - -void active_control_clear(int key) -{ - controls &= ~(1 << key); -} - -extern void update_view(float dx, float dy); - -void process_sdl_mouse(SDL_Event *e) -{ - update_view((float) e->motion.xrel / screen_x, (float) e->motion.yrel / screen_y); -} - -void process_event(SDL_Event *e) -{ - switch (e->type) { - case SDL_MOUSEMOTION: - process_sdl_mouse(e); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - break; - - case SDL_QUIT: - quit = 1; - break; - - case SDL_WINDOWEVENT: - switch (e->window.event) { - case SDL_WINDOWEVENT_SIZE_CHANGED: - screen_x = e->window.data1; - screen_y = e->window.data2; - loopmode(0,1,0); - break; - } - break; - - case SDL_KEYDOWN: { - int k = e->key.keysym.sym; - int s = e->key.keysym.scancode; - SDL_Keymod mod; - mod = SDL_GetModState(); - if (k == SDLK_ESCAPE) - quit = 1; - - if (s == SDL_SCANCODE_D) active_control_set(0); - if (s == SDL_SCANCODE_A) active_control_set(1); - if (s == SDL_SCANCODE_W) active_control_set(2); - if (s == SDL_SCANCODE_S) active_control_set(3); - if (k == SDLK_SPACE) active_control_set(4); - if (s == SDL_SCANCODE_LCTRL) active_control_set(5); - if (s == SDL_SCANCODE_S) active_control_set(6); - if (s == SDL_SCANCODE_D) active_control_set(7); - if (k == '1') global_hack = !global_hack; - if (k == '2') global_hack = -1; - - #if 0 - if (game_mode == GAME_editor) { - switch (k) { - case SDLK_RIGHT: editor_key(STBTE_scroll_right); break; - case SDLK_LEFT : editor_key(STBTE_scroll_left ); break; - case SDLK_UP : editor_key(STBTE_scroll_up ); break; - case SDLK_DOWN : editor_key(STBTE_scroll_down ); break; - } - switch (s) { - case SDL_SCANCODE_S: editor_key(STBTE_tool_select); break; - case SDL_SCANCODE_B: editor_key(STBTE_tool_brush ); break; - case SDL_SCANCODE_E: editor_key(STBTE_tool_erase ); break; - case SDL_SCANCODE_R: editor_key(STBTE_tool_rectangle ); break; - case SDL_SCANCODE_I: editor_key(STBTE_tool_eyedropper); break; - case SDL_SCANCODE_L: editor_key(STBTE_tool_link); break; - case SDL_SCANCODE_G: editor_key(STBTE_act_toggle_grid); break; - } - if ((e->key.keysym.mod & KMOD_CTRL) && !(e->key.keysym.mod & ~KMOD_CTRL)) { - switch (s) { - case SDL_SCANCODE_X: editor_key(STBTE_act_cut ); break; - case SDL_SCANCODE_C: editor_key(STBTE_act_copy ); break; - case SDL_SCANCODE_V: editor_key(STBTE_act_paste); break; - case SDL_SCANCODE_Z: editor_key(STBTE_act_undo ); break; - case SDL_SCANCODE_Y: editor_key(STBTE_act_redo ); break; - } - } - } - #endif - break; - } - case SDL_KEYUP: { - int k = e->key.keysym.sym; - int s = e->key.keysym.scancode; - if (s == SDL_SCANCODE_D) active_control_clear(0); - if (s == SDL_SCANCODE_A) active_control_clear(1); - if (s == SDL_SCANCODE_W) active_control_clear(2); - if (s == SDL_SCANCODE_S) active_control_clear(3); - if (k == SDLK_SPACE) active_control_clear(4); - if (s == SDL_SCANCODE_LCTRL) active_control_clear(5); - if (s == SDL_SCANCODE_S) active_control_clear(6); - if (s == SDL_SCANCODE_D) active_control_clear(7); - break; - } - } -} - -static SDL_GLContext *context; - -static float getTimestep(float minimum_time) -{ - float elapsedTime; - double thisTime; - static double lastTime = -1; - - if (lastTime == -1) - lastTime = SDL_GetTicks() / 1000.0 - minimum_time; - - for(;;) { - thisTime = SDL_GetTicks() / 1000.0; - elapsedTime = (float) (thisTime - lastTime); - if (elapsedTime >= minimum_time) { - lastTime = thisTime; - return elapsedTime; - } - // @TODO: compute correct delay - SDL_Delay(1); - } -} - -void APIENTRY gl_debug(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *param) -{ - ods("%s\n", message); -} - -int is_synchronous_debug; -void enable_synchronous(void) -{ - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - is_synchronous_debug = 1; -} - -void prepare_threads(void); - -//void stbwingraph_main(void) -int SDL_main(int argc, char **argv) -{ - SDL_Init(SDL_INIT_VIDEO); - - prepare_threads(); - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE , 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE , 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - - #ifdef GL_DEBUG - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); - #endif - - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); - - screen_x = 1920; - screen_y = 1080; - - window = SDL_CreateWindow("caveview", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - screen_x, screen_y, - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE - ); - if (!window) error("Couldn't create window"); - - context = SDL_GL_CreateContext(window); - if (!context) error("Couldn't create context"); - - SDL_GL_MakeCurrent(window, context); // is this true by default? - - SDL_SetRelativeMouseMode(SDL_TRUE); - #if defined(_MSC_VER) && _MSC_VER < 1300 - // work around broken behavior in VC6 debugging - if (IsDebuggerPresent()) - SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); - #endif - - stbgl_initExtensions(); - - #ifdef GL_DEBUG - if (glDebugMessageCallbackARB) { - glDebugMessageCallbackARB(gl_debug, NULL); - - enable_synchronous(); - } - #endif - - SDL_GL_SetSwapInterval(1); - - render_init(); - mesh_init(); - world_init(); - - initialized = 1; - - while (!quit) { - SDL_Event e; - while (SDL_PollEvent(&e)) - process_event(&e); - - loopmode(getTimestep(0.0166f/8), 1, 1); - } - - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/caveview/cave_mesher.c b/source/engine/thirdparty/stb/tests/caveview/cave_mesher.c deleted file mode 100644 index 1f76c89..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/cave_mesher.c +++ /dev/null @@ -1,933 +0,0 @@ -// This file takes minecraft chunks (decoded by cave_parse) and -// uses stb_voxel_render to turn them into vertex buffers. - -#define STB_GLEXT_DECLARE "glext_list.h" -#include "stb_gl.h" -#include "stb_image.h" -#include "stb_glprog.h" - -#include "caveview.h" -#include "cave_parse.h" -#include "stb.h" -#include "sdl.h" -#include "sdl_thread.h" -#include - -//#define VHEIGHT_TEST -//#define STBVOX_OPTIMIZED_VHEIGHT - -#define STBVOX_CONFIG_MODE 1 -#define STBVOX_CONFIG_OPENGL_MODELVIEW -#define STBVOX_CONFIG_PREFER_TEXBUFFER -//#define STBVOX_CONFIG_LIGHTING_SIMPLE -#define STBVOX_CONFIG_FOG_SMOOTHSTEP -//#define STBVOX_CONFIG_PREMULTIPLIED_ALPHA // this doesn't work properly alpha test without next #define -//#define STBVOX_CONFIG_UNPREMULTIPLY // slower, fixes alpha test makes windows & fancy leaves look better -//#define STBVOX_CONFIG_TEX1_EDGE_CLAMP -#define STBVOX_CONFIG_DISABLE_TEX2 -//#define STBVOX_CONFIG_DOWN_TEXLERP_PACKED -#define STBVOX_CONFIG_ROTATION_IN_LIGHTING - -#define STB_VOXEL_RENDER_IMPLEMENTATION -#include "stb_voxel_render.h" - -extern void ods(char *fmt, ...); - -//#define FANCY_LEAVES // nearly 2x the triangles when enabled (if underground is filled) -#define FAST_CHUNK -#define IN_PLACE - -#define SKIP_TERRAIN 0 -//#define SKIP_TERRAIN 48 // use to avoid building underground stuff - // allows you to see what perf would be like if underground was efficiently culled, - // or if you were making a game without underground - -enum -{ - C_empty, - C_solid, - C_trans, - C_cross, - C_water, - C_slab, - C_stair, - C_force, -}; - -unsigned char geom_map[] = -{ - STBVOX_GEOM_empty, - STBVOX_GEOM_solid, - STBVOX_GEOM_transp, - STBVOX_GEOM_crossed_pair, - STBVOX_GEOM_solid, - STBVOX_GEOM_slab_lower, - STBVOX_GEOM_floor_slope_north_is_top, - STBVOX_GEOM_force, -}; - -unsigned char minecraft_info[256][7] = -{ - { C_empty, 0,0,0,0,0,0 }, - { C_solid, 1,1,1,1,1,1 }, - { C_solid, 3,3,3,3,40,2 }, - { C_solid, 2,2,2,2,2,2 }, - { C_solid, 16,16,16,16,16,16 }, - { C_solid, 4,4,4,4,4,4 }, - { C_cross, 15,15,15,15 }, - { C_solid, 17,17,17,17,17,17 }, - - // 8 - { C_water, 223,223,223,223,223,223 }, - { C_water, 223,223,223,223,223,223 }, - { C_solid, 255,255,255,255,255,255 }, - { C_solid, 255,255,255,255,255,255 }, - { C_solid, 18,18,18,18,18,18 }, - { C_solid, 19,19,19,19,19,19 }, - { C_solid, 32,32,32,32,32,32 }, - { C_solid, 33,33,33,33,33,33 }, - - // 16 - { C_solid, 34,34,34,34,34,34 }, - { C_solid, 20,20,20,20,21,21 }, -#ifdef FANCY_LEAVES - { C_force, 52,52,52,52,52,52 }, // leaves -#else - { C_solid, 53,53,53,53,53,53 }, // leaves -#endif - { C_solid, 24,24,24,24,24,24 }, - { C_trans, 49,49,49,49,49,49 }, // glass - { C_solid, 160,160,160,160,160,160 }, - { C_solid, 144,144,144,144,144,144 }, - { C_solid, 46,45,45,45,62,62 }, - - // 24 - { C_solid, 192,192,192,192, 176,176 }, - { C_solid, 74,74,74,74,74,74 }, - { C_empty }, // bed - { C_empty }, // powered rail - { C_empty }, // detector rail - { C_solid, 106,108,109,108,108,108 }, - { C_empty }, // cobweb=11 - { C_cross, 39,39,39,39 }, - - // 32 - { C_cross, 55,55,55,55,0,0 }, - { C_solid, 107,108,109,108,108,108 }, - { C_empty }, // piston head - { C_solid, 64,64,64,64,64,64 }, // various colors - { C_empty }, // unused - { C_cross, 13,13,13,13,0,0 }, - { C_cross, 12,12,12,12,0,0 }, - { C_cross, 29,29,29,29,0,0 }, - - // 40 - { C_cross, 28,28,28,28,0,0 }, - { C_solid, 23,23,23,23,23,23 }, - { C_solid, 22,22,22,22,22,22 }, - { C_solid, 5,5,5,5,6,6, }, - { C_slab , 5,5,5,5,6,6, }, - { C_solid, 7,7,7,7,7,7, }, - { C_solid, 8,8,8,8,9,10 }, - { C_solid, 35,35,35,35,4,4, }, - - // 48 - //{ C_solid, 36,36,36,36,36,36 }, - { C_force, 36,36,36,36,36,36 }, - { C_solid, 37,37,37,37,37,37 }, - { C_cross, 80,80,80,80,80,80 }, // torch - { C_empty }, // fire - { C_trans, 65,65,65,65,65,65 }, - { C_stair, 4,4,4,4,4,4 }, - { C_solid, 26,26,26,27,25,25 }, - { C_empty }, // redstone - - // 56 - { C_solid, 50,50,50,50,50,50 }, - //{ C_force, 50,50,50,50,50,50 }, - { C_solid, 26,26,26,26,26,26 }, - { C_solid, 60,59,59,59,43,43 }, - { C_cross, 95,95,95,95 }, - { C_solid, 2,2,2,2,86,2 }, - { C_solid, 44,45,45,45,62,62 }, - { C_solid, 61,45,45,45,62,62 }, - { C_empty }, // sign - - // 64 - { C_empty }, // door - { C_empty }, // ladder - { C_empty }, // rail - { C_stair, 16,16,16,16,16,16 }, // cobblestone stairs - { C_empty }, // sign - { C_empty }, // lever - { C_empty }, // stone pressure plate - { C_empty }, // iron door - - // 72 - { C_empty }, // wooden pressure - { C_solid, 51,51,51,51,51,51 }, - { C_solid, 51,51,51,51,51,51 }, - { C_empty }, - { C_empty }, - { C_empty }, - { C_empty }, // snow on block below, do as half slab? - { C_solid, 67,67,67,67,67,67 }, - - // 80 - { C_solid, 66,66,66,66,66,66 }, - { C_solid, 70,70,70,70,69,71 }, - { C_solid, 72,72,72,72,72,72 }, - { C_cross, 73,73,73,73,73,73 }, - { C_solid, 74,74,74,74,75,74 }, - { C_empty }, // fence - { C_solid,119,118,118,118,102,102 }, - { C_solid,103,103,103,103,103,103 }, - - // 88 - { C_solid, 104,104,104,104,104,104 }, - { C_solid, 105,105,105,105,105,105 }, - { C_solid, 167,167,167,167,167,167 }, - { C_solid, 120,118,118,118,102,102 }, - { C_empty }, // cake - { C_empty }, // repeater - { C_empty }, // repeater - { C_solid, 49,49,49,49,49,49 }, // colored glass - - // 96 - { C_empty }, - { C_empty }, - { C_solid, 54,54,54,54,54,54 }, - { C_solid, 125,125,125,125,125,125 }, - { C_solid, 126,126,126,126,126,126 }, - { C_empty }, // bars - { C_trans, 49,49,49,49,49,49 }, // glass pane - { C_solid, 136,136,136,136,137,137 }, // melon - - // 104 - { C_empty }, // pumpkin stem - { C_empty }, // melon stem - { C_empty }, // vines - { C_empty }, // gate - { C_stair, 7,7,7,7,7,7, }, // brick stairs - { C_stair, 54,54,54,54,54,54 }, // stone brick stairs - { C_empty }, // mycelium - { C_empty }, // lily pad - - // 112 - { C_solid, 224,224,224,224,224,224 }, - { C_empty }, // nether brick fence - { C_stair, 224,224,224,224,224,224 }, // nether brick stairs - { C_empty }, // nether wart - { C_solid, 182,182,182,182,166,183 }, - { C_empty }, // brewing stand - { C_empty }, // cauldron - { C_empty }, // end portal - - // 120 - { C_solid, 159,159,159,159,158,158 }, - { C_solid, 175,175,175,175,175,175 }, - { C_empty }, // dragon egg - { C_solid, 211,211,211,211,211,211 }, - { C_solid, 212,212,212,212,212,212 }, - { C_solid, 4,4,4,4,4,4, }, // wood double-slab - { C_slab , 4,4,4,4,4,4, }, // wood slab - { C_empty }, // cocoa - - // 128 - { C_solid, 192,192,192,192,176,176 }, // sandstone stairs - { C_solid, 32,32,32,32,32,32 }, // emerald ore - { C_solid, 26,26,26,27,25,25 }, // ender chest - { C_empty }, - { C_empty }, - { C_solid, 23,23,23,23,23,23 }, // emerald block - { C_solid, 198,198,198,198,198,198 }, // spruce stairs - { C_solid, 214,214,214,214,214,214 }, // birch stairs - - // 136 - { C_stair, 199,199,199,199,199,199 }, // jungle stairs - { C_empty }, // command block - { C_empty }, // beacon - { C_slab, 16,16,16,16,16,16 }, // cobblestone wall - { C_empty }, // flower pot - { C_empty }, // carrot - { C_empty }, // potatoes - { C_empty }, // wooden button - - // 144 - { C_empty }, // mob head - { C_empty }, // anvil - { C_solid, 26,26,26,27,25,25 }, // trapped chest - { C_empty }, // weighted pressure plate light - { C_empty }, // weighted pressure plat eheavy - { C_empty }, // comparator inactive - { C_empty }, // comparator active - { C_empty }, // daylight sensor - - // 152 - { C_solid, 135,135,135,135,135,135 }, // redstone block - { C_solid, 0,0,0,0,0,0, }, // nether quartz ore - { C_empty }, // hopper - { C_solid, 22,22,22,22,22,22 }, // quartz block - { C_stair, 22,22,22,22,22,22 }, // quartz stairs - { C_empty }, // activator rail - { C_solid, 46,45,45,45,62,62 }, // dropper - { C_solid, 72,72,72,72,72,72 }, // stained clay - - // 160 - { C_trans, 49,49,49,49,49,49 }, // stained glass pane - #ifdef FANCY_LEAVES - { C_force, 52,52,52,52,52,52 }, // leaves - #else - { C_solid, 53,53,53,53,53,53 }, // acacia leaves - #endif - { C_solid, 20,20,20,20,21,21 }, // acacia tree - { C_solid, 199,199,199,199,199,199 }, // acacia wood stairs - { C_solid, 198,198,198,198,198,198 }, // dark oak stairs - { C_solid, 146,146,146,146,146,146 }, // slime block - - { C_solid, 176,176,176,176,176,176 }, // red sandstone - { C_solid, 176,176,176,176,176,176 }, // red sandstone - - // 168 - { C_empty }, - { C_empty }, - { C_empty }, - { C_empty }, - { C_solid, 72,72,72,72,72,72 }, // hardened clay - { C_empty }, - { C_empty }, - { C_empty }, - - // 176 - { C_empty }, - { C_empty }, - { C_solid, 176,176,176,176,176,176 }, // red sandstone -}; - -unsigned char minecraft_tex1_for_blocktype[256][6]; -unsigned char effective_blocktype[256]; -unsigned char minecraft_color_for_blocktype[256][6]; -unsigned char minecraft_geom_for_blocktype[256]; - -uint8 build_buffer[BUILD_BUFFER_SIZE]; -uint8 face_buffer[FACE_BUFFER_SIZE]; - -//GLuint vbuf, fbuf, fbuf_tex; - -//unsigned char tex1_for_blocktype[256][6]; - -//unsigned char blocktype[34][34][257]; -//unsigned char lighting[34][34][257]; - -// a superchunk is 64x64x256, with the border blocks computed as well, -// which means we need 4x4 chunks plus 16 border chunks plus 4 corner chunks - -#define SUPERCHUNK_X 4 -#define SUPERCHUNK_Y 4 - -unsigned char remap_data[16][16]; -unsigned char remap[256]; -unsigned char rotate_data[4] = { 1,3,2,0 }; - -void convert_fastchunk_inplace(fast_chunk *fc) -{ - int i; - int num_blocks=0, step=0; - unsigned char rot[4096]; - #ifndef IN_PLACE - unsigned char *storage; - #endif - - memset(rot, 0, 4096); - - for (i=0; i < 16; ++i) - num_blocks += fc->blockdata[i] != NULL; - - #ifndef IN_PLACE - storage = malloc(16*16*16*2 * num_blocks); - #endif - - for (i=0; i < 16; ++i) { - if (fc->blockdata[i]) { - int o=0; - unsigned char *bd,*dd,*lt,*sky; - unsigned char *out, *outb; - - // this ordering allows us to determine which data we can safely overwrite for in-place processing - bd = fc->blockdata[i]; - dd = fc->data[i]; - lt = fc->light[i]; - sky = fc->skylight[i]; - - #ifdef IN_PLACE - out = bd; - #else - out = storage + 16*16*16*2*step; - #endif - - // bd is written in place, but also reads from dd - for (o=0; o < 16*16*16/2; o += 1) { - unsigned char v1,v2; - unsigned char d = dd[o]; - v1 = bd[o*2+0]; - v2 = bd[o*2+1]; - - if (remap[v1]) - { - //unsigned char d = bd[o] & 15; - v1 = remap_data[remap[v1]][d&15]; - rot[o*2+0] = rotate_data[d&3]; - } else - v1 = effective_blocktype[v1]; - - if (remap[v2]) - { - //unsigned char d = bd[o] >> 4; - v2 = remap_data[remap[v2]][d>>4]; - rot[o*2+1] = rotate_data[(d>>4)&3]; - } else - v2 = effective_blocktype[v2]; - - out[o*2+0] = v1; - out[o*2+1] = v2; - } - - // this reads from lt & sky - #ifndef IN_PLACE - outb = out + 16*16*16; - ++step; - #endif - - // MC used to write in this order and it makes it possible to compute in-place - if (dd < sky && sky < lt) { - // @TODO go this path always if !IN_PLACE - #ifdef IN_PLACE - outb = dd; - #endif - - for (o=0; o < 16*16*16/2; ++o) { - int bright; - bright = (lt[o]&15)*12 + 15 + (sky[o]&15)*16; - if (bright > 255) bright = 255; - if (bright < 32) bright = 32; - outb[o*2+0] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright, (rot[o*2+0]&3)); - - bright = (lt[o]>>4)*12 + 15 + (sky[o]>>4)*16; - if (bright > 255) bright = 255; - if (bright < 32) bright = 32; - outb[o*2+1] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright, (rot[o*2+1]&3)); - } - } else { - // @TODO: if blocktype is in between others, this breaks; need to find which side has two pointers, and use that - // overwrite rot[] array, then copy out - #ifdef IN_PLACE - outb = (dd < sky) ? dd : sky; - if (lt < outb) lt = outb; - #endif - - for (o=0; o < 16*16*16/2; ++o) { - int bright; - bright = (lt[o]&15)*12 + 15 + (sky[o]&15)*16; - if (bright > 255) bright = 255; - if (bright < 32) bright = 32; - rot[o*2+0] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright, (rot[o*2+0]&3)); - - bright = (lt[o]>>4)*12 + 15 + (sky[o]>>4)*16; - if (bright > 255) bright = 255; - if (bright < 32) bright = 32; - rot[o*2+1] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright, (rot[o*2+1]&3)); - } - - memcpy(outb, rot, 4096); - fc->data[i] = outb; - } - - #ifndef IN_PLACE - fc->blockdata[i] = out; - fc->data[i] = outb; - #endif - } - } - - #ifndef IN_PLACE - free(fc->pointer_to_free); - fc->pointer_to_free = storage; - #endif -} - -void make_converted_fastchunk(fast_chunk *fc, int x, int y, int segment, uint8 *sv_blocktype, uint8 *sv_lighting) -{ - int z; - assert(fc == NULL || (fc->refcount > 0 && fc->refcount < 64)); - if (fc == NULL || fc->blockdata[segment] == NULL) { - for (z=0; z < 16; ++z) { - sv_blocktype[z] = C_empty; - sv_lighting[z] = 255; - } - } else { - unsigned char *block = fc->blockdata[segment]; - unsigned char *data = fc->data[segment]; - y = 15-y; - for (z=0; z < 16; ++z) { - sv_blocktype[z] = block[z*256 + y*16 + x]; - sv_lighting [z] = data [z*256 + y*16 + x]; - } - } -} - - -#define CHUNK_CACHE 64 -typedef struct -{ - int valid; - int chunk_x, chunk_y; - fast_chunk *fc; -} cached_converted_chunk; - -cached_converted_chunk chunk_cache[CHUNK_CACHE][CHUNK_CACHE]; -int cache_size = CHUNK_CACHE; - -void reset_cache_size(int size) -{ - int i,j; - for (j=size; j < cache_size; ++j) { - for (i=size; i < cache_size; ++i) { - cached_converted_chunk *ccc = &chunk_cache[j][i]; - if (ccc->valid) { - if (ccc->fc) { - free(ccc->fc->pointer_to_free); - free(ccc->fc); - ccc->fc = NULL; - } - ccc->valid = 0; - } - } - } - cache_size = size; -} - -// this must be called inside mutex -void deref_fastchunk(fast_chunk *fc) -{ - if (fc) { - assert(fc->refcount > 0); - --fc->refcount; - if (fc->refcount == 0) { - free(fc->pointer_to_free); - free(fc); - } - } -} - -SDL_mutex * chunk_cache_mutex; -SDL_mutex * chunk_get_mutex; - -void lock_chunk_get_mutex(void) -{ - SDL_LockMutex(chunk_get_mutex); -} -void unlock_chunk_get_mutex(void) -{ - SDL_UnlockMutex(chunk_get_mutex); -} - -fast_chunk *get_converted_fastchunk(int chunk_x, int chunk_y) -{ - int slot_x = (chunk_x & (cache_size-1)); - int slot_y = (chunk_y & (cache_size-1)); - fast_chunk *fc; - cached_converted_chunk *ccc; - SDL_LockMutex(chunk_cache_mutex); - ccc = &chunk_cache[slot_y][slot_x]; - if (ccc->valid) { - if (ccc->chunk_x == chunk_x && ccc->chunk_y == chunk_y) { - fast_chunk *fc = ccc->fc; - if (fc) - ++fc->refcount; - SDL_UnlockMutex(chunk_cache_mutex); - return fc; - } - if (ccc->fc) { - deref_fastchunk(ccc->fc); - ccc->fc = NULL; - ccc->valid = 0; - } - } - SDL_UnlockMutex(chunk_cache_mutex); - - fc = get_decoded_fastchunk_uncached(chunk_x, -chunk_y); - if (fc) - convert_fastchunk_inplace(fc); - - SDL_LockMutex(chunk_cache_mutex); - // another thread might have updated it, so before we overwrite it... - if (ccc->fc) { - deref_fastchunk(ccc->fc); - ccc->fc = NULL; - } - - if (fc) - fc->refcount = 1; // 1 in the cache - - ccc->chunk_x = chunk_x; - ccc->chunk_y = chunk_y; - ccc->valid = 1; - if (fc) - ++fc->refcount; - ccc->fc = fc; - SDL_UnlockMutex(chunk_cache_mutex); - return fc; -} - -void make_map_segment_for_superchunk_preconvert(int chunk_x, int chunk_y, int segment, fast_chunk *fc_table[4][4], uint8 sv_blocktype[34][34][18], uint8 sv_lighting[34][34][18]) -{ - int a,b; - assert((chunk_x & 1) == 0); - assert((chunk_y & 1) == 0); - for (b=-1; b < 3; ++b) { - for (a=-1; a < 3; ++a) { - int xo = a*16+1; - int yo = b*16+1; - int x,y; - fast_chunk *fc = fc_table[b+1][a+1]; - for (y=0; y < 16; ++y) - for (x=0; x < 16; ++x) - if (xo+x >= 0 && xo+x < 34 && yo+y >= 0 && yo+y < 34) - make_converted_fastchunk(fc,x,y, segment, sv_blocktype[xo+x][yo+y], sv_lighting[xo+x][yo+y]); - } - } -} - -// build 1 mesh covering 2x2 chunks -void build_chunk(int chunk_x, int chunk_y, fast_chunk *fc_table[4][4], raw_mesh *rm) -{ - int a,b,z; - stbvox_input_description *map; - - #ifdef VHEIGHT_TEST - unsigned char vheight[34][34][18]; - #endif - - #ifndef STBVOX_CONFIG_DISABLE_TEX2 - unsigned char tex2_choice[34][34][18]; - #endif - - assert((chunk_x & 1) == 0); - assert((chunk_y & 1) == 0); - - rm->cx = chunk_x; - rm->cy = chunk_y; - - stbvox_set_input_stride(&rm->mm, 34*18, 18); - - assert(rm->mm.input.geometry == NULL); - - map = stbvox_get_input_description(&rm->mm); - map->block_tex1_face = minecraft_tex1_for_blocktype; - map->block_color_face = minecraft_color_for_blocktype; - map->block_geometry = minecraft_geom_for_blocktype; - - stbvox_reset_buffers(&rm->mm); - stbvox_set_buffer(&rm->mm, 0, 0, rm->build_buffer, BUILD_BUFFER_SIZE); - stbvox_set_buffer(&rm->mm, 0, 1, rm->face_buffer , FACE_BUFFER_SIZE); - - map->blocktype = &rm->sv_blocktype[1][1][1]; // this is (0,0,0), but we need to be able to query off the edges - map->lighting = &rm->sv_lighting[1][1][1]; - - // fill in the top two rows of the buffer - for (a=0; a < 34; ++a) { - for (b=0; b < 34; ++b) { - rm->sv_blocktype[a][b][16] = 0; - rm->sv_lighting [a][b][16] = 255; - rm->sv_blocktype[a][b][17] = 0; - rm->sv_lighting [a][b][17] = 255; - } - } - - #ifndef STBVOX_CONFIG_DISABLE_TEX2 - for (a=0; a < 34; ++a) { - for (b=0; b < 34; ++b) { - int px = chunk_x*16 + a - 1; - int py = chunk_y*16 + b - 1; - float dist = (float) sqrt(px*px + py*py); - float s1 = (float) sin(dist / 16), s2, s3; - dist = (float) sqrt((px-80)*(px-80) + (py-50)*(py-50)); - s2 = (float) sin(dist / 11); - for (z=0; z < 18; ++z) { - s3 = (float) sin(z * 3.141592 / 8); - - s3 = s1*s2*s3; - tex2_choice[a][b][z] = 63 & (int) stb_linear_remap(s3,-1,1, -20,83); - } - } - } - #endif - - for (z=256-16; z >= SKIP_TERRAIN; z -= 16) - { - int z0 = z; - int z1 = z+16; - if (z1 == 256) z1 = 255; - - make_map_segment_for_superchunk_preconvert(chunk_x, chunk_y, z >> 4, fc_table, rm->sv_blocktype, rm->sv_lighting); - - map->blocktype = &rm->sv_blocktype[1][1][1-z]; // specify location of 0,0,0 so that accessing z0..z1 gets right data - map->lighting = &rm->sv_lighting[1][1][1-z]; - #ifndef STBVOX_CONFIG_DISABLE_TEX2 - map->tex2 = &tex2_choice[1][1][1-z]; - #endif - - #ifdef VHEIGHT_TEST - // hacky test of vheight - for (a=0; a < 34; ++a) { - for (b=0; b < 34; ++b) { - int c; - for (c=0; c < 17; ++c) { - if (rm->sv_blocktype[a][b][c] != 0 && rm->sv_blocktype[a][b][c+1] == 0) { - // topmost block - vheight[a][b][c] = rand() & 255; - rm->sv_blocktype[a][b][c] = 168; - } else if (c > 0 && rm->sv_blocktype[a][b][c] != 0 && rm->sv_blocktype[a][b][c-1] == 0) { - // bottommost block - vheight[a][b][c] = ((rand() % 3) << 6) + ((rand() % 3) << 4) + ((rand() % 3) << 2) + (rand() % 3); - rm->sv_blocktype[a][b][c] = 169; - } - } - vheight[a][b][c] = STBVOX_MAKE_VHEIGHT(2,2,2,2); // flat top - } - } - map->vheight = &vheight[1][1][1-z]; - #endif - - { - stbvox_set_input_range(&rm->mm, 0,0,z0, 32,32,z1); - stbvox_set_default_mesh(&rm->mm, 0); - stbvox_make_mesh(&rm->mm); - } - - // copy the bottom two rows of data up to the top - for (a=0; a < 34; ++a) { - for (b=0; b < 34; ++b) { - rm->sv_blocktype[a][b][16] = rm->sv_blocktype[a][b][0]; - rm->sv_blocktype[a][b][17] = rm->sv_blocktype[a][b][1]; - rm->sv_lighting [a][b][16] = rm->sv_lighting [a][b][0]; - rm->sv_lighting [a][b][17] = rm->sv_lighting [a][b][1]; - } - } - } - - stbvox_set_mesh_coordinates(&rm->mm, chunk_x*16, chunk_y*16, 0); - stbvox_get_transform(&rm->mm, rm->transform); - - stbvox_set_input_range(&rm->mm, 0,0,0, 32,32,255); - stbvox_get_bounds(&rm->mm, rm->bounds); - - rm->num_quads = stbvox_get_quad_count(&rm->mm, 0); -} - -int next_blocktype = 255; - -unsigned char mc_rot[4] = { 1,3,2,0 }; - -// create blocktypes with rotation baked into type... -// @TODO we no longer need this now that we store rotations -// in lighting -void build_stair_rotations(int blocktype, unsigned char *map) -{ - int i; - - // use the existing block type for floor stairs; allocate a new type for ceil stairs - for (i=0; i < 6; ++i) { - minecraft_color_for_blocktype[next_blocktype][i] = minecraft_color_for_blocktype[blocktype][i]; - minecraft_tex1_for_blocktype [next_blocktype][i] = minecraft_tex1_for_blocktype [blocktype][i]; - } - minecraft_geom_for_blocktype[next_blocktype] = (unsigned char) STBVOX_MAKE_GEOMETRY(STBVOX_GEOM_ceil_slope_north_is_bottom, 0, 0); - minecraft_geom_for_blocktype[ blocktype] = (unsigned char) STBVOX_MAKE_GEOMETRY(STBVOX_GEOM_floor_slope_north_is_top, 0, 0); - - for (i=0; i < 4; ++i) { - map[0+i+8] = map[0+i] = blocktype; - map[4+i+8] = map[4+i] = next_blocktype; - } - --next_blocktype; -} - -void build_wool_variations(int bt, unsigned char *map) -{ - int i,k; - unsigned char tex[16] = { 64, 210, 194, 178, 162, 146, 130, 114, 225, 209, 193, 177, 161, 145, 129, 113 }; - for (i=0; i < 16; ++i) { - if (i == 0) - map[i] = bt; - else { - map[i] = next_blocktype; - for (k=0; k < 6; ++k) { - minecraft_tex1_for_blocktype[next_blocktype][k] = tex[i]; - } - minecraft_geom_for_blocktype[next_blocktype] = minecraft_geom_for_blocktype[bt]; - --next_blocktype; - } - } -} - -void build_wood_variations(int bt, unsigned char *map) -{ - int i,k; - unsigned char tex[4] = { 5, 198, 214, 199 }; - for (i=0; i < 4; ++i) { - if (i == 0) - map[i] = bt; - else { - map[i] = next_blocktype; - for (k=0; k < 6; ++k) { - minecraft_tex1_for_blocktype[next_blocktype][k] = tex[i]; - } - minecraft_geom_for_blocktype[next_blocktype] = minecraft_geom_for_blocktype[bt]; - --next_blocktype; - } - } - map[i] = map[i-1]; - ++i; - for (; i < 16; ++i) - map[i] = bt; -} - -void remap_in_place(int bt, int rm) -{ - int i; - remap[bt] = rm; - for (i=0; i < 16; ++i) - remap_data[rm][i] = bt; -} - - -void mesh_init(void) -{ - int i; - - chunk_cache_mutex = SDL_CreateMutex(); - chunk_get_mutex = SDL_CreateMutex(); - - for (i=0; i < 256; ++i) { - memcpy(minecraft_tex1_for_blocktype[i], minecraft_info[i]+1, 6); - effective_blocktype[i] = (minecraft_info[i][0] == C_empty ? 0 : i); - minecraft_geom_for_blocktype[i] = geom_map[minecraft_info[i][0]]; - } - //effective_blocktype[50] = 0; // delete torches - - for (i=0; i < 6*256; ++i) { - if (minecraft_tex1_for_blocktype[0][i] == 40) - minecraft_color_for_blocktype[0][i] = 38 | 64; // apply to tex1 - if (minecraft_tex1_for_blocktype[0][i] == 39) - minecraft_color_for_blocktype[0][i] = 39 | 64; // apply to tex1 - if (minecraft_tex1_for_blocktype[0][i] == 105) - minecraft_color_for_blocktype[0][i] = 63; // emissive - if (minecraft_tex1_for_blocktype[0][i] == 212) - minecraft_color_for_blocktype[0][i] = 63; // emissive - if (minecraft_tex1_for_blocktype[0][i] == 80) - minecraft_color_for_blocktype[0][i] = 63; // emissive - } - - for (i=0; i < 6; ++i) { - minecraft_color_for_blocktype[172][i] = 47 | 64; // apply to tex1 - minecraft_color_for_blocktype[178][i] = 47 | 64; // apply to tex1 - minecraft_color_for_blocktype[18][i] = 39 | 64; // green - minecraft_color_for_blocktype[161][i] = 37 | 64; // green - minecraft_color_for_blocktype[10][i] = 63; // emissive lava - minecraft_color_for_blocktype[11][i] = 63; // emissive - //minecraft_color_for_blocktype[56][i] = 63; // emissive diamond - minecraft_color_for_blocktype[48][i] = 63; // emissive dungeon - } - - #ifdef VHEIGHT_TEST - effective_blocktype[168] = 168; - minecraft_tex1_for_blocktype[168][0] = 1; - minecraft_tex1_for_blocktype[168][1] = 1; - minecraft_tex1_for_blocktype[168][2] = 1; - minecraft_tex1_for_blocktype[168][3] = 1; - minecraft_tex1_for_blocktype[168][4] = 1; - minecraft_tex1_for_blocktype[168][5] = 1; - minecraft_geom_for_blocktype[168] = STBVOX_GEOM_floor_vheight_12; - effective_blocktype[169] = 169; - minecraft_tex1_for_blocktype[169][0] = 1; - minecraft_tex1_for_blocktype[169][1] = 1; - minecraft_tex1_for_blocktype[169][2] = 1; - minecraft_tex1_for_blocktype[169][3] = 1; - minecraft_tex1_for_blocktype[169][4] = 1; - minecraft_tex1_for_blocktype[169][5] = 1; - minecraft_geom_for_blocktype[169] = STBVOX_GEOM_ceil_vheight_03; - #endif - - remap[53] = 1; - remap[67] = 2; - remap[108] = 3; - remap[109] = 4; - remap[114] = 5; - remap[136] = 6; - remap[156] = 7; - for (i=0; i < 256; ++i) - if (remap[i]) - build_stair_rotations(i, remap_data[remap[i]]); - remap[35] = 8; - build_wool_variations(35, remap_data[remap[35]]); - remap[5] = 11; - build_wood_variations(5, remap_data[remap[5]]); - - // set the remap flags for these so they write the rotation values - remap_in_place(54, 9); - remap_in_place(146, 10); -} - -// Timing stats while optimizing the single-threaded builder - -// 32..-32, 32..-32, SKIP_TERRAIN=0, !FANCY_LEAVES on 'mcrealm' data set - -// 6.27s - reblocked to do 16 z at a time instead of 256 (still using 66x66x258), 4 meshes in parallel -// 5.96s - reblocked to use FAST_CHUNK (no intermediate data structure) -// 5.45s - unknown change, or previous measurement was wrong - -// 6.12s - use preconverted data, not in-place -// 5.91s - use preconverted, in-place -// 5.34s - preconvert, in-place, avoid dependency chain (suggested by ryg) -// 5.34s - preconvert, in-place, avoid dependency chain, use bit-table instead of byte-table -// 5.50s - preconvert, in-place, branchless - -// 6.42s - non-preconvert, avoid dependency chain (not an error) -// 5.40s - non-preconvert, w/dependency chain (same as earlier) - -// 5.50s - non-FAST_CHUNK, reblocked outer loop for better cache reuse -// 4.73s - FAST_CHUNK non-preconvert, reblocked outer loop -// 4.25s - preconvert, in-place, reblocked outer loop -// 4.18s - preconvert, in-place, unrolled again -// 4.10s - 34x34 1 mesh instead of 66x66 and 4 meshes (will make it easier to do multiple threads) - -// 4.83s - building bitmasks but not using them (2 bits per block, one if empty, one if solid) - -// 5.16s - using empty bitmasks to early out -// 5.01s - using solid & empty bitmasks to early out - "foo" -// 4.64s - empty bitmask only, test 8 at a time, then test geom -// 4.72s - empty bitmask only, 8 at a time, then test bits -// 4.46s - split bitmask building into three loops (each byte is separate) -// 4.42s - further optimize computing bitmask - -// 4.58s - using solid & empty bitmasks to early out, same as "foo" but faster bitmask building -// 4.12s - using solid & empty bitmasks to efficiently test neighbors -// 4.04s - using 16-bit fetches (not endian-independent) -// - note this is first place that beats previous best '4.10s - 34x34 1 mesh' - -// 4.30s - current time with bitmasks disabled again (note was 4.10s earlier) -// 3.95s - bitmasks enabled again, no other changes -// 4.00s - current time with bitmasks disabled again, no other changes -- wide variation that is time dependent? -// (note that most of the numbers listed here are median of 3 values already) -// 3.98s - bitmasks enabled - -// Bitmasks removed from the code as not worth the complexity increase - - - -// Raw data for Q&A: -// -// 26% parsing & loading minecraft files (4/5ths of which is zlib decode) -// 39% building mesh from stb input format -// 18% converting from minecraft blocks to stb blocks -// 9% reordering from minecraft axis order to stb axis order -// 7% uploading vertex buffer to OpenGL diff --git a/source/engine/thirdparty/stb/tests/caveview/cave_parse.c b/source/engine/thirdparty/stb/tests/caveview/cave_parse.c deleted file mode 100644 index e8ae02b..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/cave_parse.c +++ /dev/null @@ -1,632 +0,0 @@ -#include -#include -#include -#include - -#define FAST_CHUNK // disabling this enables the old, slower path that deblocks into a regular form - -#include "cave_parse.h" - -#include "stb_image.h" -#include "stb.h" - -#define NUM_CHUNKS_PER_REGION 32 // only on one axis -#define NUM_CHUNKS_PER_REGION_LOG2 5 - -#define NUM_COLUMNS_PER_CHUNK 16 -#define NUM_COLUMNS_PER_CHUNK_LOG2 4 - -uint32 read_uint32_be(FILE *f) -{ - unsigned char data[4]; - fread(data, 1, 4, f); - return (data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]; -} - -typedef struct -{ - uint8 *data; - size_t len; - int x,z; // chunk index - int refcount; // for multi-threading -} compressed_chunk; - -typedef struct -{ - int x,z; - uint32 sector_data[NUM_CHUNKS_PER_REGION][NUM_CHUNKS_PER_REGION]; -} region; - -size_t cached_compressed=0; - -FILE *last_region; -int last_region_x; -int last_region_z; -int opened=0; - -static void open_file(int reg_x, int reg_z) -{ - if (!opened || last_region_x != reg_x || last_region_z != reg_z) { - char filename[256]; - if (last_region != NULL) - fclose(last_region); - sprintf(filename, "r.%d.%d.mca", reg_x, reg_z); - last_region = fopen(filename, "rb"); - last_region_x = reg_x; - last_region_z = reg_z; - opened = 1; - } -} - -static region *load_region(int reg_x, int reg_z) -{ - region *r; - int x,z; - - open_file(reg_x, reg_z); - - r = malloc(sizeof(*r)); - - if (last_region == NULL) { - memset(r, 0, sizeof(*r)); - } else { - fseek(last_region, 0, SEEK_SET); - for (z=0; z < NUM_CHUNKS_PER_REGION; ++z) - for (x=0; x < NUM_CHUNKS_PER_REGION; ++x) - r->sector_data[z][x] = read_uint32_be(last_region); - } - r->x = reg_x; - r->z = reg_z; - - return r; -} - -void free_region(region *r) -{ - free(r); -} - -#define MAX_MAP_REGIONS 64 // in one axis: 64 regions * 32 chunk/region * 16 columns/chunk = 16384 columns -region *regions[MAX_MAP_REGIONS][MAX_MAP_REGIONS]; - -static region *get_region(int reg_x, int reg_z) -{ - int slot_x = reg_x & (MAX_MAP_REGIONS-1); - int slot_z = reg_z & (MAX_MAP_REGIONS-1); - region *r; - - r = regions[slot_z][slot_x]; - - if (r) { - if (r->x == reg_x && r->z == reg_z) - return r; - free_region(r); - } - - r = load_region(reg_x, reg_z); - regions[slot_z][slot_x] = r; - - return r; -} - -// about one region, so size should be ok -#define NUM_CACHED_X 64 -#define NUM_CACHED_Z 64 - -// @TODO: is it really worth caching these? we probably can just -// pull them from the disk cache nearly as efficiently. -// Can test that by setting to 1x1? -compressed_chunk *cached_chunk[NUM_CACHED_Z][NUM_CACHED_X]; - -static void deref_compressed_chunk(compressed_chunk *cc) -{ - assert(cc->refcount > 0); - --cc->refcount; - if (cc->refcount == 0) { - if (cc->data) - free(cc->data); - free(cc); - } -} - -static compressed_chunk *get_compressed_chunk(int chunk_x, int chunk_z) -{ - int slot_x = chunk_x & (NUM_CACHED_X-1); - int slot_z = chunk_z & (NUM_CACHED_Z-1); - compressed_chunk *cc = cached_chunk[slot_z][slot_x]; - - if (cc && cc->x == chunk_x && cc->z == chunk_z) - return cc; - else { - int reg_x = chunk_x >> NUM_CHUNKS_PER_REGION_LOG2; - int reg_z = chunk_z >> NUM_CHUNKS_PER_REGION_LOG2; - region *r = get_region(reg_x, reg_z); - if (cc) { - deref_compressed_chunk(cc); - cached_chunk[slot_z][slot_x] = NULL; - } - cc = malloc(sizeof(*cc)); - cc->x = chunk_x; - cc->z = chunk_z; - { - int subchunk_x = chunk_x & (NUM_CHUNKS_PER_REGION-1); - int subchunk_z = chunk_z & (NUM_CHUNKS_PER_REGION-1); - uint32 code = r->sector_data[subchunk_z][subchunk_x]; - - if (code & 255) { - open_file(reg_x, reg_z); - fseek(last_region, (code>>8)*4096, SEEK_SET); - cc->len = (code&255)*4096; - cc->data = malloc(cc->len); - fread(cc->data, 1, cc->len, last_region); - } else { - cc->len = 0; - cc->data = 0; - } - } - cc->refcount = 1; - cached_chunk[slot_z][slot_x] = cc; - return cc; - } -} - - -// NBT parser -- can automatically parse stuff we don't -// have definitions for, but want to explicitly parse -// stuff we do have definitions for. -// -// option 1: auto-parse everything into data structures, -// then read those -// -// option 2: have a "parse next object" which -// doesn't resolve whether it expands its children -// yet, and then the user either says "expand" or -// "skip" after looking at the name. Anything with -// "children" without names can't go through this -// interface. -// -// Let's try option 2. - - -typedef struct -{ - unsigned char *buffer_start; - unsigned char *buffer_end; - unsigned char *cur; - int nesting; - char temp_buffer[256]; -} nbt; - -enum { TAG_End=0, TAG_Byte=1, TAG_Short=2, TAG_Int=3, TAG_Long=4, - TAG_Float=5, TAG_Double=6, TAG_Byte_Array=7, TAG_String=8, - TAG_List=9, TAG_Compound=10, TAG_Int_Array=11 }; - -static void nbt_get_string_data(unsigned char *data, char *buffer, size_t bufsize) -{ - int len = data[0]*256 + data[1]; - int i; - for (i=0; i < len && i+1 < (int) bufsize; ++i) - buffer[i] = (char) data[i+2]; - buffer[i] = 0; -} - -static char *nbt_peek(nbt *n) -{ - unsigned char type = *n->cur; - if (type == TAG_End) - return NULL; - nbt_get_string_data(n->cur+1, n->temp_buffer, sizeof(n->temp_buffer)); - return n->temp_buffer; -} - -static uint32 nbt_parse_uint32(unsigned char *buffer) -{ - return (buffer[0] << 24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3]; -} - -static void nbt_skip(nbt *n); - -// skip an item that doesn't have an id or name prefix (usable in lists) -static void nbt_skip_raw(nbt *n, unsigned char type) -{ - switch (type) { - case TAG_Byte : n->cur += 1; break; - case TAG_Short : n->cur += 2; break; - case TAG_Int : n->cur += 4; break; - case TAG_Long : n->cur += 8; break; - case TAG_Float : n->cur += 4; break; - case TAG_Double: n->cur += 8; break; - case TAG_Byte_Array: n->cur += 4 + 1*nbt_parse_uint32(n->cur); break; - case TAG_Int_Array : n->cur += 4 + 4*nbt_parse_uint32(n->cur); break; - case TAG_String : n->cur += 2 + (n->cur[0]*256 + n->cur[1]); break; - case TAG_List : { - unsigned char list_type = *n->cur++; - unsigned int list_len = nbt_parse_uint32(n->cur); - unsigned int i; - n->cur += 4; // list_len - for (i=0; i < list_len; ++i) - nbt_skip_raw(n, list_type); - break; - } - case TAG_Compound : { - while (*n->cur != TAG_End) - nbt_skip(n); - nbt_skip(n); // skip the TAG_end - break; - } - } - assert(n->cur <= n->buffer_end); -} - -static void nbt_skip(nbt *n) -{ - unsigned char type = *n->cur++; - if (type == TAG_End) - return; - // skip name - n->cur += (n->cur[0]*256 + n->cur[1]) + 2; - nbt_skip_raw(n, type); -} - -// byteswap -static void nbt_swap(unsigned char *ptr, int len) -{ - int i; - for (i=0; i < (len>>1); ++i) { - unsigned char t = ptr[i]; - ptr[i] = ptr[len-1-i]; - ptr[len-1-i] = t; - } -} - -// pass in the expected type, fail if doesn't match -// returns a pointer to the data, byteswapped if appropriate -static void *nbt_get_fromlist(nbt *n, unsigned char type, int *len) -{ - unsigned char *ptr; - assert(type != TAG_Compound); - assert(type != TAG_List); // we could support getting lists of primitives as if they were arrays, but eh - if (len) *len = 1; - ptr = n->cur; - switch (type) { - case TAG_Byte : break; - - case TAG_Short : nbt_swap(ptr, 2); break; - case TAG_Int : nbt_swap(ptr, 4); break; - case TAG_Long : nbt_swap(ptr, 8); break; - case TAG_Float : nbt_swap(ptr, 4); break; - case TAG_Double: nbt_swap(ptr, 8); break; - - case TAG_Byte_Array: - *len = nbt_parse_uint32(ptr); - ptr += 4; - break; - case TAG_Int_Array: { - int i; - *len = nbt_parse_uint32(ptr); - ptr += 4; - for (i=0; i < *len; ++i) - nbt_swap(ptr + 4*i, 4); - break; - } - - default: assert(0); // unhandled case - } - nbt_skip_raw(n, type); - return ptr; -} - -static void *nbt_get(nbt *n, unsigned char type, int *len) -{ - assert(n->cur[0] == type); - n->cur += 3 + (n->cur[1]*256+n->cur[2]); - return nbt_get_fromlist(n, type, len); -} - -static void nbt_begin_compound(nbt *n) // start a compound -{ - assert(*n->cur == TAG_Compound); - // skip header - n->cur += 3 + (n->cur[1]*256 + n->cur[2]); - ++n->nesting; -} - -static void nbt_begin_compound_in_list(nbt *n) // start a compound -{ - ++n->nesting; -} - -static void nbt_end_compound(nbt *n) // end a compound -{ - assert(*n->cur == TAG_End); - assert(n->nesting != 0); - ++n->cur; - --n->nesting; -} - -// @TODO no interface to get lists from lists -static int nbt_begin_list(nbt *n, unsigned char type) -{ - uint32 len; - unsigned char *ptr; - - ptr = n->cur + 3 + (n->cur[1]*256 + n->cur[2]); - if (ptr[0] != type) - return -1; - n->cur = ptr; - len = nbt_parse_uint32(n->cur+1); - assert(n->cur[0] == type); - // @TODO keep a stack with the count to make sure they do it right - ++n->nesting; - n->cur += 5; - return (int) len; -} - -static void nbt_end_list(nbt *n) -{ - --n->nesting; -} - -// raw_block chunk is 16x256x16x4 = 2^(4+8+4+2) = 256KB -// -// if we want to process 64x64x256 at a time, that will be: -// 4*4*256KB => 4MB per area in raw_block -// -// (plus we maybe need to decode adjacent regions) - - -#ifdef FAST_CHUNK -typedef fast_chunk parse_chunk; -#else -typedef chunk parse_chunk; -#endif - -static parse_chunk *minecraft_chunk_parse(unsigned char *data, size_t len) -{ - char *s; - parse_chunk *c = NULL; - - nbt n_store, *n = &n_store; - n->buffer_start = data; - n->buffer_end = data + len; - n->cur = n->buffer_start; - n->nesting = 0; - - nbt_begin_compound(n); - while ((s = nbt_peek(n)) != NULL) { - if (!strcmp(s, "Level")) { - int *height; - c = malloc(sizeof(*c)); - #ifdef FAST_CHUNK - memset(c, 0, sizeof(*c)); - c->pointer_to_free = data; - #else - c->rb[15][15][255].block = 0; - #endif - c->max_y = 0; - - nbt_begin_compound(n); - while ((s = nbt_peek(n)) != NULL) { - if (!strcmp(s, "xPos")) - c->xpos = *(int *) nbt_get(n, TAG_Int, 0); - else if (!strcmp(s, "zPos")) - c->zpos = *(int *) nbt_get(n, TAG_Int, 0); - else if (!strcmp(s, "Sections")) { - int count = nbt_begin_list(n, TAG_Compound), i; - if (count == -1) { - // this not-a-list case happens in The End and I'm not sure - // what it means... possibly one of those silly encodings - // where it's not encoded as a list if there's only one? - // not worth figuring out - nbt_skip(n); - count = -1; - } - for (i=0; i < count; ++i) { - int yi, len; - uint8 *light = NULL, *blocks = NULL, *data = NULL, *skylight = NULL; - nbt_begin_compound_in_list(n); - while ((s = nbt_peek(n)) != NULL) { - if (!strcmp(s, "Y")) - yi = * (uint8 *) nbt_get(n, TAG_Byte, 0); - else if (!strcmp(s, "BlockLight")) { - light = nbt_get(n, TAG_Byte_Array, &len); - assert(len == 2048); - } else if (!strcmp(s, "Blocks")) { - blocks = nbt_get(n, TAG_Byte_Array, &len); - assert(len == 4096); - } else if (!strcmp(s, "Data")) { - data = nbt_get(n, TAG_Byte_Array, &len); - assert(len == 2048); - } else if (!strcmp(s, "SkyLight")) { - skylight = nbt_get(n, TAG_Byte_Array, &len); - assert(len == 2048); - } - } - nbt_end_compound(n); - - assert(yi < 16); - - #ifndef FAST_CHUNK - - // clear data below current max_y - { - int x,z; - while (c->max_y < yi*16) { - for (x=0; x < 16; ++x) - for (z=0; z < 16; ++z) - c->rb[z][x][c->max_y].block = 0; - ++c->max_y; - } - } - - // now assemble the data - { - int x,y,z, o2=0,o4=0; - for (y=0; y < 16; ++y) { - for (z=0; z < 16; ++z) { - for (x=0; x < 16; x += 2) { - raw_block *rb = &c->rb[15-z][x][y + yi*16]; // 15-z because switching to z-up will require flipping an axis - rb[0].block = blocks[o4]; - rb[0].light = light[o2] & 15; - rb[0].data = data[o2] & 15; - rb[0].skylight = skylight[o2] & 15; - - rb[256].block = blocks[o4+1]; - rb[256].light = light[o2] >> 4; - rb[256].data = data[o2] >> 4; - rb[256].skylight = skylight[o2] >> 4; - - o2 += 1; - o4 += 2; - } - } - } - c->max_y += 16; - } - #else - c->blockdata[yi] = blocks; - c->data [yi] = data; - c->light [yi] = light; - c->skylight [yi] = skylight; - #endif - } - //nbt_end_list(n); - } else if (!strcmp(s, "HeightMap")) { - height = nbt_get(n, TAG_Int_Array, &len); - assert(len == 256); - } else - nbt_skip(n); - } - nbt_end_compound(n); - - } else - nbt_skip(n); - } - nbt_end_compound(n); - assert(n->cur == n->buffer_end); - return c; -} - -#define MAX_DECODED_CHUNK_X 64 -#define MAX_DECODED_CHUNK_Z 64 - -typedef struct -{ - int cx,cz; - fast_chunk *fc; - int valid; -} decoded_buffer; - -static decoded_buffer decoded_buffers[MAX_DECODED_CHUNK_Z][MAX_DECODED_CHUNK_X]; -void lock_chunk_get_mutex(void); -void unlock_chunk_get_mutex(void); - -#ifdef FAST_CHUNK -fast_chunk *get_decoded_fastchunk_uncached(int chunk_x, int chunk_z) -{ - unsigned char *decoded; - compressed_chunk *cc; - int inlen; - int len; - fast_chunk *fc; - - lock_chunk_get_mutex(); - cc = get_compressed_chunk(chunk_x, chunk_z); - if (cc->len != 0) - ++cc->refcount; - unlock_chunk_get_mutex(); - - if (cc->len == 0) - return NULL; - - assert(cc != NULL); - - assert(cc->data[4] == 2); - - inlen = nbt_parse_uint32(cc->data); - decoded = stbi_zlib_decode_malloc_guesssize(cc->data+5, inlen, inlen*3, &len); - assert(decoded != NULL); - assert(len != 0); - - lock_chunk_get_mutex(); - deref_compressed_chunk(cc); - unlock_chunk_get_mutex(); - - #ifdef FAST_CHUNK - fc = minecraft_chunk_parse(decoded, len); - #else - fc = NULL; - #endif - if (fc == NULL) - free(decoded); - return fc; -} - - -decoded_buffer *get_decoded_buffer(int chunk_x, int chunk_z) -{ - decoded_buffer *db = &decoded_buffers[chunk_z&(MAX_DECODED_CHUNK_Z-1)][chunk_x&(MAX_DECODED_CHUNK_X-1)]; - if (db->valid) { - if (db->cx == chunk_x && db->cz == chunk_z) - return db; - if (db->fc) { - free(db->fc->pointer_to_free); - free(db->fc); - } - } - - db->cx = chunk_x; - db->cz = chunk_z; - db->valid = 1; - db->fc = 0; - - { - db->fc = get_decoded_fastchunk_uncached(chunk_x, chunk_z); - return db; - } -} - -fast_chunk *get_decoded_fastchunk(int chunk_x, int chunk_z) -{ - decoded_buffer *db = get_decoded_buffer(chunk_x, chunk_z); - return db->fc; -} -#endif - -#ifndef FAST_CHUNK -chunk *get_decoded_chunk_raw(int chunk_x, int chunk_z) -{ - unsigned char *decoded; - compressed_chunk *cc = get_compressed_chunk(chunk_x, chunk_z); - assert(cc != NULL); - if (cc->len == 0) - return NULL; - else { - chunk *ch; - int inlen = nbt_parse_uint32(cc->data); - int len; - assert(cc->data[4] == 2); - decoded = stbi_zlib_decode_malloc_guesssize(cc->data+5, inlen, inlen*3, &len); - assert(decoded != NULL); - #ifdef FAST_CHUNK - ch = NULL; - #else - ch = minecraft_chunk_parse(decoded, len); - #endif - free(decoded); - return ch; - } -} - -static chunk *decoded_chunks[MAX_DECODED_CHUNK_Z][MAX_DECODED_CHUNK_X]; -chunk *get_decoded_chunk(int chunk_x, int chunk_z) -{ - chunk *c = decoded_chunks[chunk_z&(MAX_DECODED_CHUNK_Z-1)][chunk_x&(MAX_DECODED_CHUNK_X-1)]; - if (c && c->xpos == chunk_x && c->zpos == chunk_z) - return c; - if (c) free(c); - c = get_decoded_chunk_raw(chunk_x, chunk_z); - decoded_chunks[chunk_z&(MAX_DECODED_CHUNK_Z-1)][chunk_x&(MAX_DECODED_CHUNK_X-1)] = c; - return c; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/caveview/cave_parse.h b/source/engine/thirdparty/stb/tests/caveview/cave_parse.h deleted file mode 100644 index 4cdfe2a..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/cave_parse.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef INCLUDE_CAVE_PARSE_H -#define INCLUDE_CAVE_PARSE_H - -typedef struct -{ - unsigned char block; - unsigned char data; - unsigned char light:4; - unsigned char skylight:4; -} raw_block; - -// this is the old fully-decoded chunk -typedef struct -{ - int xpos, zpos, max_y; - int height[16][16]; - raw_block rb[16][16][256]; // [z][x][y] which becomes [y][x][z] in stb -} chunk; - -chunk *get_decoded_chunk(int chunk_x, int chunk_z); - -#define NUM_SEGMENTS 16 -typedef struct -{ - int max_y, xpos, zpos; - - unsigned char *blockdata[NUM_SEGMENTS]; - unsigned char *data[NUM_SEGMENTS]; - unsigned char *skylight[NUM_SEGMENTS]; - unsigned char *light[NUM_SEGMENTS]; - - void *pointer_to_free; - - int refcount; // this allows multi-threaded building without wrapping in ANOTHER struct -} fast_chunk; - -fast_chunk *get_decoded_fastchunk(int chunk_x, int chunk_z); // cache, never call free() - -fast_chunk *get_decoded_fastchunk_uncached(int chunk_x, int chunk_z); - -#endif diff --git a/source/engine/thirdparty/stb/tests/caveview/cave_render.c b/source/engine/thirdparty/stb/tests/caveview/cave_render.c deleted file mode 100644 index 3ed4628..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/cave_render.c +++ /dev/null @@ -1,951 +0,0 @@ -// This file renders vertex buffers, converts raw meshes -// to GL meshes, and manages threads that do the raw-mesh -// building (found in cave_mesher.c) - - -#include "stb_voxel_render.h" - -#define STB_GLEXT_DECLARE "glext_list.h" -#include "stb_gl.h" -#include "stb_image.h" -#include "stb_glprog.h" - -#include "caveview.h" -#include "cave_parse.h" -#include "stb.h" -#include "sdl.h" -#include "sdl_thread.h" -#include -#include - -//#define STBVOX_CONFIG_TEX1_EDGE_CLAMP - - -// currently no dynamic way to set mesh cache size or view distance -//#define SHORTVIEW - - -stbvox_mesh_maker g_mesh_maker; - -GLuint main_prog; -GLint uniform_locations[64]; - -//#define MAX_QUADS_PER_DRAW (65536 / 4) // assuming 16-bit indices, 4 verts per quad -//#define FIXED_INDEX_BUFFER_SIZE (MAX_QUADS_PER_DRAW * 6 * 2) // 16*1024 * 12 == ~192KB - -// while uploading texture data, this holds our each texture -#define TEX_SIZE 64 -uint32 texture[TEX_SIZE][TEX_SIZE]; - -GLuint voxel_tex[2]; - -// chunk state -enum -{ - STATE_invalid, - STATE_needed, - STATE_requested, - STATE_abandoned, - STATE_valid, -}; - -// mesh is 32x32x255 ... this is hardcoded in that -// a mesh covers 2x2 minecraft chunks, no #defines for it -typedef struct -{ - int state; - int chunk_x, chunk_y; - int num_quads; - float priority; - int vbuf_size, fbuf_size; - - float transform[3][3]; - float bounds[2][3]; - - GLuint vbuf;// vbuf_tex; - GLuint fbuf, fbuf_tex; - -} chunk_mesh; - -void scale_texture(unsigned char *src, int x, int y, int w, int h) -{ - int i,j,k; - assert(w == 256 && h == 256); - for (j=0; j < TEX_SIZE; ++j) { - for (i=0; i < TEX_SIZE; ++i) { - uint32 val=0; - for (k=0; k < 4; ++k) { - val >>= 8; - val += src[ 4*(x+(i>>2)) + 4*w*(y+(j>>2)) + k]<<24; - } - texture[j][i] = val; - } - } -} - -void build_base_texture(int n) -{ - int x,y; - uint32 color = stb_rand() | 0x808080; - for (y=0; ystate == STATE_valid) { - glDeleteTextures(1, &cm->fbuf_tex); - glDeleteBuffersARB(1, &cm->vbuf); - glDeleteBuffersARB(1, &cm->fbuf); - cached_chunk_mesh[slot_y][slot_x].state = STATE_invalid; - } -} - -void upload_mesh(chunk_mesh *cm, uint8 *build_buffer, uint8 *face_buffer) -{ - glGenBuffersARB(1, &cm->vbuf); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, cm->vbuf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, cm->num_quads*4*sizeof(uint32), build_buffer, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glGenBuffersARB(1, &cm->fbuf); - glBindBufferARB(GL_TEXTURE_BUFFER_ARB, cm->fbuf); - glBufferDataARB(GL_TEXTURE_BUFFER_ARB, cm->num_quads*sizeof(uint32), face_buffer , GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_TEXTURE_BUFFER_ARB, 0); - - glGenTextures(1, &cm->fbuf_tex); - glBindTexture(GL_TEXTURE_BUFFER_ARB, cm->fbuf_tex); - glTexBufferARB(GL_TEXTURE_BUFFER_ARB, GL_RGBA8UI, cm->fbuf); - glBindTexture(GL_TEXTURE_BUFFER_ARB, 0); -} - -static void upload_mesh_data(raw_mesh *rm) -{ - int cx = rm->cx; - int cy = rm->cy; - int slot_x = (cx >> 1) & (CACHED_MESH_NUM_X-1); - int slot_y = (cy >> 1) & (CACHED_MESH_NUM_Y-1); - chunk_mesh *cm; - - free_chunk(slot_x, slot_y); - - cm = &cached_chunk_mesh[slot_y][slot_x]; - cm->num_quads = rm->num_quads; - - upload_mesh(cm, rm->build_buffer, rm->face_buffer); - cm->vbuf_size = rm->num_quads*4*sizeof(uint32); - cm->fbuf_size = rm->num_quads*sizeof(uint32); - cm->priority = 100000; - cm->chunk_x = cx; - cm->chunk_y = cy; - - memcpy(cm->bounds, rm->bounds, sizeof(cm->bounds)); - memcpy(cm->transform, rm->transform, sizeof(cm->transform)); - - // write barrier here - cm->state = STATE_valid; -} - -GLint uniform_loc[16]; -float table3[128][3]; -float table4[64][4]; -GLint tablei[2]; - -float step=0; - -#ifdef SHORTVIEW -int view_dist_in_chunks = 50; -#else -int view_dist_in_chunks = 80; -#endif - -void setup_uniforms(float pos[3]) -{ - int i,j; - step += 1.0f/60.0f; - for (i=0; i < STBVOX_UNIFORM_count; ++i) { - stbvox_uniform_info raw, *ui=&raw; - stbvox_get_uniform_info(&raw, i); - uniform_loc[i] = -1; - - if (i == STBVOX_UNIFORM_texscale || i == STBVOX_UNIFORM_texgen || i == STBVOX_UNIFORM_color_table) - continue; - - if (ui) { - void *data = ui->default_value; - uniform_loc[i] = stbgl_find_uniform(main_prog, ui->name); - switch (i) { - case STBVOX_UNIFORM_face_data: - tablei[0] = 2; - data = tablei; - break; - - case STBVOX_UNIFORM_tex_array: - glActiveTextureARB(GL_TEXTURE0_ARB); - glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, voxel_tex[0]); - glActiveTextureARB(GL_TEXTURE1_ARB); - glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, voxel_tex[1]); - glActiveTextureARB(GL_TEXTURE0_ARB); - tablei[0] = 0; - tablei[1] = 1; - data = tablei; - break; - - case STBVOX_UNIFORM_color_table: - data = ui->default_value; - ((float *)data)[63*4+3] = 2.0f; // emissive - break; - - case STBVOX_UNIFORM_camera_pos: - data = table3[0]; - table3[0][0] = pos[0]; - table3[0][1] = pos[1]; - table3[0][2] = pos[2]; - table3[0][3] = stb_max(0,(float)sin(step*2)*0.125f); - break; - - case STBVOX_UNIFORM_ambient: { - float bright = 1.0; - //float bright = 0.75; - float amb[3][3]; - - // ambient direction is sky-colored upwards - // "ambient" lighting is from above - table4[0][0] = 0.3f; - table4[0][1] = -0.5f; - table4[0][2] = 0.9f; - - amb[1][0] = 0.3f; amb[1][1] = 0.3f; amb[1][2] = 0.3f; // dark-grey - amb[2][0] = 1.0; amb[2][1] = 1.0; amb[2][2] = 1.0; // white - - // convert so (table[1]*dot+table[2]) gives - // above interpolation - // lerp((dot+1)/2, amb[1], amb[2]) - // amb[1] + (amb[2] - amb[1]) * (dot+1)/2 - // amb[1] + (amb[2] - amb[1]) * dot/2 + (amb[2]-amb[1])/2 - - for (j=0; j < 3; ++j) { - table4[1][j] = (amb[2][j] - amb[1][j])/2 * bright; - table4[2][j] = (amb[1][j] + amb[2][j])/2 * bright; - } - - // fog color - table4[3][0] = 0.6f, table4[3][1] = 0.7f, table4[3][2] = 0.9f; - table4[3][3] = 1.0f / (view_dist_in_chunks * 16); - table4[3][3] *= table4[3][3]; - - data = table4; - break; - } - } - - switch (ui->type) { - case STBVOX_UNIFORM_TYPE_sampler: stbglUniform1iv(uniform_loc[i], ui->array_length, data); break; - case STBVOX_UNIFORM_TYPE_vec2: stbglUniform2fv(uniform_loc[i], ui->array_length, data); break; - case STBVOX_UNIFORM_TYPE_vec3: stbglUniform3fv(uniform_loc[i], ui->array_length, data); break; - case STBVOX_UNIFORM_TYPE_vec4: stbglUniform4fv(uniform_loc[i], ui->array_length, data); break; - } - } - } -} - -GLuint unitex[64], unibuf[64]; -void make_texture_buffer_for_uniform(int uniform, int slot) -{ - GLenum type; - stbvox_uniform_info raw, *ui=&raw; - GLint uloc; - - stbvox_get_uniform_info(ui, uniform); - uloc = stbgl_find_uniform(main_prog, ui->name); - - if (uniform == STBVOX_UNIFORM_color_table) - ((float *)ui->default_value)[63*4+3] = 2.0f; // emissive - - glGenBuffersARB(1, &unibuf[uniform]); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, unibuf[uniform]); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, ui->array_length * ui->bytes_per_element, ui->default_value, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glGenTextures(1, &unitex[uniform]); - glBindTexture(GL_TEXTURE_BUFFER_ARB, unitex[uniform]); - switch (ui->type) { - case STBVOX_UNIFORM_TYPE_vec2: type = GL_RG32F; break; - case STBVOX_UNIFORM_TYPE_vec3: type = GL_RGB32F; break; - case STBVOX_UNIFORM_TYPE_vec4: type = GL_RGBA32F; break; - default: assert(0); - } - glTexBufferARB(GL_TEXTURE_BUFFER_ARB, type, unibuf[uniform]); - glBindTexture(GL_TEXTURE_BUFFER_ARB, 0); - - glActiveTextureARB(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_BUFFER_ARB, unitex[uniform]); - glActiveTextureARB(GL_TEXTURE0); - - stbglUseProgram(main_prog); - stbglUniform1i(uloc, slot); -} - -#define MAX_MESH_WORKERS 8 -#define MAX_CHUNK_LOAD_WORKERS 2 - -int num_mesh_workers; -int num_chunk_load_workers; - -typedef struct -{ - int state; - int request_cx; - int request_cy; - int padding[13]; - - SDL_sem * request_received; - - SDL_sem * chunk_server_done_processing; - int chunk_action; - int chunk_request_x; - int chunk_request_y; - fast_chunk *chunks[4][4]; - - int padding2[16]; - raw_mesh rm; - int padding3[16]; - - uint8 *build_buffer; - uint8 *face_buffer ; -} mesh_worker; - -enum -{ - WSTATE_idle, - WSTATE_requested, - WSTATE_running, - WSTATE_mesh_ready, -}; - -mesh_worker mesh_data[MAX_MESH_WORKERS]; -int num_meshes_started; // stats - -int request_chunk(int chunk_x, int chunk_y); -void update_meshes_from_render_thread(void); - -unsigned char tex2_data[64][4]; - -void init_tex2_gradient(void) -{ - int i; - for (i=0; i < 16; ++i) { - tex2_data[i+ 0][0] = 64 + 12*i; - tex2_data[i+ 0][1] = 32; - tex2_data[i+ 0][2] = 64; - - tex2_data[i+16][0] = 255; - tex2_data[i+16][1] = 32 + 8*i; - tex2_data[i+16][2] = 64; - - tex2_data[i+32][0] = 255; - tex2_data[i+32][1] = 160; - tex2_data[i+32][2] = 64 + 12*i; - - tex2_data[i+48][0] = 255; - tex2_data[i+48][1] = 160 + 6*i; - tex2_data[i+48][2] = 255; - } -} - -void set_tex2_alpha(float fa) -{ - int i; - int a = (int) stb_lerp(fa, 0, 255); - if (a < 0) a = 0; else if (a > 255) a = 255; - glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, voxel_tex[1]); - for (i=0; i < 64; ++i) { - tex2_data[i][3] = a; - glTexSubImage3DEXT(GL_TEXTURE_2D_ARRAY_EXT, 0, 0,0,i, 1,1,1, GL_RGBA, GL_UNSIGNED_BYTE, tex2_data[i]); - } -} - -void render_init(void) -{ - int i; - char *binds[] = { "attr_vertex", "attr_face", NULL }; - char *vertex; - char *fragment; - int w=0,h=0; - - unsigned char *texdata = stbi_load("terrain.png", &w, &h, NULL, 4); - - stbvox_init_mesh_maker(&g_mesh_maker); - for (i=0; i < num_mesh_workers; ++i) { - stbvox_init_mesh_maker(&mesh_data[i].rm.mm); - } - - vertex = stbvox_get_vertex_shader(); - fragment = stbvox_get_fragment_shader(); - - { - char error_buffer[1024]; - char *main_vertex[] = { vertex, NULL }; - char *main_fragment[] = { fragment, NULL }; - main_prog = stbgl_create_program(main_vertex, main_fragment, binds, error_buffer, sizeof(error_buffer)); - if (main_prog == 0) { - ods("Compile error for main shader: %s\n", error_buffer); - assert(0); - exit(1); - } - } - //init_index_buffer(); - - make_texture_buffer_for_uniform(STBVOX_UNIFORM_texscale , 3); - make_texture_buffer_for_uniform(STBVOX_UNIFORM_texgen , 4); - make_texture_buffer_for_uniform(STBVOX_UNIFORM_color_table , 5); - - glGenTextures(2, voxel_tex); - - glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, voxel_tex[0]); - glTexImage3DEXT(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGBA, - TEX_SIZE,TEX_SIZE,256, - 0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); - for (i=0; i < 256; ++i) { - if (texdata) - scale_texture(texdata, (i&15)*w/16, (h/16)*(i>>4), w,h); - else - build_base_texture(i); - glTexSubImage3DEXT(GL_TEXTURE_2D_ARRAY_EXT, 0, 0,0,i, TEX_SIZE,TEX_SIZE,1, GL_RGBA, GL_UNSIGNED_BYTE, texture[0]); - } - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16); - #ifdef STBVOX_CONFIG_TEX1_EDGE_CLAMP - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - #endif - - glGenerateMipmapEXT(GL_TEXTURE_2D_ARRAY_EXT); - - glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, voxel_tex[1]); - glTexImage3DEXT(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGBA, - 1,1,64, - 0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); - init_tex2_gradient(); - set_tex2_alpha(0.0); - #if 0 - for (i=0; i < 128; ++i) { - //build_overlay_texture(i); - glTexSubImage3DEXT(GL_TEXTURE_2D_ARRAY_EXT, 0, 0,0,i, TEX_SIZE,TEX_SIZE,1, GL_RGBA, GL_UNSIGNED_BYTE, texture[0]); - } - #endif - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glGenerateMipmapEXT(GL_TEXTURE_2D_ARRAY_EXT); -} - -void world_init(void) -{ - int a,b,x,y; - - Uint64 start_time, end_time; - #ifdef NDEBUG - int range = 32; - #else - int range = 12; - #endif - - start_time = SDL_GetPerformanceCounter(); - - // iterate in 8x8 clusters of qchunks at a time to get better converted-chunk-cache reuse - // than a purely row-by-row ordering is (single-threaded this is a bigger win than - // any of the above optimizations were, since it halves zlib/mc-conversion costs) - for (x=-range; x <= range; x += 16) - for (y=-range; y <= range; y += 16) - for (b=y; b < y+16 && b <= range; b += 2) - for (a=x; a < x+16 && a <= range; a += 2) - while (!request_chunk(a, b)) { // if request fails, all threads are busy - update_meshes_from_render_thread(); - SDL_Delay(1); - } - - // wait until all the workers are done, - // (this is only needed if we want to time - // when the build finishes, or when we want to reset the - // cache size; otherwise we could just go ahead and - // start rendering whatever we've got) - for(;;) { - int i; - update_meshes_from_render_thread(); - for (i=0; i < num_mesh_workers; ++i) - if (mesh_data[i].state != WSTATE_idle) - break; - if (i == num_mesh_workers) - break; - SDL_Delay(3); - } - - end_time = SDL_GetPerformanceCounter(); - ods("Build time: %7.2fs\n", (end_time - start_time) / (float) SDL_GetPerformanceFrequency()); - - // don't waste lots of storage on chunk caches once it's finished starting-up; - // this was only needed to be this large because we worked in large blocks - // to maximize sharing - reset_cache_size(32); -} - -extern SDL_mutex * chunk_cache_mutex; - -int mesh_worker_handler(void *data) -{ - mesh_worker *mw = data; - mw->face_buffer = malloc(FACE_BUFFER_SIZE); - mw->build_buffer = malloc(BUILD_BUFFER_SIZE); - - // this loop only works because the compiler can't - // tell that the SDL_calls don't access mw->state; - // really we should barrier that stuff - for(;;) { - int i,j; - int cx,cy; - - // wait for a chunk request - SDL_SemWait(mw->request_received); - - // analyze the chunk request - assert(mw->state == WSTATE_requested); - cx = mw->request_cx; - cy = mw->request_cy; - - // this is inaccurate as it can block while another thread has the cache locked - mw->state = WSTATE_running; - - // get the chunks we need (this takes a lock and caches them) - for (j=0; j < 4; ++j) - for (i=0; i < 4; ++i) - mw->chunks[j][i] = get_converted_fastchunk(cx-1 + i, cy-1 + j); - - // build the mesh based on the chunks - mw->rm.build_buffer = mw->build_buffer; - mw->rm.face_buffer = mw->face_buffer; - build_chunk(cx, cy, mw->chunks, &mw->rm); - mw->state = WSTATE_mesh_ready; - // don't need to notify of this, because it gets polled - - // when done, free the chunks - - // for efficiency we just take the mutex once around the whole thing, - // though this spreads the mutex logic over two files - SDL_LockMutex(chunk_cache_mutex); - for (j=0; j < 4; ++j) - for (i=0; i < 4; ++i) { - deref_fastchunk(mw->chunks[j][i]); - mw->chunks[j][i] = NULL; - } - SDL_UnlockMutex(chunk_cache_mutex); - } - return 0; -} - -int request_chunk(int chunk_x, int chunk_y) -{ - int i; - for (i=0; i < num_mesh_workers; ++i) { - mesh_worker *mw = &mesh_data[i]; - if (mw->state == WSTATE_idle) { - mw->request_cx = chunk_x; - mw->request_cy = chunk_y; - mw->state = WSTATE_requested; - SDL_SemPost(mw->request_received); - ++num_meshes_started; - return 1; - } - } - return 0; -} - -void prepare_threads(void) -{ - int i; - int num_proc = SDL_GetCPUCount(); - - if (num_proc > 6) - num_mesh_workers = num_proc/2; - else if (num_proc > 4) - num_mesh_workers = 4; - else - num_mesh_workers = num_proc-1; - -// @TODO -// Thread usage is probably pretty terrible; need to make a -// separate queue of needed chunks, instead of just generating -// one request per thread per frame, and a separate queue of -// results. (E.g. If it takes 1.5 frames to build mesh, thread -// is idle for 0.5 frames.) To fake this for now, I've just -// doubled the number of threads to let those serve as a 'queue', -// but that's dumb. - - num_mesh_workers *= 2; // try to get better thread usage - - if (num_mesh_workers > MAX_MESH_WORKERS) - num_mesh_workers = MAX_MESH_WORKERS; - - for (i=0; i < num_mesh_workers; ++i) { - mesh_worker *data = &mesh_data[i]; - data->request_received = SDL_CreateSemaphore(0); - data->chunk_server_done_processing = SDL_CreateSemaphore(0); - SDL_CreateThread(mesh_worker_handler, "mesh worker", data); - } -} - - -// "better" buffer uploading -#if 0 - if (glBufferStorage) { - glDeleteBuffersARB(1, &vb->vbuf); - glGenBuffersARB(1, &vb->vbuf); - - glBindBufferARB(GL_ARRAY_BUFFER_ARB, vb->vbuf); - glBufferStorage(GL_ARRAY_BUFFER_ARB, sizeof(build_buffer), build_buffer, 0); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } else { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, vb->vbuf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(build_buffer), build_buffer, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } -#endif - - -typedef struct -{ - float x,y,z,w; -} plane; - -static plane frustum[6]; - -static void matd_mul(double out[4][4], double src1[4][4], double src2[4][4]) -{ - int i,j,k; - for (j=0; j < 4; ++j) { - for (i=0; i < 4; ++i) { - double t=0; - for (k=0; k < 4; ++k) - t += src1[k][i] * src2[j][k]; - out[i][j] = t; - } - } -} - -// https://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/ -static void compute_frustum(void) -{ - int i; - GLdouble mv[4][4],proj[4][4], mvproj[4][4]; - glGetDoublev(GL_MODELVIEW_MATRIX , mv[0]); - glGetDoublev(GL_PROJECTION_MATRIX, proj[0]); - matd_mul(mvproj, proj, mv); - for (i=0; i < 4; ++i) { - (&frustum[0].x)[i] = (float) (mvproj[3][i] + mvproj[0][i]); - (&frustum[1].x)[i] = (float) (mvproj[3][i] - mvproj[0][i]); - (&frustum[2].x)[i] = (float) (mvproj[3][i] + mvproj[1][i]); - (&frustum[3].x)[i] = (float) (mvproj[3][i] - mvproj[1][i]); - (&frustum[4].x)[i] = (float) (mvproj[3][i] + mvproj[2][i]); - (&frustum[5].x)[i] = (float) (mvproj[3][i] - mvproj[2][i]); - } -} - -static int test_plane(plane *p, float x0, float y0, float z0, float x1, float y1, float z1) -{ - // return false if the box is entirely behind the plane - float d=0; - assert(x0 <= x1 && y0 <= y1 && z0 <= z1); - if (p->x > 0) d += x1*p->x; else d += x0*p->x; - if (p->y > 0) d += y1*p->y; else d += y0*p->y; - if (p->z > 0) d += z1*p->z; else d += z0*p->z; - return d + p->w >= 0; -} - -static int is_box_in_frustum(float *bmin, float *bmax) -{ - int i; - for (i=0; i < 6; ++i) - if (!test_plane(&frustum[i], bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2])) - return 0; - return 1; -} - -float compute_priority(int cx, int cy, float x, float y) -{ - float distx, disty, dist2; - distx = (cx*16+8) - x; - disty = (cy*16+8) - y; - dist2 = distx*distx + disty*disty; - return view_dist_in_chunks*view_dist_in_chunks * 16 * 16 - dist2; -} - -int chunk_locations, chunks_considered, chunks_in_frustum; -int quads_considered, quads_rendered; -int chunk_storage_rendered, chunk_storage_considered, chunk_storage_total; -int update_frustum = 1; - -#ifdef SHORTVIEW -int max_chunk_storage = 450 << 20; -int min_chunk_storage = 350 << 20; -#else -int max_chunk_storage = 900 << 20; -int min_chunk_storage = 800 << 20; -#endif - -float min_priority = -500; // this really wants to be in unit space, not squared space - -int num_meshes_uploaded; - -void update_meshes_from_render_thread(void) -{ - int i; - for (i=0; i < num_mesh_workers; ++i) { - mesh_worker *mw = &mesh_data[i]; - if (mw->state == WSTATE_mesh_ready) { - upload_mesh_data(&mw->rm); - ++num_meshes_uploaded; - mw->state = WSTATE_idle; - } - } -} - -extern float tex2_alpha; -extern int global_hack; -int num_threads_active; -float chunk_server_activity; - -void render_caves(float campos[3]) -{ - float x = campos[0], y = campos[1]; - int qchunk_x, qchunk_y; - int cam_x, cam_y; - int i,j, rad; - - compute_frustum(); - - chunk_locations = chunks_considered = chunks_in_frustum = 0; - quads_considered = quads_rendered = 0; - chunk_storage_total = chunk_storage_considered = chunk_storage_rendered = 0; - - cam_x = (int) floor(x+0.5); - cam_y = (int) floor(y+0.5); - - qchunk_x = (((int) floor(x)+16) >> 5) << 1; - qchunk_y = (((int) floor(y)+16) >> 5) << 1; - - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5); - - stbglUseProgram(main_prog); - setup_uniforms(campos); // set uniforms to default values inefficiently - glActiveTextureARB(GL_TEXTURE2_ARB); - stbglEnableVertexAttribArray(0); - - { - float lighting[2][3] = { { campos[0],campos[1],campos[2] }, { 0.75,0.75,0.65f } }; - float bright = 8; - lighting[1][0] *= bright; - lighting[1][1] *= bright; - lighting[1][2] *= bright; - stbglUniform3fv(stbgl_find_uniform(main_prog, "light_source"), 2, lighting[0]); - } - - if (global_hack) - set_tex2_alpha(tex2_alpha); - - num_meshes_uploaded = 0; - update_meshes_from_render_thread(); - - // traverse all in-range chunks and analyze them - for (j=-view_dist_in_chunks; j <= view_dist_in_chunks; j += 2) { - for (i=-view_dist_in_chunks; i <= view_dist_in_chunks; i += 2) { - float priority; - int cx = qchunk_x + i; - int cy = qchunk_y + j; - - priority = compute_priority(cx, cy, x, y); - if (priority >= min_priority) { - int slot_x = (cx>>1) & (CACHED_MESH_NUM_X-1); - int slot_y = (cy>>1) & (CACHED_MESH_NUM_Y-1); - chunk_mesh *cm = &cached_chunk_mesh[slot_y][slot_x]; - ++chunk_locations; - if (cm->state == STATE_valid && priority >= 0) { - // check if chunk pos actually matches - if (cm->chunk_x != cx || cm->chunk_y != cy) { - // we have a stale chunk we need to recreate - free_chunk(slot_x, slot_y); // it probably will have already gotten freed, but just in case - } - } - if (cm->state == STATE_invalid) { - cm->chunk_x = cx; - cm->chunk_y = cy; - cm->state = STATE_needed; - } - cm->priority = priority; - } - } - } - - // draw front-to-back - for (rad = 0; rad <= view_dist_in_chunks; rad += 2) { - for (j=-rad; j <= rad; j += 2) { - // if j is +- rad, then iterate i through all values - // if j isn't +-rad, then i should be only -rad & rad - int step = 2; - if (abs(j) != rad) - step = 2*rad; - for (i=-rad; i <= rad; i += step) { - int cx = qchunk_x + i; - int cy = qchunk_y + j; - int slot_x = (cx>>1) & (CACHED_MESH_NUM_X-1); - int slot_y = (cy>>1) & (CACHED_MESH_NUM_Y-1); - chunk_mesh *cm = &cached_chunk_mesh[slot_y][slot_x]; - if (cm->state == STATE_valid && cm->priority >= 0) { - ++chunks_considered; - quads_considered += cm->num_quads; - if (is_box_in_frustum(cm->bounds[0], cm->bounds[1])) { - ++chunks_in_frustum; - - // @TODO if in range - stbglUniform3fv(uniform_loc[STBVOX_UNIFORM_transform], 3, cm->transform[0]); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, cm->vbuf); - glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 4, (void*) 0); - glBindTexture(GL_TEXTURE_BUFFER_ARB, cm->fbuf_tex); - glDrawArrays(GL_QUADS, 0, cm->num_quads*4); - quads_rendered += cm->num_quads; - - chunk_storage_rendered += cm->vbuf_size + cm->fbuf_size; - } - chunk_storage_considered += cm->vbuf_size + cm->fbuf_size; - } - } - } - } - - stbglDisableVertexAttribArray(0); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glActiveTextureARB(GL_TEXTURE0_ARB); - - stbglUseProgram(0); - num_meshes_started = 0; - - { - #define MAX_QUEUE 8 - float highest_priority[MAX_QUEUE]; - int highest_i[MAX_QUEUE], highest_j[MAX_QUEUE]; - float lowest_priority = view_dist_in_chunks * view_dist_in_chunks * 16 * 16.0f; - int lowest_i = -1, lowest_j = -1; - - for (i=0; i < MAX_QUEUE; ++i) { - highest_priority[i] = min_priority; - highest_i[i] = -1; - highest_j[i] = -1; - } - - for (j=0; j < CACHED_MESH_NUM_Y; ++j) { - for (i=0; i < CACHED_MESH_NUM_X; ++i) { - chunk_mesh *cm = &cached_chunk_mesh[j][i]; - if (cm->state == STATE_valid) { - cm->priority = compute_priority(cm->chunk_x, cm->chunk_y, x, y); - chunk_storage_total += cm->vbuf_size + cm->fbuf_size; - if (cm->priority < lowest_priority) { - lowest_priority = cm->priority; - lowest_i = i; - lowest_j = j; - } - } - if (cm->state == STATE_needed) { - cm->priority = compute_priority(cm->chunk_x, cm->chunk_y, x, y); - if (cm->priority < min_priority) - cm->state = STATE_invalid; - else if (cm->priority > highest_priority[0]) { - int k; - highest_priority[0] = cm->priority; - highest_i[0] = i; - highest_j[0] = j; - // bubble this up to right place - for (k=0; k < MAX_QUEUE-1; ++k) { - if (highest_priority[k] > highest_priority[k+1]) { - highest_priority[k] = highest_priority[k+1]; - highest_priority[k+1] = cm->priority; - highest_i[k] = highest_i[k+1]; - highest_i[k+1] = i; - highest_j[k] = highest_j[k+1]; - highest_j[k+1] = j; - } else { - break; - } - } - } - } - } - } - - - // I couldn't find any straightforward logic that avoids - // the hysteresis problem of continually creating & freeing - // a block on the margin, so I just don't free a block until - // it's out of range, but this doesn't actually correctly - // handle when the cache is too small for the given range - if (chunk_storage_total >= min_chunk_storage && lowest_i >= 0) { - if (cached_chunk_mesh[lowest_j][lowest_i].priority < -1200) // -1000? 0? - free_chunk(lowest_i, lowest_j); - } - - if (chunk_storage_total < max_chunk_storage && highest_i[0] >= 0) { - for (j=MAX_QUEUE-1; j >= 0; --j) { - if (highest_j[0] >= 0) { - chunk_mesh *cm = &cached_chunk_mesh[highest_j[j]][highest_i[j]]; - if (request_chunk(cm->chunk_x, cm->chunk_y)) { - cm->state = STATE_requested; - } else { - // if we couldn't queue this one, skip the remainder - break; - } - } - } - } - } - - update_meshes_from_render_thread(); - - num_threads_active = 0; - for (i=0; i < num_mesh_workers; ++i) { - num_threads_active += (mesh_data[i].state == WSTATE_running); - } -} diff --git a/source/engine/thirdparty/stb/tests/caveview/caveview.dsp b/source/engine/thirdparty/stb/tests/caveview/caveview.dsp deleted file mode 100644 index 2a462d3..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/caveview.dsp +++ /dev/null @@ -1,157 +0,0 @@ -# Microsoft Developer Studio Project File - Name="caveview" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=caveview - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "caveview.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "caveview.mak" CFG="caveview - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "caveview - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "caveview - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "caveview - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /WX /GX /Zd /O2 /I "../.." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl2.lib opengl32.lib glu32.lib winmm.lib sdl2_mixer.lib advapi32.lib /nologo /subsystem:windows /debug /machine:I386 -# SUBTRACT LINK32 /map - -!ELSEIF "$(CFG)" == "caveview - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /Zi /Od /I "../.." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl2.lib opengl32.lib glu32.lib winmm.lib sdl2_mixer.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "caveview - Win32 Release" -# Name "caveview - Win32 Debug" -# Begin Source File - -SOURCE=.\cave_main.c -# End Source File -# Begin Source File - -SOURCE=.\cave_mesher.c -# End Source File -# Begin Source File - -SOURCE=.\cave_parse.c -# End Source File -# Begin Source File - -SOURCE=.\cave_parse.h -# End Source File -# Begin Source File - -SOURCE=.\cave_render.c -# End Source File -# Begin Source File - -SOURCE=.\caveview.h -# End Source File -# Begin Source File - -SOURCE=.\glext.h -# End Source File -# Begin Source File - -SOURCE=.\glext_list.h -# End Source File -# Begin Source File - -SOURCE=.\README.md -# End Source File -# Begin Source File - -SOURCE=.\win32\SDL_windows_main.c -# End Source File -# Begin Source File - -SOURCE=..\..\stb.h -# End Source File -# Begin Source File - -SOURCE=..\..\stb_easy_font.h -# End Source File -# Begin Source File - -SOURCE=.\stb_gl.h -# End Source File -# Begin Source File - -SOURCE=.\stb_glprog.h -# End Source File -# Begin Source File - -SOURCE=..\..\stb_image.h -# End Source File -# Begin Source File - -SOURCE=..\..\stb_voxel_render.h -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/caveview/caveview.dsw b/source/engine/thirdparty/stb/tests/caveview/caveview.dsw deleted file mode 100644 index ddc9387..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/caveview.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "caveview"=.\caveview.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/source/engine/thirdparty/stb/tests/caveview/caveview.h b/source/engine/thirdparty/stb/tests/caveview/caveview.h deleted file mode 100644 index 73a71da..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/caveview.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef INCLUDE_CAVEVIEW_H -#define INCLUDE_CAVEVIEW_H - -#include "stb.h" - -#include "stb_voxel_render.h" - -typedef struct -{ - int cx,cy; - - stbvox_mesh_maker mm; - - uint8 *build_buffer; - uint8 *face_buffer; - - int num_quads; - float transform[3][3]; - float bounds[2][3]; - - uint8 sv_blocktype[34][34][18]; - uint8 sv_lighting [34][34][18]; -} raw_mesh; - -// a 3D checkerboard of empty,solid would be: 32x32x255x6/2 ~= 800000 -// an all-leaf qchunk would be: 32 x 32 x 255 x 6 ~= 1,600,000 - -#define BUILD_QUAD_MAX 400000 -#define BUILD_BUFFER_SIZE (4*4*BUILD_QUAD_MAX) // 4 bytes per vertex, 4 vertices per quad -#define FACE_BUFFER_SIZE ( 4*BUILD_QUAD_MAX) // 4 bytes per quad - - -extern void mesh_init(void); -extern void render_init(void); -extern void world_init(void); -extern void ods(char *fmt, ...); // output debug string -extern void reset_cache_size(int size); - - -extern void render_caves(float pos[3]); - - -#include "cave_parse.h" // fast_chunk - -extern fast_chunk *get_converted_fastchunk(int chunk_x, int chunk_y); -extern void build_chunk(int chunk_x, int chunk_y, fast_chunk *fc_table[4][4], raw_mesh *rm); -extern void reset_cache_size(int size); -extern void deref_fastchunk(fast_chunk *fc); - -#endif \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/caveview/glext.h b/source/engine/thirdparty/stb/tests/caveview/glext.h deleted file mode 100644 index c6a233a..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/glext.h +++ /dev/null @@ -1,11124 +0,0 @@ -#ifndef __glext_h_ -#define __glext_h_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2013 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE 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 OR COPYRIGHT HOLDERS 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 -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ -/* -** This header is generated from the Khronos OpenGL / OpenGL ES XML -** API Registry. The current version of the Registry, generator scripts -** used to make the header, and the header can be found at -** http://www.opengl.org/registry/ -** -** Khronos $Revision: 24756 $ on $Date: 2014-01-14 03:42:29 -0800 (Tue, 14 Jan 2014) $ -*/ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -#define GL_GLEXT_VERSION 20140114 - -/* Generated C header for: - * API: gl - * Profile: compatibility - * Versions considered: .* - * Versions emitted: 1\.[2-9]|[234]\.[0-9] - * Default extensions included: gl - * Additional extensions included: _nomatch_^ - * Extensions removed: _nomatch_^ - */ - -#ifndef GL_VERSION_1_2 -#define GL_VERSION_1_2 1 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_RESCALE_NORMAL 0x803A -#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define GL_SINGLE_COLOR 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR 0x81FA -#define GL_ALIASED_POINT_SIZE_RANGE 0x846D -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif -#endif /* GL_VERSION_1_2 */ - -#ifndef GL_VERSION_1_3 -#define GL_VERSION_1_3 1 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define GL_MAX_TEXTURE_UNITS 0x84E2 -#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 -#define GL_MULTISAMPLE_BIT 0x20000000 -#define GL_NORMAL_MAP 0x8511 -#define GL_REFLECTION_MAP 0x8512 -#define GL_COMPRESSED_ALPHA 0x84E9 -#define GL_COMPRESSED_LUMINANCE 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define GL_COMPRESSED_INTENSITY 0x84EC -#define GL_COMBINE 0x8570 -#define GL_COMBINE_RGB 0x8571 -#define GL_COMBINE_ALPHA 0x8572 -#define GL_SOURCE0_RGB 0x8580 -#define GL_SOURCE1_RGB 0x8581 -#define GL_SOURCE2_RGB 0x8582 -#define GL_SOURCE0_ALPHA 0x8588 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SOURCE2_ALPHA 0x858A -#define GL_OPERAND0_RGB 0x8590 -#define GL_OPERAND1_RGB 0x8591 -#define GL_OPERAND2_RGB 0x8592 -#define GL_OPERAND0_ALPHA 0x8598 -#define GL_OPERAND1_ALPHA 0x8599 -#define GL_OPERAND2_ALPHA 0x859A -#define GL_RGB_SCALE 0x8573 -#define GL_ADD_SIGNED 0x8574 -#define GL_INTERPOLATE 0x8575 -#define GL_SUBTRACT 0x84E7 -#define GL_CONSTANT 0x8576 -#define GL_PRIMARY_COLOR 0x8577 -#define GL_PREVIOUS 0x8578 -#define GL_DOT3_RGB 0x86AE -#define GL_DOT3_RGBA 0x86AF -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTexture (GLenum texture); -GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); -GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); -GLAPI void APIENTRY glClientActiveTexture (GLenum texture); -GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); -GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); -GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); -GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); -GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); -GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); -GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); -GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); -GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); -GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); -GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); -GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); -GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); -#endif -#endif /* GL_VERSION_1_3 */ - -#ifndef GL_VERSION_1_4 -#define GL_VERSION_1_4 1 -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_POINT_SIZE_MIN 0x8126 -#define GL_POINT_SIZE_MAX 0x8127 -#define GL_POINT_DISTANCE_ATTENUATION 0x8129 -#define GL_GENERATE_MIPMAP 0x8191 -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_FOG_COORDINATE_SOURCE 0x8450 -#define GL_FOG_COORDINATE 0x8451 -#define GL_FRAGMENT_DEPTH 0x8452 -#define GL_CURRENT_FOG_COORDINATE 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 -#define GL_FOG_COORDINATE_ARRAY 0x8457 -#define GL_COLOR_SUM 0x8458 -#define GL_CURRENT_SECONDARY_COLOR 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D -#define GL_SECONDARY_COLOR_ARRAY 0x845E -#define GL_TEXTURE_FILTER_CONTROL 0x8500 -#define GL_DEPTH_TEXTURE_MODE 0x884B -#define GL_COMPARE_R_TO_TEXTURE 0x884E -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); -typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); -typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); -GLAPI void APIENTRY glFogCoordf (GLfloat coord); -GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); -GLAPI void APIENTRY glFogCoordd (GLdouble coord); -GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); -GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); -GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); -GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); -GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); -GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); -GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); -GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); -GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); -GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); -GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); -GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); -GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); -GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); -GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); -GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2iv (const GLint *v); -GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); -GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3iv (const GLint *v); -GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); -GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI void APIENTRY glBlendEquation (GLenum mode); -#endif -#endif /* GL_VERSION_1_4 */ - -#ifndef GL_VERSION_1_5 -#define GL_VERSION_1_5 1 -#include -typedef ptrdiff_t GLsizeiptr; -typedef ptrdiff_t GLintptr; -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SRC1_ALPHA 0x8589 -#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E -#define GL_FOG_COORD_SRC 0x8450 -#define GL_FOG_COORD 0x8451 -#define GL_CURRENT_FOG_COORD 0x8453 -#define GL_FOG_COORD_ARRAY_TYPE 0x8454 -#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORD_ARRAY_POINTER 0x8456 -#define GL_FOG_COORD_ARRAY 0x8457 -#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D -#define GL_SRC0_RGB 0x8580 -#define GL_SRC1_RGB 0x8581 -#define GL_SRC2_RGB 0x8582 -#define GL_SRC0_ALPHA 0x8588 -#define GL_SRC2_ALPHA 0x858A -typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); -typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQuery (GLuint id); -GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQuery (GLenum target); -GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); -GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); -GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); -GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); -GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); -#endif -#endif /* GL_VERSION_1_5 */ - -#ifndef GL_VERSION_2_0 -#define GL_VERSION_2_0 1 -typedef char GLchar; -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 -#define GL_POINT_SPRITE 0x8861 -#define GL_COORD_REPLACE 0x8862 -#define GL_MAX_TEXTURE_COORDS 0x8871 -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); -typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); -GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); -GLAPI void APIENTRY glCompileShader (GLuint shader); -GLAPI GLuint APIENTRY glCreateProgram (void); -GLAPI GLuint APIENTRY glCreateShader (GLenum type); -GLAPI void APIENTRY glDeleteProgram (GLuint program); -GLAPI void APIENTRY glDeleteShader (GLuint shader); -GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); -GLAPI GLboolean APIENTRY glIsProgram (GLuint program); -GLAPI GLboolean APIENTRY glIsShader (GLuint shader); -GLAPI void APIENTRY glLinkProgram (GLuint program); -GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -GLAPI void APIENTRY glUseProgram (GLuint program); -GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glValidateProgram (GLuint program); -GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -#endif -#endif /* GL_VERSION_2_0 */ - -#ifndef GL_VERSION_2_1 -#define GL_VERSION_2_1 1 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F -#define GL_SLUMINANCE_ALPHA 0x8C44 -#define GL_SLUMINANCE8_ALPHA8 0x8C45 -#define GL_SLUMINANCE 0x8C46 -#define GL_SLUMINANCE8 0x8C47 -#define GL_COMPRESSED_SLUMINANCE 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -#endif -#endif /* GL_VERSION_2_1 */ - -#ifndef GL_VERSION_3_0 -#define GL_VERSION_3_0 1 -typedef unsigned short GLhalf; -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_INDEX 0x8222 -#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#define GL_CLAMP_VERTEX_COLOR 0x891A -#define GL_CLAMP_FRAGMENT_COLOR 0x891B -#define GL_ALPHA_INTEGER 0x8D97 -typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); -GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); -GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedback (void); -GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); -GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRender (void); -GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); -GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); -GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmap (GLenum target); -GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glBindVertexArray (GLuint array); -GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); -#endif -#endif /* GL_VERSION_3_0 */ - -#ifndef GL_VERSION_3_1 -#define GL_VERSION_3_1 1 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFFu -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); -GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); -GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -#endif -#endif /* GL_VERSION_3_1 */ - -#ifndef GL_VERSION_3_2 -#define GL_VERSION_3_2 1 -typedef struct __GLsync *GLsync; -#ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glxext.h, so must be protected */ -#define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GL_EXT_timer_query extension). */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(__sun__) || defined(__digital__) -#include -#if defined(__STDC__) -#if defined(__arch64__) || defined(_LP64) -typedef long int int64_t; -typedef unsigned long int uint64_t; -#else -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) -#include -#elif defined(__SCO__) || defined(__USLC__) -#include -#elif defined(__UNIXOS2__) || defined(__SOL64__) -typedef long int int32_t; -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif -#endif -typedef uint64_t GLuint64; -typedef int64_t GLint64; -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_DEPTH_CLAMP 0x864F -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); -typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); -typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -GLAPI void APIENTRY glProvokingVertex (GLenum mode); -GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); -GLAPI GLboolean APIENTRY glIsSync (GLsync sync); -GLAPI void APIENTRY glDeleteSync (GLsync sync); -GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); -GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); -GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); -#endif -#endif /* GL_VERSION_3_2 */ - -#ifndef GL_VERSION_3_3 -#define GL_VERSION_3_3 1 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -#define GL_SRC1_COLOR 0x88F9 -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#define GL_SAMPLER_BINDING 0x8919 -#define GL_RGB10_A2UI 0x906F -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#define GL_TIME_ELAPSED 0x88BF -#define GL_TIMESTAMP 0x8E28 -#define GL_INT_2_10_10_10_REV 0x8D9F -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); -typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); -typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); -typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); -GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); -GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); -GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); -GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); -GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); -GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); -GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); -GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); -GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); -GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); -GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); -GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); -GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); -GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); -#endif -#endif /* GL_VERSION_3_3 */ - -#ifndef GL_VERSION_4_0 -#define GL_VERSION_4_0 1 -#define GL_SAMPLE_SHADING 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F -#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F -#define GL_DRAW_INDIRECT_BUFFER 0x8F3F -#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 -#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C -#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D -#define GL_MAX_VERTEX_STREAMS 0x8E71 -#define GL_DOUBLE_VEC2 0x8FFC -#define GL_DOUBLE_VEC3 0x8FFD -#define GL_DOUBLE_VEC4 0x8FFE -#define GL_DOUBLE_MAT2 0x8F46 -#define GL_DOUBLE_MAT3 0x8F47 -#define GL_DOUBLE_MAT4 0x8F48 -#define GL_DOUBLE_MAT2x3 0x8F49 -#define GL_DOUBLE_MAT2x4 0x8F4A -#define GL_DOUBLE_MAT3x2 0x8F4B -#define GL_DOUBLE_MAT3x4 0x8F4C -#define GL_DOUBLE_MAT4x2 0x8F4D -#define GL_DOUBLE_MAT4x3 0x8F4E -#define GL_ACTIVE_SUBROUTINES 0x8DE5 -#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 -#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 -#define GL_MAX_SUBROUTINES 0x8DE7 -#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 -#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A -#define GL_COMPATIBLE_SUBROUTINES 0x8E4B -#define GL_PATCHES 0x000E -#define GL_PATCH_VERTICES 0x8E72 -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 -#define GL_TESS_GEN_MODE 0x8E76 -#define GL_TESS_GEN_SPACING 0x8E77 -#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 -#define GL_TESS_GEN_POINT_MODE 0x8E79 -#define GL_ISOLINES 0x8E7A -#define GL_FRACTIONAL_ODD 0x8E7B -#define GL_FRACTIONAL_EVEN 0x8E7C -#define GL_MAX_PATCH_VERTICES 0x8E7D -#define GL_MAX_TESS_GEN_LEVEL 0x8E7E -#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F -#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 -#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 -#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 -#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 -#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 -#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 -#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 -#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 -#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A -#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C -#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D -#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E -#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#define GL_TESS_CONTROL_SHADER 0x8E88 -#define GL_TRANSFORM_FEEDBACK 0x8E22 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 -#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); -typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); -typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); -typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); -typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); -typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShading (GLfloat value); -GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); -GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); -GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); -GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); -GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); -GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); -GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); -GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); -GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedback (void); -GLAPI void APIENTRY glResumeTransformFeedback (void); -GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); -GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); -GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); -GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); -GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); -#endif -#endif /* GL_VERSION_4_0 */ - -#ifndef GL_VERSION_4_1 -#define GL_VERSION_4_1 1 -#define GL_FIXED 0x140C -#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define GL_LOW_FLOAT 0x8DF0 -#define GL_MEDIUM_FLOAT 0x8DF1 -#define GL_HIGH_FLOAT 0x8DF2 -#define GL_LOW_INT 0x8DF3 -#define GL_MEDIUM_INT 0x8DF4 -#define GL_HIGH_INT 0x8DF5 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_SHADER_BINARY_FORMATS 0x8DF8 -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#define GL_RGB565 0x8D62 -#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 -#define GL_PROGRAM_BINARY_LENGTH 0x8741 -#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE -#define GL_PROGRAM_BINARY_FORMATS 0x87FF -#define GL_VERTEX_SHADER_BIT 0x00000001 -#define GL_FRAGMENT_SHADER_BIT 0x00000002 -#define GL_GEOMETRY_SHADER_BIT 0x00000004 -#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 -#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 -#define GL_ALL_SHADER_BITS 0xFFFFFFFF -#define GL_PROGRAM_SEPARABLE 0x8258 -#define GL_ACTIVE_PROGRAM 0x8259 -#define GL_PROGRAM_PIPELINE_BINDING 0x825A -#define GL_MAX_VIEWPORTS 0x825B -#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C -#define GL_VIEWPORT_BOUNDS_RANGE 0x825D -#define GL_LAYER_PROVOKING_VERTEX 0x825E -#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F -#define GL_UNDEFINED_VERTEX 0x8260 -typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); -typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); -typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); -typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); -typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); -typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); -typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); -typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); -typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReleaseShaderCompiler (void); -GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); -GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); -GLAPI void APIENTRY glClearDepthf (GLfloat d); -GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); -GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); -GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); -GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); -GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); -GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); -GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); -GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); -GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); -GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); -GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); -GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); -GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); -#endif -#endif /* GL_VERSION_4_1 */ - -#ifndef GL_VERSION_4_2 -#define GL_VERSION_4_2 1 -#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 -#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 -#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 -#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A -#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B -#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C -#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D -#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E -#define GL_NUM_SAMPLE_COUNTS 0x9380 -#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC -#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 -#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 -#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 -#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 -#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB -#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE -#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF -#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 -#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 -#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 -#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 -#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 -#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 -#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC -#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 -#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA -#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 -#define GL_COMMAND_BARRIER_BIT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 -#define GL_ALL_BARRIER_BITS 0xFFFFFFFF -#define GL_MAX_IMAGE_UNITS 0x8F38 -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 -#define GL_IMAGE_BINDING_NAME 0x8F3A -#define GL_IMAGE_BINDING_LEVEL 0x8F3B -#define GL_IMAGE_BINDING_LAYERED 0x8F3C -#define GL_IMAGE_BINDING_LAYER 0x8F3D -#define GL_IMAGE_BINDING_ACCESS 0x8F3E -#define GL_IMAGE_1D 0x904C -#define GL_IMAGE_2D 0x904D -#define GL_IMAGE_3D 0x904E -#define GL_IMAGE_2D_RECT 0x904F -#define GL_IMAGE_CUBE 0x9050 -#define GL_IMAGE_BUFFER 0x9051 -#define GL_IMAGE_1D_ARRAY 0x9052 -#define GL_IMAGE_2D_ARRAY 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 -#define GL_INT_IMAGE_1D 0x9057 -#define GL_INT_IMAGE_2D 0x9058 -#define GL_INT_IMAGE_3D 0x9059 -#define GL_INT_IMAGE_2D_RECT 0x905A -#define GL_INT_IMAGE_CUBE 0x905B -#define GL_INT_IMAGE_BUFFER 0x905C -#define GL_INT_IMAGE_1D_ARRAY 0x905D -#define GL_INT_IMAGE_2D_ARRAY 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C -#define GL_MAX_IMAGE_SAMPLES 0x906D -#define GL_IMAGE_BINDING_FORMAT 0x906E -#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 -#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA -#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB -#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD -#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE -#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF -#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C -#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D -#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E -#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F -#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); -typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); -GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); -GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); -#endif -#endif /* GL_VERSION_4_2 */ - -#ifndef GL_VERSION_4_3 -#define GL_VERSION_4_3 1 -typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 -#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E -#define GL_COMPRESSED_RGB8_ETC2 0x9274 -#define GL_COMPRESSED_SRGB8_ETC2 0x9275 -#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 -#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 -#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 -#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 -#define GL_COMPRESSED_R11_EAC 0x9270 -#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 -#define GL_COMPRESSED_RG11_EAC 0x9272 -#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 -#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 -#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A -#define GL_MAX_ELEMENT_INDEX 0x8D6B -#define GL_COMPUTE_SHADER 0x91B9 -#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB -#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC -#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD -#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 -#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 -#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 -#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 -#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 -#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB -#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE -#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF -#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED -#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE -#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#define GL_DEBUG_SOURCE_API 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#define GL_DEBUG_SOURCE_OTHER 0x824B -#define GL_DEBUG_TYPE_ERROR 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#define GL_DEBUG_TYPE_OTHER 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#define GL_DEBUG_TYPE_MARKER 0x8268 -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#define GL_BUFFER 0x82E0 -#define GL_SHADER 0x82E1 -#define GL_PROGRAM 0x82E2 -#define GL_QUERY 0x82E3 -#define GL_PROGRAM_PIPELINE 0x82E4 -#define GL_SAMPLER 0x82E6 -#define GL_MAX_LABEL_LENGTH 0x82E8 -#define GL_DEBUG_OUTPUT 0x92E0 -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#define GL_MAX_UNIFORM_LOCATIONS 0x826E -#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 -#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 -#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 -#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 -#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 -#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 -#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 -#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 -#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 -#define GL_INTERNALFORMAT_SUPPORTED 0x826F -#define GL_INTERNALFORMAT_PREFERRED 0x8270 -#define GL_INTERNALFORMAT_RED_SIZE 0x8271 -#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 -#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 -#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 -#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 -#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 -#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 -#define GL_INTERNALFORMAT_RED_TYPE 0x8278 -#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 -#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A -#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B -#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C -#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D -#define GL_MAX_WIDTH 0x827E -#define GL_MAX_HEIGHT 0x827F -#define GL_MAX_DEPTH 0x8280 -#define GL_MAX_LAYERS 0x8281 -#define GL_MAX_COMBINED_DIMENSIONS 0x8282 -#define GL_COLOR_COMPONENTS 0x8283 -#define GL_DEPTH_COMPONENTS 0x8284 -#define GL_STENCIL_COMPONENTS 0x8285 -#define GL_COLOR_RENDERABLE 0x8286 -#define GL_DEPTH_RENDERABLE 0x8287 -#define GL_STENCIL_RENDERABLE 0x8288 -#define GL_FRAMEBUFFER_RENDERABLE 0x8289 -#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A -#define GL_FRAMEBUFFER_BLEND 0x828B -#define GL_READ_PIXELS 0x828C -#define GL_READ_PIXELS_FORMAT 0x828D -#define GL_READ_PIXELS_TYPE 0x828E -#define GL_TEXTURE_IMAGE_FORMAT 0x828F -#define GL_TEXTURE_IMAGE_TYPE 0x8290 -#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 -#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 -#define GL_MIPMAP 0x8293 -#define GL_MANUAL_GENERATE_MIPMAP 0x8294 -#define GL_AUTO_GENERATE_MIPMAP 0x8295 -#define GL_COLOR_ENCODING 0x8296 -#define GL_SRGB_READ 0x8297 -#define GL_SRGB_WRITE 0x8298 -#define GL_FILTER 0x829A -#define GL_VERTEX_TEXTURE 0x829B -#define GL_TESS_CONTROL_TEXTURE 0x829C -#define GL_TESS_EVALUATION_TEXTURE 0x829D -#define GL_GEOMETRY_TEXTURE 0x829E -#define GL_FRAGMENT_TEXTURE 0x829F -#define GL_COMPUTE_TEXTURE 0x82A0 -#define GL_TEXTURE_SHADOW 0x82A1 -#define GL_TEXTURE_GATHER 0x82A2 -#define GL_TEXTURE_GATHER_SHADOW 0x82A3 -#define GL_SHADER_IMAGE_LOAD 0x82A4 -#define GL_SHADER_IMAGE_STORE 0x82A5 -#define GL_SHADER_IMAGE_ATOMIC 0x82A6 -#define GL_IMAGE_TEXEL_SIZE 0x82A7 -#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 -#define GL_IMAGE_PIXEL_FORMAT 0x82A9 -#define GL_IMAGE_PIXEL_TYPE 0x82AA -#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC -#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD -#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE -#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF -#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 -#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 -#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 -#define GL_CLEAR_BUFFER 0x82B4 -#define GL_TEXTURE_VIEW 0x82B5 -#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 -#define GL_FULL_SUPPORT 0x82B7 -#define GL_CAVEAT_SUPPORT 0x82B8 -#define GL_IMAGE_CLASS_4_X_32 0x82B9 -#define GL_IMAGE_CLASS_2_X_32 0x82BA -#define GL_IMAGE_CLASS_1_X_32 0x82BB -#define GL_IMAGE_CLASS_4_X_16 0x82BC -#define GL_IMAGE_CLASS_2_X_16 0x82BD -#define GL_IMAGE_CLASS_1_X_16 0x82BE -#define GL_IMAGE_CLASS_4_X_8 0x82BF -#define GL_IMAGE_CLASS_2_X_8 0x82C0 -#define GL_IMAGE_CLASS_1_X_8 0x82C1 -#define GL_IMAGE_CLASS_11_11_10 0x82C2 -#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 -#define GL_VIEW_CLASS_128_BITS 0x82C4 -#define GL_VIEW_CLASS_96_BITS 0x82C5 -#define GL_VIEW_CLASS_64_BITS 0x82C6 -#define GL_VIEW_CLASS_48_BITS 0x82C7 -#define GL_VIEW_CLASS_32_BITS 0x82C8 -#define GL_VIEW_CLASS_24_BITS 0x82C9 -#define GL_VIEW_CLASS_16_BITS 0x82CA -#define GL_VIEW_CLASS_8_BITS 0x82CB -#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC -#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD -#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE -#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF -#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 -#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 -#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 -#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 -#define GL_UNIFORM 0x92E1 -#define GL_UNIFORM_BLOCK 0x92E2 -#define GL_PROGRAM_INPUT 0x92E3 -#define GL_PROGRAM_OUTPUT 0x92E4 -#define GL_BUFFER_VARIABLE 0x92E5 -#define GL_SHADER_STORAGE_BLOCK 0x92E6 -#define GL_VERTEX_SUBROUTINE 0x92E8 -#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 -#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA -#define GL_GEOMETRY_SUBROUTINE 0x92EB -#define GL_FRAGMENT_SUBROUTINE 0x92EC -#define GL_COMPUTE_SUBROUTINE 0x92ED -#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE -#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF -#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 -#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 -#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 -#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 -#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 -#define GL_ACTIVE_RESOURCES 0x92F5 -#define GL_MAX_NAME_LENGTH 0x92F6 -#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 -#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 -#define GL_NAME_LENGTH 0x92F9 -#define GL_TYPE 0x92FA -#define GL_ARRAY_SIZE 0x92FB -#define GL_OFFSET 0x92FC -#define GL_BLOCK_INDEX 0x92FD -#define GL_ARRAY_STRIDE 0x92FE -#define GL_MATRIX_STRIDE 0x92FF -#define GL_IS_ROW_MAJOR 0x9300 -#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 -#define GL_BUFFER_BINDING 0x9302 -#define GL_BUFFER_DATA_SIZE 0x9303 -#define GL_NUM_ACTIVE_VARIABLES 0x9304 -#define GL_ACTIVE_VARIABLES 0x9305 -#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 -#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 -#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 -#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 -#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A -#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B -#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C -#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D -#define GL_LOCATION 0x930E -#define GL_LOCATION_INDEX 0x930F -#define GL_IS_PER_PATCH 0x92E7 -#define GL_SHADER_STORAGE_BUFFER 0x90D2 -#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 -#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 -#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 -#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 -#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 -#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 -#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 -#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA -#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB -#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC -#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD -#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE -#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF -#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 -#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 -#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA -#define GL_TEXTURE_BUFFER_OFFSET 0x919D -#define GL_TEXTURE_BUFFER_SIZE 0x919E -#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F -#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB -#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC -#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD -#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE -#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF -#define GL_VERTEX_ATTRIB_BINDING 0x82D4 -#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 -#define GL_VERTEX_BINDING_DIVISOR 0x82D6 -#define GL_VERTEX_BINDING_OFFSET 0x82D7 -#define GL_VERTEX_BINDING_STRIDE 0x82D8 -#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 -#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA -#define GL_DISPLAY_LIST 0x82E7 -typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); -typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); -typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); -typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); -typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); -typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); -typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); -typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); -typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); -typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); -typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); -GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); -GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); -GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); -GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); -GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); -GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); -GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); -GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); -GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); -GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); -GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); -GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); -GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); -GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); -GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); -GLAPI void APIENTRY glPopDebugGroup (void); -GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); -GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); -#endif -#endif /* GL_VERSION_4_3 */ - -#ifndef GL_VERSION_4_4 -#define GL_VERSION_4_4 1 -#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 -#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 -#define GL_TEXTURE_BUFFER_BINDING 0x8C2A -#define GL_MAP_PERSISTENT_BIT 0x0040 -#define GL_MAP_COHERENT_BIT 0x0080 -#define GL_DYNAMIC_STORAGE_BIT 0x0100 -#define GL_CLIENT_STORAGE_BIT 0x0200 -#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 -#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F -#define GL_BUFFER_STORAGE_FLAGS 0x8220 -#define GL_CLEAR_TEXTURE 0x9365 -#define GL_LOCATION_COMPONENT 0x934A -#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B -#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C -#define GL_QUERY_BUFFER 0x9192 -#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 -#define GL_QUERY_BUFFER_BINDING 0x9193 -#define GL_QUERY_RESULT_NO_WAIT 0x9194 -#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 -typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); -typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); -typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); -typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); -typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); -typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); -GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); -GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); -GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); -GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); -GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); -GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); -#endif -#endif /* GL_VERSION_4_4 */ - -#ifndef GL_ARB_ES2_compatibility -#define GL_ARB_ES2_compatibility 1 -#endif /* GL_ARB_ES2_compatibility */ - -#ifndef GL_ARB_ES3_compatibility -#define GL_ARB_ES3_compatibility 1 -#endif /* GL_ARB_ES3_compatibility */ - -#ifndef GL_ARB_arrays_of_arrays -#define GL_ARB_arrays_of_arrays 1 -#endif /* GL_ARB_arrays_of_arrays */ - -#ifndef GL_ARB_base_instance -#define GL_ARB_base_instance 1 -#endif /* GL_ARB_base_instance */ - -#ifndef GL_ARB_bindless_texture -#define GL_ARB_bindless_texture 1 -typedef uint64_t GLuint64EXT; -#define GL_UNSIGNED_INT64_ARB 0x140F -typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); -typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); -typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); -typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); -GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); -GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); -GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); -GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); -GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); -GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); -GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); -GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); -GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); -GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); -GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); -#endif -#endif /* GL_ARB_bindless_texture */ - -#ifndef GL_ARB_blend_func_extended -#define GL_ARB_blend_func_extended 1 -#endif /* GL_ARB_blend_func_extended */ - -#ifndef GL_ARB_buffer_storage -#define GL_ARB_buffer_storage 1 -#endif /* GL_ARB_buffer_storage */ - -#ifndef GL_ARB_cl_event -#define GL_ARB_cl_event 1 -struct _cl_context; -struct _cl_event; -#define GL_SYNC_CL_EVENT_ARB 0x8240 -#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 -typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); -#endif -#endif /* GL_ARB_cl_event */ - -#ifndef GL_ARB_clear_buffer_object -#define GL_ARB_clear_buffer_object 1 -#endif /* GL_ARB_clear_buffer_object */ - -#ifndef GL_ARB_clear_texture -#define GL_ARB_clear_texture 1 -#endif /* GL_ARB_clear_texture */ - -#ifndef GL_ARB_color_buffer_float -#define GL_ARB_color_buffer_float 1 -#define GL_RGBA_FLOAT_MODE_ARB 0x8820 -#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A -#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B -#define GL_CLAMP_READ_COLOR_ARB 0x891C -#define GL_FIXED_ONLY_ARB 0x891D -typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); -#endif -#endif /* GL_ARB_color_buffer_float */ - -#ifndef GL_ARB_compatibility -#define GL_ARB_compatibility 1 -#endif /* GL_ARB_compatibility */ - -#ifndef GL_ARB_compressed_texture_pixel_storage -#define GL_ARB_compressed_texture_pixel_storage 1 -#endif /* GL_ARB_compressed_texture_pixel_storage */ - -#ifndef GL_ARB_compute_shader -#define GL_ARB_compute_shader 1 -#define GL_COMPUTE_SHADER_BIT 0x00000020 -#endif /* GL_ARB_compute_shader */ - -#ifndef GL_ARB_compute_variable_group_size -#define GL_ARB_compute_variable_group_size 1 -#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 -#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB -#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 -#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF -typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); -#endif -#endif /* GL_ARB_compute_variable_group_size */ - -#ifndef GL_ARB_conservative_depth -#define GL_ARB_conservative_depth 1 -#endif /* GL_ARB_conservative_depth */ - -#ifndef GL_ARB_copy_buffer -#define GL_ARB_copy_buffer 1 -#define GL_COPY_READ_BUFFER_BINDING 0x8F36 -#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 -#endif /* GL_ARB_copy_buffer */ - -#ifndef GL_ARB_copy_image -#define GL_ARB_copy_image 1 -#endif /* GL_ARB_copy_image */ - -#ifndef GL_ARB_debug_output -#define GL_ARB_debug_output 1 -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define GL_DEBUG_SOURCE_API_ARB 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B -#define GL_DEBUG_TYPE_ERROR_ARB 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -#endif -#endif /* GL_ARB_debug_output */ - -#ifndef GL_ARB_depth_buffer_float -#define GL_ARB_depth_buffer_float 1 -#endif /* GL_ARB_depth_buffer_float */ - -#ifndef GL_ARB_depth_clamp -#define GL_ARB_depth_clamp 1 -#endif /* GL_ARB_depth_clamp */ - -#ifndef GL_ARB_depth_texture -#define GL_ARB_depth_texture 1 -#define GL_DEPTH_COMPONENT16_ARB 0x81A5 -#define GL_DEPTH_COMPONENT24_ARB 0x81A6 -#define GL_DEPTH_COMPONENT32_ARB 0x81A7 -#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A -#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B -#endif /* GL_ARB_depth_texture */ - -#ifndef GL_ARB_draw_buffers -#define GL_ARB_draw_buffers 1 -#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 -#define GL_DRAW_BUFFER0_ARB 0x8825 -#define GL_DRAW_BUFFER1_ARB 0x8826 -#define GL_DRAW_BUFFER2_ARB 0x8827 -#define GL_DRAW_BUFFER3_ARB 0x8828 -#define GL_DRAW_BUFFER4_ARB 0x8829 -#define GL_DRAW_BUFFER5_ARB 0x882A -#define GL_DRAW_BUFFER6_ARB 0x882B -#define GL_DRAW_BUFFER7_ARB 0x882C -#define GL_DRAW_BUFFER8_ARB 0x882D -#define GL_DRAW_BUFFER9_ARB 0x882E -#define GL_DRAW_BUFFER10_ARB 0x882F -#define GL_DRAW_BUFFER11_ARB 0x8830 -#define GL_DRAW_BUFFER12_ARB 0x8831 -#define GL_DRAW_BUFFER13_ARB 0x8832 -#define GL_DRAW_BUFFER14_ARB 0x8833 -#define GL_DRAW_BUFFER15_ARB 0x8834 -typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); -#endif -#endif /* GL_ARB_draw_buffers */ - -#ifndef GL_ARB_draw_buffers_blend -#define GL_ARB_draw_buffers_blend 1 -typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif -#endif /* GL_ARB_draw_buffers_blend */ - -#ifndef GL_ARB_draw_elements_base_vertex -#define GL_ARB_draw_elements_base_vertex 1 -#endif /* GL_ARB_draw_elements_base_vertex */ - -#ifndef GL_ARB_draw_indirect -#define GL_ARB_draw_indirect 1 -#endif /* GL_ARB_draw_indirect */ - -#ifndef GL_ARB_draw_instanced -#define GL_ARB_draw_instanced 1 -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); -#endif -#endif /* GL_ARB_draw_instanced */ - -#ifndef GL_ARB_enhanced_layouts -#define GL_ARB_enhanced_layouts 1 -#endif /* GL_ARB_enhanced_layouts */ - -#ifndef GL_ARB_explicit_attrib_location -#define GL_ARB_explicit_attrib_location 1 -#endif /* GL_ARB_explicit_attrib_location */ - -#ifndef GL_ARB_explicit_uniform_location -#define GL_ARB_explicit_uniform_location 1 -#endif /* GL_ARB_explicit_uniform_location */ - -#ifndef GL_ARB_fragment_coord_conventions -#define GL_ARB_fragment_coord_conventions 1 -#endif /* GL_ARB_fragment_coord_conventions */ - -#ifndef GL_ARB_fragment_layer_viewport -#define GL_ARB_fragment_layer_viewport 1 -#endif /* GL_ARB_fragment_layer_viewport */ - -#ifndef GL_ARB_fragment_program -#define GL_ARB_fragment_program 1 -#define GL_FRAGMENT_PROGRAM_ARB 0x8804 -#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 -#define GL_PROGRAM_LENGTH_ARB 0x8627 -#define GL_PROGRAM_FORMAT_ARB 0x8876 -#define GL_PROGRAM_BINDING_ARB 0x8677 -#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 -#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 -#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 -#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 -#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 -#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 -#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 -#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 -#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 -#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 -#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA -#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB -#define GL_PROGRAM_ATTRIBS_ARB 0x88AC -#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD -#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE -#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF -#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 -#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 -#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 -#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 -#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 -#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 -#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 -#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 -#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A -#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B -#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C -#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D -#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E -#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F -#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 -#define GL_PROGRAM_STRING_ARB 0x8628 -#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B -#define GL_CURRENT_MATRIX_ARB 0x8641 -#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 -#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 -#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F -#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E -#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 -#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 -#define GL_MATRIX0_ARB 0x88C0 -#define GL_MATRIX1_ARB 0x88C1 -#define GL_MATRIX2_ARB 0x88C2 -#define GL_MATRIX3_ARB 0x88C3 -#define GL_MATRIX4_ARB 0x88C4 -#define GL_MATRIX5_ARB 0x88C5 -#define GL_MATRIX6_ARB 0x88C6 -#define GL_MATRIX7_ARB 0x88C7 -#define GL_MATRIX8_ARB 0x88C8 -#define GL_MATRIX9_ARB 0x88C9 -#define GL_MATRIX10_ARB 0x88CA -#define GL_MATRIX11_ARB 0x88CB -#define GL_MATRIX12_ARB 0x88CC -#define GL_MATRIX13_ARB 0x88CD -#define GL_MATRIX14_ARB 0x88CE -#define GL_MATRIX15_ARB 0x88CF -#define GL_MATRIX16_ARB 0x88D0 -#define GL_MATRIX17_ARB 0x88D1 -#define GL_MATRIX18_ARB 0x88D2 -#define GL_MATRIX19_ARB 0x88D3 -#define GL_MATRIX20_ARB 0x88D4 -#define GL_MATRIX21_ARB 0x88D5 -#define GL_MATRIX22_ARB 0x88D6 -#define GL_MATRIX23_ARB 0x88D7 -#define GL_MATRIX24_ARB 0x88D8 -#define GL_MATRIX25_ARB 0x88D9 -#define GL_MATRIX26_ARB 0x88DA -#define GL_MATRIX27_ARB 0x88DB -#define GL_MATRIX28_ARB 0x88DC -#define GL_MATRIX29_ARB 0x88DD -#define GL_MATRIX30_ARB 0x88DE -#define GL_MATRIX31_ARB 0x88DF -typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string); -typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); -typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string); -GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); -GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); -GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string); -GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); -#endif -#endif /* GL_ARB_fragment_program */ - -#ifndef GL_ARB_fragment_program_shadow -#define GL_ARB_fragment_program_shadow 1 -#endif /* GL_ARB_fragment_program_shadow */ - -#ifndef GL_ARB_fragment_shader -#define GL_ARB_fragment_shader 1 -#define GL_FRAGMENT_SHADER_ARB 0x8B30 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B -#endif /* GL_ARB_fragment_shader */ - -#ifndef GL_ARB_framebuffer_no_attachments -#define GL_ARB_framebuffer_no_attachments 1 -#endif /* GL_ARB_framebuffer_no_attachments */ - -#ifndef GL_ARB_framebuffer_object -#define GL_ARB_framebuffer_object 1 -#endif /* GL_ARB_framebuffer_object */ - -#ifndef GL_ARB_framebuffer_sRGB -#define GL_ARB_framebuffer_sRGB 1 -#endif /* GL_ARB_framebuffer_sRGB */ - -#ifndef GL_ARB_geometry_shader4 -#define GL_ARB_geometry_shader4 1 -#define GL_LINES_ADJACENCY_ARB 0x000A -#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B -#define GL_TRIANGLES_ADJACENCY_ARB 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D -#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 -#define GL_GEOMETRY_SHADER_ARB 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD -#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); -GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif -#endif /* GL_ARB_geometry_shader4 */ - -#ifndef GL_ARB_get_program_binary -#define GL_ARB_get_program_binary 1 -#endif /* GL_ARB_get_program_binary */ - -#ifndef GL_ARB_gpu_shader5 -#define GL_ARB_gpu_shader5 1 -#endif /* GL_ARB_gpu_shader5 */ - -#ifndef GL_ARB_gpu_shader_fp64 -#define GL_ARB_gpu_shader_fp64 1 -#endif /* GL_ARB_gpu_shader_fp64 */ - -#ifndef GL_ARB_half_float_pixel -#define GL_ARB_half_float_pixel 1 -typedef unsigned short GLhalfARB; -#define GL_HALF_FLOAT_ARB 0x140B -#endif /* GL_ARB_half_float_pixel */ - -#ifndef GL_ARB_half_float_vertex -#define GL_ARB_half_float_vertex 1 -#endif /* GL_ARB_half_float_vertex */ - -#ifndef GL_ARB_imaging -#define GL_ARB_imaging 1 -#define GL_BLEND_COLOR 0x8005 -#define GL_BLEND_EQUATION 0x8009 -#define GL_CONVOLUTION_1D 0x8010 -#define GL_CONVOLUTION_2D 0x8011 -#define GL_SEPARABLE_2D 0x8012 -#define GL_CONVOLUTION_BORDER_MODE 0x8013 -#define GL_CONVOLUTION_FILTER_SCALE 0x8014 -#define GL_CONVOLUTION_FILTER_BIAS 0x8015 -#define GL_REDUCE 0x8016 -#define GL_CONVOLUTION_FORMAT 0x8017 -#define GL_CONVOLUTION_WIDTH 0x8018 -#define GL_CONVOLUTION_HEIGHT 0x8019 -#define GL_MAX_CONVOLUTION_WIDTH 0x801A -#define GL_MAX_CONVOLUTION_HEIGHT 0x801B -#define GL_POST_CONVOLUTION_RED_SCALE 0x801C -#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D -#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E -#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F -#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 -#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 -#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 -#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 -#define GL_HISTOGRAM 0x8024 -#define GL_PROXY_HISTOGRAM 0x8025 -#define GL_HISTOGRAM_WIDTH 0x8026 -#define GL_HISTOGRAM_FORMAT 0x8027 -#define GL_HISTOGRAM_RED_SIZE 0x8028 -#define GL_HISTOGRAM_GREEN_SIZE 0x8029 -#define GL_HISTOGRAM_BLUE_SIZE 0x802A -#define GL_HISTOGRAM_ALPHA_SIZE 0x802B -#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C -#define GL_HISTOGRAM_SINK 0x802D -#define GL_MINMAX 0x802E -#define GL_MINMAX_FORMAT 0x802F -#define GL_MINMAX_SINK 0x8030 -#define GL_TABLE_TOO_LARGE 0x8031 -#define GL_COLOR_MATRIX 0x80B1 -#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 -#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 -#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 -#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 -#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 -#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 -#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 -#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 -#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA -#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB -#define GL_COLOR_TABLE 0x80D0 -#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 -#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 -#define GL_PROXY_COLOR_TABLE 0x80D3 -#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 -#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 -#define GL_COLOR_TABLE_SCALE 0x80D6 -#define GL_COLOR_TABLE_BIAS 0x80D7 -#define GL_COLOR_TABLE_FORMAT 0x80D8 -#define GL_COLOR_TABLE_WIDTH 0x80D9 -#define GL_COLOR_TABLE_RED_SIZE 0x80DA -#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB -#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC -#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD -#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE -#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF -#define GL_CONSTANT_BORDER 0x8151 -#define GL_REPLICATE_BORDER 0x8153 -#define GL_CONVOLUTION_BORDER_COLOR 0x8154 -typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); -typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); -GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table); -GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); -GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); -GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); -GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); -GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image); -GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); -GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); -GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glResetHistogram (GLenum target); -GLAPI void APIENTRY glResetMinmax (GLenum target); -#endif -#endif /* GL_ARB_imaging */ - -#ifndef GL_ARB_indirect_parameters -#define GL_ARB_indirect_parameters 1 -#define GL_PARAMETER_BUFFER_ARB 0x80EE -#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -#endif -#endif /* GL_ARB_indirect_parameters */ - -#ifndef GL_ARB_instanced_arrays -#define GL_ARB_instanced_arrays 1 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); -#endif -#endif /* GL_ARB_instanced_arrays */ - -#ifndef GL_ARB_internalformat_query -#define GL_ARB_internalformat_query 1 -#endif /* GL_ARB_internalformat_query */ - -#ifndef GL_ARB_internalformat_query2 -#define GL_ARB_internalformat_query2 1 -#define GL_SRGB_DECODE_ARB 0x8299 -#endif /* GL_ARB_internalformat_query2 */ - -#ifndef GL_ARB_invalidate_subdata -#define GL_ARB_invalidate_subdata 1 -#endif /* GL_ARB_invalidate_subdata */ - -#ifndef GL_ARB_map_buffer_alignment -#define GL_ARB_map_buffer_alignment 1 -#endif /* GL_ARB_map_buffer_alignment */ - -#ifndef GL_ARB_map_buffer_range -#define GL_ARB_map_buffer_range 1 -#endif /* GL_ARB_map_buffer_range */ - -#ifndef GL_ARB_matrix_palette -#define GL_ARB_matrix_palette 1 -#define GL_MATRIX_PALETTE_ARB 0x8840 -#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 -#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 -#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 -#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 -#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 -#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 -#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 -#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 -#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 -typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); -typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); -GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); -GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); -GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); -GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); -#endif -#endif /* GL_ARB_matrix_palette */ - -#ifndef GL_ARB_multi_bind -#define GL_ARB_multi_bind 1 -#endif /* GL_ARB_multi_bind */ - -#ifndef GL_ARB_multi_draw_indirect -#define GL_ARB_multi_draw_indirect 1 -#endif /* GL_ARB_multi_draw_indirect */ - -#ifndef GL_ARB_multisample -#define GL_ARB_multisample 1 -#define GL_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert); -#endif -#endif /* GL_ARB_multisample */ - -#ifndef GL_ARB_multitexture -#define GL_ARB_multitexture 1 -#define GL_TEXTURE0_ARB 0x84C0 -#define GL_TEXTURE1_ARB 0x84C1 -#define GL_TEXTURE2_ARB 0x84C2 -#define GL_TEXTURE3_ARB 0x84C3 -#define GL_TEXTURE4_ARB 0x84C4 -#define GL_TEXTURE5_ARB 0x84C5 -#define GL_TEXTURE6_ARB 0x84C6 -#define GL_TEXTURE7_ARB 0x84C7 -#define GL_TEXTURE8_ARB 0x84C8 -#define GL_TEXTURE9_ARB 0x84C9 -#define GL_TEXTURE10_ARB 0x84CA -#define GL_TEXTURE11_ARB 0x84CB -#define GL_TEXTURE12_ARB 0x84CC -#define GL_TEXTURE13_ARB 0x84CD -#define GL_TEXTURE14_ARB 0x84CE -#define GL_TEXTURE15_ARB 0x84CF -#define GL_TEXTURE16_ARB 0x84D0 -#define GL_TEXTURE17_ARB 0x84D1 -#define GL_TEXTURE18_ARB 0x84D2 -#define GL_TEXTURE19_ARB 0x84D3 -#define GL_TEXTURE20_ARB 0x84D4 -#define GL_TEXTURE21_ARB 0x84D5 -#define GL_TEXTURE22_ARB 0x84D6 -#define GL_TEXTURE23_ARB 0x84D7 -#define GL_TEXTURE24_ARB 0x84D8 -#define GL_TEXTURE25_ARB 0x84D9 -#define GL_TEXTURE26_ARB 0x84DA -#define GL_TEXTURE27_ARB 0x84DB -#define GL_TEXTURE28_ARB 0x84DC -#define GL_TEXTURE29_ARB 0x84DD -#define GL_TEXTURE30_ARB 0x84DE -#define GL_TEXTURE31_ARB 0x84DF -#define GL_ACTIVE_TEXTURE_ARB 0x84E0 -#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 -#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 -typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTextureARB (GLenum texture); -GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); -GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); -GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); -GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); -GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); -GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); -GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); -GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); -GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); -GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); -GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); -#endif -#endif /* GL_ARB_multitexture */ - -#ifndef GL_ARB_occlusion_query -#define GL_ARB_occlusion_query 1 -#define GL_QUERY_COUNTER_BITS_ARB 0x8864 -#define GL_CURRENT_QUERY_ARB 0x8865 -#define GL_QUERY_RESULT_ARB 0x8866 -#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 -#define GL_SAMPLES_PASSED_ARB 0x8914 -typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); -GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQueryARB (GLenum target); -GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); -#endif -#endif /* GL_ARB_occlusion_query */ - -#ifndef GL_ARB_occlusion_query2 -#define GL_ARB_occlusion_query2 1 -#endif /* GL_ARB_occlusion_query2 */ - -#ifndef GL_ARB_pixel_buffer_object -#define GL_ARB_pixel_buffer_object 1 -#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF -#endif /* GL_ARB_pixel_buffer_object */ - -#ifndef GL_ARB_point_parameters -#define GL_ARB_point_parameters 1 -#define GL_POINT_SIZE_MIN_ARB 0x8126 -#define GL_POINT_SIZE_MAX_ARB 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 -#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 -typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); -#endif -#endif /* GL_ARB_point_parameters */ - -#ifndef GL_ARB_point_sprite -#define GL_ARB_point_sprite 1 -#define GL_POINT_SPRITE_ARB 0x8861 -#define GL_COORD_REPLACE_ARB 0x8862 -#endif /* GL_ARB_point_sprite */ - -#ifndef GL_ARB_program_interface_query -#define GL_ARB_program_interface_query 1 -#endif /* GL_ARB_program_interface_query */ - -#ifndef GL_ARB_provoking_vertex -#define GL_ARB_provoking_vertex 1 -#endif /* GL_ARB_provoking_vertex */ - -#ifndef GL_ARB_query_buffer_object -#define GL_ARB_query_buffer_object 1 -#endif /* GL_ARB_query_buffer_object */ - -#ifndef GL_ARB_robust_buffer_access_behavior -#define GL_ARB_robust_buffer_access_behavior 1 -#endif /* GL_ARB_robust_buffer_access_behavior */ - -#ifndef GL_ARB_robustness -#define GL_ARB_robustness 1 -#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 -#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 -typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); -typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); -typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); -typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); -typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); -typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); -typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); -typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); -typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); -typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); -typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); -GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); -GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); -GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); -GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); -GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); -GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); -GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); -GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); -GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); -GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); -GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -#endif -#endif /* GL_ARB_robustness */ - -#ifndef GL_ARB_robustness_isolation -#define GL_ARB_robustness_isolation 1 -#endif /* GL_ARB_robustness_isolation */ - -#ifndef GL_ARB_sample_shading -#define GL_ARB_sample_shading 1 -#define GL_SAMPLE_SHADING_ARB 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); -#endif -#endif /* GL_ARB_sample_shading */ - -#ifndef GL_ARB_sampler_objects -#define GL_ARB_sampler_objects 1 -#endif /* GL_ARB_sampler_objects */ - -#ifndef GL_ARB_seamless_cube_map -#define GL_ARB_seamless_cube_map 1 -#endif /* GL_ARB_seamless_cube_map */ - -#ifndef GL_ARB_seamless_cubemap_per_texture -#define GL_ARB_seamless_cubemap_per_texture 1 -#endif /* GL_ARB_seamless_cubemap_per_texture */ - -#ifndef GL_ARB_separate_shader_objects -#define GL_ARB_separate_shader_objects 1 -#endif /* GL_ARB_separate_shader_objects */ - -#ifndef GL_ARB_shader_atomic_counters -#define GL_ARB_shader_atomic_counters 1 -#endif /* GL_ARB_shader_atomic_counters */ - -#ifndef GL_ARB_shader_bit_encoding -#define GL_ARB_shader_bit_encoding 1 -#endif /* GL_ARB_shader_bit_encoding */ - -#ifndef GL_ARB_shader_draw_parameters -#define GL_ARB_shader_draw_parameters 1 -#endif /* GL_ARB_shader_draw_parameters */ - -#ifndef GL_ARB_shader_group_vote -#define GL_ARB_shader_group_vote 1 -#endif /* GL_ARB_shader_group_vote */ - -#ifndef GL_ARB_shader_image_load_store -#define GL_ARB_shader_image_load_store 1 -#endif /* GL_ARB_shader_image_load_store */ - -#ifndef GL_ARB_shader_image_size -#define GL_ARB_shader_image_size 1 -#endif /* GL_ARB_shader_image_size */ - -#ifndef GL_ARB_shader_objects -#define GL_ARB_shader_objects 1 -#ifdef __APPLE__ -typedef void *GLhandleARB; -#else -typedef unsigned int GLhandleARB; -#endif -typedef char GLcharARB; -#define GL_PROGRAM_OBJECT_ARB 0x8B40 -#define GL_SHADER_OBJECT_ARB 0x8B48 -#define GL_OBJECT_TYPE_ARB 0x8B4E -#define GL_OBJECT_SUBTYPE_ARB 0x8B4F -#define GL_FLOAT_VEC2_ARB 0x8B50 -#define GL_FLOAT_VEC3_ARB 0x8B51 -#define GL_FLOAT_VEC4_ARB 0x8B52 -#define GL_INT_VEC2_ARB 0x8B53 -#define GL_INT_VEC3_ARB 0x8B54 -#define GL_INT_VEC4_ARB 0x8B55 -#define GL_BOOL_ARB 0x8B56 -#define GL_BOOL_VEC2_ARB 0x8B57 -#define GL_BOOL_VEC3_ARB 0x8B58 -#define GL_BOOL_VEC4_ARB 0x8B59 -#define GL_FLOAT_MAT2_ARB 0x8B5A -#define GL_FLOAT_MAT3_ARB 0x8B5B -#define GL_FLOAT_MAT4_ARB 0x8B5C -#define GL_SAMPLER_1D_ARB 0x8B5D -#define GL_SAMPLER_2D_ARB 0x8B5E -#define GL_SAMPLER_3D_ARB 0x8B5F -#define GL_SAMPLER_CUBE_ARB 0x8B60 -#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 -#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 -#define GL_SAMPLER_2D_RECT_ARB 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 -#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 -#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 -#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 -#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 -#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 -#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 -#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 -#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 -#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 -typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); -typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); -typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); -typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); -typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); -typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); -GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); -GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); -GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); -GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); -GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); -GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); -GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); -GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); -GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); -GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); -GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); -GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); -GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); -#endif -#endif /* GL_ARB_shader_objects */ - -#ifndef GL_ARB_shader_precision -#define GL_ARB_shader_precision 1 -#endif /* GL_ARB_shader_precision */ - -#ifndef GL_ARB_shader_stencil_export -#define GL_ARB_shader_stencil_export 1 -#endif /* GL_ARB_shader_stencil_export */ - -#ifndef GL_ARB_shader_storage_buffer_object -#define GL_ARB_shader_storage_buffer_object 1 -#endif /* GL_ARB_shader_storage_buffer_object */ - -#ifndef GL_ARB_shader_subroutine -#define GL_ARB_shader_subroutine 1 -#endif /* GL_ARB_shader_subroutine */ - -#ifndef GL_ARB_shader_texture_lod -#define GL_ARB_shader_texture_lod 1 -#endif /* GL_ARB_shader_texture_lod */ - -#ifndef GL_ARB_shading_language_100 -#define GL_ARB_shading_language_100 1 -#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C -#endif /* GL_ARB_shading_language_100 */ - -#ifndef GL_ARB_shading_language_420pack -#define GL_ARB_shading_language_420pack 1 -#endif /* GL_ARB_shading_language_420pack */ - -#ifndef GL_ARB_shading_language_include -#define GL_ARB_shading_language_include 1 -#define GL_SHADER_INCLUDE_ARB 0x8DAE -#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 -#define GL_NAMED_STRING_TYPE_ARB 0x8DEA -typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); -typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); -GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); -#endif -#endif /* GL_ARB_shading_language_include */ - -#ifndef GL_ARB_shading_language_packing -#define GL_ARB_shading_language_packing 1 -#endif /* GL_ARB_shading_language_packing */ - -#ifndef GL_ARB_shadow -#define GL_ARB_shadow 1 -#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C -#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D -#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E -#endif /* GL_ARB_shadow */ - -#ifndef GL_ARB_shadow_ambient -#define GL_ARB_shadow_ambient 1 -#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF -#endif /* GL_ARB_shadow_ambient */ - -#ifndef GL_ARB_sparse_texture -#define GL_ARB_sparse_texture 1 -#define GL_TEXTURE_SPARSE_ARB 0x91A6 -#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 -#define GL_MIN_SPARSE_LEVEL_ARB 0x919B -#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 -#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 -#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 -#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 -#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 -#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 -#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A -#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 -typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); -#endif -#endif /* GL_ARB_sparse_texture */ - -#ifndef GL_ARB_stencil_texturing -#define GL_ARB_stencil_texturing 1 -#endif /* GL_ARB_stencil_texturing */ - -#ifndef GL_ARB_sync -#define GL_ARB_sync 1 -#endif /* GL_ARB_sync */ - -#ifndef GL_ARB_tessellation_shader -#define GL_ARB_tessellation_shader 1 -#endif /* GL_ARB_tessellation_shader */ - -#ifndef GL_ARB_texture_border_clamp -#define GL_ARB_texture_border_clamp 1 -#define GL_CLAMP_TO_BORDER_ARB 0x812D -#endif /* GL_ARB_texture_border_clamp */ - -#ifndef GL_ARB_texture_buffer_object -#define GL_ARB_texture_buffer_object 1 -#define GL_TEXTURE_BUFFER_ARB 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E -typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); -#endif -#endif /* GL_ARB_texture_buffer_object */ - -#ifndef GL_ARB_texture_buffer_object_rgb32 -#define GL_ARB_texture_buffer_object_rgb32 1 -#endif /* GL_ARB_texture_buffer_object_rgb32 */ - -#ifndef GL_ARB_texture_buffer_range -#define GL_ARB_texture_buffer_range 1 -#endif /* GL_ARB_texture_buffer_range */ - -#ifndef GL_ARB_texture_compression -#define GL_ARB_texture_compression 1 -#define GL_COMPRESSED_ALPHA_ARB 0x84E9 -#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB -#define GL_COMPRESSED_INTENSITY_ARB 0x84EC -#define GL_COMPRESSED_RGB_ARB 0x84ED -#define GL_COMPRESSED_RGBA_ARB 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 -#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img); -#endif -#endif /* GL_ARB_texture_compression */ - -#ifndef GL_ARB_texture_compression_bptc -#define GL_ARB_texture_compression_bptc 1 -#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C -#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D -#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E -#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F -#endif /* GL_ARB_texture_compression_bptc */ - -#ifndef GL_ARB_texture_compression_rgtc -#define GL_ARB_texture_compression_rgtc 1 -#endif /* GL_ARB_texture_compression_rgtc */ - -#ifndef GL_ARB_texture_cube_map -#define GL_ARB_texture_cube_map 1 -#define GL_NORMAL_MAP_ARB 0x8511 -#define GL_REFLECTION_MAP_ARB 0x8512 -#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C -#endif /* GL_ARB_texture_cube_map */ - -#ifndef GL_ARB_texture_cube_map_array -#define GL_ARB_texture_cube_map_array 1 -#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F -#endif /* GL_ARB_texture_cube_map_array */ - -#ifndef GL_ARB_texture_env_add -#define GL_ARB_texture_env_add 1 -#endif /* GL_ARB_texture_env_add */ - -#ifndef GL_ARB_texture_env_combine -#define GL_ARB_texture_env_combine 1 -#define GL_COMBINE_ARB 0x8570 -#define GL_COMBINE_RGB_ARB 0x8571 -#define GL_COMBINE_ALPHA_ARB 0x8572 -#define GL_SOURCE0_RGB_ARB 0x8580 -#define GL_SOURCE1_RGB_ARB 0x8581 -#define GL_SOURCE2_RGB_ARB 0x8582 -#define GL_SOURCE0_ALPHA_ARB 0x8588 -#define GL_SOURCE1_ALPHA_ARB 0x8589 -#define GL_SOURCE2_ALPHA_ARB 0x858A -#define GL_OPERAND0_RGB_ARB 0x8590 -#define GL_OPERAND1_RGB_ARB 0x8591 -#define GL_OPERAND2_RGB_ARB 0x8592 -#define GL_OPERAND0_ALPHA_ARB 0x8598 -#define GL_OPERAND1_ALPHA_ARB 0x8599 -#define GL_OPERAND2_ALPHA_ARB 0x859A -#define GL_RGB_SCALE_ARB 0x8573 -#define GL_ADD_SIGNED_ARB 0x8574 -#define GL_INTERPOLATE_ARB 0x8575 -#define GL_SUBTRACT_ARB 0x84E7 -#define GL_CONSTANT_ARB 0x8576 -#define GL_PRIMARY_COLOR_ARB 0x8577 -#define GL_PREVIOUS_ARB 0x8578 -#endif /* GL_ARB_texture_env_combine */ - -#ifndef GL_ARB_texture_env_crossbar -#define GL_ARB_texture_env_crossbar 1 -#endif /* GL_ARB_texture_env_crossbar */ - -#ifndef GL_ARB_texture_env_dot3 -#define GL_ARB_texture_env_dot3 1 -#define GL_DOT3_RGB_ARB 0x86AE -#define GL_DOT3_RGBA_ARB 0x86AF -#endif /* GL_ARB_texture_env_dot3 */ - -#ifndef GL_ARB_texture_float -#define GL_ARB_texture_float 1 -#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 -#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 -#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 -#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 -#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 -#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 -#define GL_RGBA32F_ARB 0x8814 -#define GL_RGB32F_ARB 0x8815 -#define GL_ALPHA32F_ARB 0x8816 -#define GL_INTENSITY32F_ARB 0x8817 -#define GL_LUMINANCE32F_ARB 0x8818 -#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 -#define GL_RGBA16F_ARB 0x881A -#define GL_RGB16F_ARB 0x881B -#define GL_ALPHA16F_ARB 0x881C -#define GL_INTENSITY16F_ARB 0x881D -#define GL_LUMINANCE16F_ARB 0x881E -#define GL_LUMINANCE_ALPHA16F_ARB 0x881F -#endif /* GL_ARB_texture_float */ - -#ifndef GL_ARB_texture_gather -#define GL_ARB_texture_gather 1 -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F -#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F -#endif /* GL_ARB_texture_gather */ - -#ifndef GL_ARB_texture_mirror_clamp_to_edge -#define GL_ARB_texture_mirror_clamp_to_edge 1 -#endif /* GL_ARB_texture_mirror_clamp_to_edge */ - -#ifndef GL_ARB_texture_mirrored_repeat -#define GL_ARB_texture_mirrored_repeat 1 -#define GL_MIRRORED_REPEAT_ARB 0x8370 -#endif /* GL_ARB_texture_mirrored_repeat */ - -#ifndef GL_ARB_texture_multisample -#define GL_ARB_texture_multisample 1 -#endif /* GL_ARB_texture_multisample */ - -#ifndef GL_ARB_texture_non_power_of_two -#define GL_ARB_texture_non_power_of_two 1 -#endif /* GL_ARB_texture_non_power_of_two */ - -#ifndef GL_ARB_texture_query_levels -#define GL_ARB_texture_query_levels 1 -#endif /* GL_ARB_texture_query_levels */ - -#ifndef GL_ARB_texture_query_lod -#define GL_ARB_texture_query_lod 1 -#endif /* GL_ARB_texture_query_lod */ - -#ifndef GL_ARB_texture_rectangle -#define GL_ARB_texture_rectangle 1 -#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 -#endif /* GL_ARB_texture_rectangle */ - -#ifndef GL_ARB_texture_rg -#define GL_ARB_texture_rg 1 -#endif /* GL_ARB_texture_rg */ - -#ifndef GL_ARB_texture_rgb10_a2ui -#define GL_ARB_texture_rgb10_a2ui 1 -#endif /* GL_ARB_texture_rgb10_a2ui */ - -#ifndef GL_ARB_texture_stencil8 -#define GL_ARB_texture_stencil8 1 -#endif /* GL_ARB_texture_stencil8 */ - -#ifndef GL_ARB_texture_storage -#define GL_ARB_texture_storage 1 -#endif /* GL_ARB_texture_storage */ - -#ifndef GL_ARB_texture_storage_multisample -#define GL_ARB_texture_storage_multisample 1 -#endif /* GL_ARB_texture_storage_multisample */ - -#ifndef GL_ARB_texture_swizzle -#define GL_ARB_texture_swizzle 1 -#endif /* GL_ARB_texture_swizzle */ - -#ifndef GL_ARB_texture_view -#define GL_ARB_texture_view 1 -#endif /* GL_ARB_texture_view */ - -#ifndef GL_ARB_timer_query -#define GL_ARB_timer_query 1 -#endif /* GL_ARB_timer_query */ - -#ifndef GL_ARB_transform_feedback2 -#define GL_ARB_transform_feedback2 1 -#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 -#endif /* GL_ARB_transform_feedback2 */ - -#ifndef GL_ARB_transform_feedback3 -#define GL_ARB_transform_feedback3 1 -#endif /* GL_ARB_transform_feedback3 */ - -#ifndef GL_ARB_transform_feedback_instanced -#define GL_ARB_transform_feedback_instanced 1 -#endif /* GL_ARB_transform_feedback_instanced */ - -#ifndef GL_ARB_transpose_matrix -#define GL_ARB_transpose_matrix 1 -#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); -GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); -GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); -GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); -#endif -#endif /* GL_ARB_transpose_matrix */ - -#ifndef GL_ARB_uniform_buffer_object -#define GL_ARB_uniform_buffer_object 1 -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#endif /* GL_ARB_uniform_buffer_object */ - -#ifndef GL_ARB_vertex_array_bgra -#define GL_ARB_vertex_array_bgra 1 -#endif /* GL_ARB_vertex_array_bgra */ - -#ifndef GL_ARB_vertex_array_object -#define GL_ARB_vertex_array_object 1 -#endif /* GL_ARB_vertex_array_object */ - -#ifndef GL_ARB_vertex_attrib_64bit -#define GL_ARB_vertex_attrib_64bit 1 -#endif /* GL_ARB_vertex_attrib_64bit */ - -#ifndef GL_ARB_vertex_attrib_binding -#define GL_ARB_vertex_attrib_binding 1 -#endif /* GL_ARB_vertex_attrib_binding */ - -#ifndef GL_ARB_vertex_blend -#define GL_ARB_vertex_blend 1 -#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 -#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 -#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 -#define GL_VERTEX_BLEND_ARB 0x86A7 -#define GL_CURRENT_WEIGHT_ARB 0x86A8 -#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 -#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA -#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB -#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC -#define GL_WEIGHT_ARRAY_ARB 0x86AD -#define GL_MODELVIEW0_ARB 0x1700 -#define GL_MODELVIEW1_ARB 0x850A -#define GL_MODELVIEW2_ARB 0x8722 -#define GL_MODELVIEW3_ARB 0x8723 -#define GL_MODELVIEW4_ARB 0x8724 -#define GL_MODELVIEW5_ARB 0x8725 -#define GL_MODELVIEW6_ARB 0x8726 -#define GL_MODELVIEW7_ARB 0x8727 -#define GL_MODELVIEW8_ARB 0x8728 -#define GL_MODELVIEW9_ARB 0x8729 -#define GL_MODELVIEW10_ARB 0x872A -#define GL_MODELVIEW11_ARB 0x872B -#define GL_MODELVIEW12_ARB 0x872C -#define GL_MODELVIEW13_ARB 0x872D -#define GL_MODELVIEW14_ARB 0x872E -#define GL_MODELVIEW15_ARB 0x872F -#define GL_MODELVIEW16_ARB 0x8730 -#define GL_MODELVIEW17_ARB 0x8731 -#define GL_MODELVIEW18_ARB 0x8732 -#define GL_MODELVIEW19_ARB 0x8733 -#define GL_MODELVIEW20_ARB 0x8734 -#define GL_MODELVIEW21_ARB 0x8735 -#define GL_MODELVIEW22_ARB 0x8736 -#define GL_MODELVIEW23_ARB 0x8737 -#define GL_MODELVIEW24_ARB 0x8738 -#define GL_MODELVIEW25_ARB 0x8739 -#define GL_MODELVIEW26_ARB 0x873A -#define GL_MODELVIEW27_ARB 0x873B -#define GL_MODELVIEW28_ARB 0x873C -#define GL_MODELVIEW29_ARB 0x873D -#define GL_MODELVIEW30_ARB 0x873E -#define GL_MODELVIEW31_ARB 0x873F -typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); -typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); -typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); -typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); -typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); -typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); -typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); -typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); -typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); -GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); -GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); -GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); -GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); -GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); -GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); -GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); -GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glVertexBlendARB (GLint count); -#endif -#endif /* GL_ARB_vertex_blend */ - -#ifndef GL_ARB_vertex_buffer_object -#define GL_ARB_vertex_buffer_object 1 -typedef ptrdiff_t GLsizeiptrARB; -typedef ptrdiff_t GLintptrARB; -#define GL_BUFFER_SIZE_ARB 0x8764 -#define GL_BUFFER_USAGE_ARB 0x8765 -#define GL_ARRAY_BUFFER_ARB 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 -#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 -#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F -#define GL_READ_ONLY_ARB 0x88B8 -#define GL_WRITE_ONLY_ARB 0x88B9 -#define GL_READ_WRITE_ARB 0x88BA -#define GL_BUFFER_ACCESS_ARB 0x88BB -#define GL_BUFFER_MAPPED_ARB 0x88BC -#define GL_BUFFER_MAP_POINTER_ARB 0x88BD -#define GL_STREAM_DRAW_ARB 0x88E0 -#define GL_STREAM_READ_ARB 0x88E1 -#define GL_STREAM_COPY_ARB 0x88E2 -#define GL_STATIC_DRAW_ARB 0x88E4 -#define GL_STATIC_READ_ARB 0x88E5 -#define GL_STATIC_COPY_ARB 0x88E6 -#define GL_DYNAMIC_DRAW_ARB 0x88E8 -#define GL_DYNAMIC_READ_ARB 0x88E9 -#define GL_DYNAMIC_COPY_ARB 0x88EA -typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); -typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); -GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); -GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); -GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); -GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); -GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params); -#endif -#endif /* GL_ARB_vertex_buffer_object */ - -#ifndef GL_ARB_vertex_program -#define GL_ARB_vertex_program 1 -#define GL_COLOR_SUM_ARB 0x8458 -#define GL_VERTEX_PROGRAM_ARB 0x8620 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 -#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A -#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 -#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 -#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 -#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); -GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); -GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer); -#endif -#endif /* GL_ARB_vertex_program */ - -#ifndef GL_ARB_vertex_shader -#define GL_ARB_vertex_shader 1 -#define GL_VERTEX_SHADER_ARB 0x8B31 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A -#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D -#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 -#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); -GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); -#endif -#endif /* GL_ARB_vertex_shader */ - -#ifndef GL_ARB_vertex_type_10f_11f_11f_rev -#define GL_ARB_vertex_type_10f_11f_11f_rev 1 -#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ - -#ifndef GL_ARB_vertex_type_2_10_10_10_rev -#define GL_ARB_vertex_type_2_10_10_10_rev 1 -#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ - -#ifndef GL_ARB_viewport_array -#define GL_ARB_viewport_array 1 -#endif /* GL_ARB_viewport_array */ - -#ifndef GL_ARB_window_pos -#define GL_ARB_window_pos 1 -typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); -GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); -GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); -GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); -#endif -#endif /* GL_ARB_window_pos */ - -#ifndef GL_KHR_debug -#define GL_KHR_debug 1 -#endif /* GL_KHR_debug */ - -#ifndef GL_KHR_texture_compression_astc_hdr -#define GL_KHR_texture_compression_astc_hdr 1 -#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 -#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 -#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 -#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 -#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 -#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 -#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 -#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 -#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 -#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 -#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA -#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB -#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC -#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC -#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD -#endif /* GL_KHR_texture_compression_astc_hdr */ - -#ifndef GL_KHR_texture_compression_astc_ldr -#define GL_KHR_texture_compression_astc_ldr 1 -#endif /* GL_KHR_texture_compression_astc_ldr */ - -#ifndef GL_OES_byte_coordinates -#define GL_OES_byte_coordinates 1 -typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords); -typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s); -typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t); -typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r); -typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q); -typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x); -typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y); -typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z); -typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s); -GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords); -GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t); -GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords); -GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r); -GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords); -GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); -GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords); -GLAPI void APIENTRY glTexCoord1bOES (GLbyte s); -GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords); -GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t); -GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords); -GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r); -GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords); -GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q); -GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords); -GLAPI void APIENTRY glVertex2bOES (GLbyte x); -GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords); -GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y); -GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords); -GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z); -GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords); -#endif -#endif /* GL_OES_byte_coordinates */ - -#ifndef GL_OES_compressed_paletted_texture -#define GL_OES_compressed_paletted_texture 1 -#define GL_PALETTE4_RGB8_OES 0x8B90 -#define GL_PALETTE4_RGBA8_OES 0x8B91 -#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 -#define GL_PALETTE4_RGBA4_OES 0x8B93 -#define GL_PALETTE4_RGB5_A1_OES 0x8B94 -#define GL_PALETTE8_RGB8_OES 0x8B95 -#define GL_PALETTE8_RGBA8_OES 0x8B96 -#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 -#define GL_PALETTE8_RGBA4_OES 0x8B98 -#define GL_PALETTE8_RGB5_A1_OES 0x8B99 -#endif /* GL_OES_compressed_paletted_texture */ - -#ifndef GL_OES_fixed_point -#define GL_OES_fixed_point 1 -typedef GLint GLfixed; -#define GL_FIXED_OES 0x140C -typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref); -typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth); -typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation); -typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f); -typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param); -typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); -typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation); -typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param); -typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params); -typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width); -typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m); -typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param); -typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); -typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz); -typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); -typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params); -typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size); -typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units); -typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert); -typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); -typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); -typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); -typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value); -typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); -typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue); -typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components); -typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); -typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u); -typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v); -typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v); -typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values); -typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params); -typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component); -typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); -typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); -typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); -typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2); -typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords); -typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token); -typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values); -typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor); -typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities); -typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y); -typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z); -typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w); -typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); -typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2); -typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s); -typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t); -typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r); -typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q); -typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param); -typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params); -typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x); -typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y); -typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords); -typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z); -typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref); -GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -GLAPI void APIENTRY glClearDepthxOES (GLfixed depth); -GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation); -GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f); -GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param); -GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param); -GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); -GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation); -GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params); -GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param); -GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param); -GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param); -GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params); -GLAPI void APIENTRY glLineWidthxOES (GLfixed width); -GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m); -GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param); -GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param); -GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m); -GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); -GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz); -GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); -GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params); -GLAPI void APIENTRY glPointSizexOES (GLfixed size); -GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units); -GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); -GLAPI void APIENTRY glSampleCoverageOES (GLfixed value, GLboolean invert); -GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z); -GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param); -GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params); -GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param); -GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); -GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z); -GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value); -GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); -GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); -GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue); -GLAPI void APIENTRY glColor3xvOES (const GLfixed *components); -GLAPI void APIENTRY glColor4xvOES (const GLfixed *components); -GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param); -GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); -GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u); -GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords); -GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v); -GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords); -GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer); -GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v); -GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param); -GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values); -GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params); -GLAPI void APIENTRY glIndexxOES (GLfixed component); -GLAPI void APIENTRY glIndexxvOES (const GLfixed *component); -GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m); -GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); -GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); -GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2); -GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); -GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m); -GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s); -GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords); -GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t); -GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords); -GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r); -GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords); -GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords); -GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords); -GLAPI void APIENTRY glPassThroughxOES (GLfixed token); -GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values); -GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param); -GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param); -GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor); -GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities); -GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y); -GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords); -GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z); -GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords); -GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w); -GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords); -GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); -GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2); -GLAPI void APIENTRY glTexCoord1xOES (GLfixed s); -GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords); -GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t); -GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords); -GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r); -GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords); -GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q); -GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords); -GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param); -GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params); -GLAPI void APIENTRY glVertex2xOES (GLfixed x); -GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords); -GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y); -GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords); -GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z); -GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords); -#endif -#endif /* GL_OES_fixed_point */ - -#ifndef GL_OES_query_matrix -#define GL_OES_query_matrix 1 -typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent); -#endif -#endif /* GL_OES_query_matrix */ - -#ifndef GL_OES_read_format -#define GL_OES_read_format 1 -#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B -#endif /* GL_OES_read_format */ - -#ifndef GL_OES_single_precision -#define GL_OES_single_precision 1 -typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth); -typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation); -typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f); -typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); -typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation); -typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClearDepthfOES (GLclampf depth); -GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation); -GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f); -GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); -GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation); -GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); -#endif -#endif /* GL_OES_single_precision */ - -#ifndef GL_3DFX_multisample -#define GL_3DFX_multisample 1 -#define GL_MULTISAMPLE_3DFX 0x86B2 -#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 -#define GL_SAMPLES_3DFX 0x86B4 -#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 -#endif /* GL_3DFX_multisample */ - -#ifndef GL_3DFX_tbuffer -#define GL_3DFX_tbuffer 1 -typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); -#endif -#endif /* GL_3DFX_tbuffer */ - -#ifndef GL_3DFX_texture_compression_FXT1 -#define GL_3DFX_texture_compression_FXT1 1 -#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 -#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 -#endif /* GL_3DFX_texture_compression_FXT1 */ - -#ifndef GL_AMD_blend_minmax_factor -#define GL_AMD_blend_minmax_factor 1 -#define GL_FACTOR_MIN_AMD 0x901C -#define GL_FACTOR_MAX_AMD 0x901D -#endif /* GL_AMD_blend_minmax_factor */ - -#ifndef GL_AMD_conservative_depth -#define GL_AMD_conservative_depth 1 -#endif /* GL_AMD_conservative_depth */ - -#ifndef GL_AMD_debug_output -#define GL_AMD_debug_output 1 -typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); -#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 -#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 -#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 -#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A -#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B -#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C -#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D -#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E -#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F -#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 -typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); -#endif -#endif /* GL_AMD_debug_output */ - -#ifndef GL_AMD_depth_clamp_separate -#define GL_AMD_depth_clamp_separate 1 -#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E -#define GL_DEPTH_CLAMP_FAR_AMD 0x901F -#endif /* GL_AMD_depth_clamp_separate */ - -#ifndef GL_AMD_draw_buffers_blend -#define GL_AMD_draw_buffers_blend 1 -typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -#endif -#endif /* GL_AMD_draw_buffers_blend */ - -#ifndef GL_AMD_interleaved_elements -#define GL_AMD_interleaved_elements 1 -#define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 -#define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 -typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param); -#endif -#endif /* GL_AMD_interleaved_elements */ - -#ifndef GL_AMD_multi_draw_indirect -#define GL_AMD_multi_draw_indirect 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); -#endif -#endif /* GL_AMD_multi_draw_indirect */ - -#ifndef GL_AMD_name_gen_delete -#define GL_AMD_name_gen_delete 1 -#define GL_DATA_BUFFER_AMD 0x9151 -#define GL_PERFORMANCE_MONITOR_AMD 0x9152 -#define GL_QUERY_OBJECT_AMD 0x9153 -#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 -#define GL_SAMPLER_OBJECT_AMD 0x9155 -typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); -typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); -typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); -GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); -GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); -#endif -#endif /* GL_AMD_name_gen_delete */ - -#ifndef GL_AMD_occlusion_query_event -#define GL_AMD_occlusion_query_event 1 -#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F -#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001 -#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002 -#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004 -#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008 -#define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF -typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param); -#endif -#endif /* GL_AMD_occlusion_query_event */ - -#ifndef GL_AMD_performance_monitor -#define GL_AMD_performance_monitor 1 -#define GL_COUNTER_TYPE_AMD 0x8BC0 -#define GL_COUNTER_RANGE_AMD 0x8BC1 -#define GL_UNSIGNED_INT64_AMD 0x8BC2 -#define GL_PERCENTAGE_AMD 0x8BC3 -#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 -#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 -#define GL_PERFMON_RESULT_AMD 0x8BC6 -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); -typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); -GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); -#endif -#endif /* GL_AMD_performance_monitor */ - -#ifndef GL_AMD_pinned_memory -#define GL_AMD_pinned_memory 1 -#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 -#endif /* GL_AMD_pinned_memory */ - -#ifndef GL_AMD_query_buffer_object -#define GL_AMD_query_buffer_object 1 -#define GL_QUERY_BUFFER_AMD 0x9192 -#define GL_QUERY_BUFFER_BINDING_AMD 0x9193 -#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 -#endif /* GL_AMD_query_buffer_object */ - -#ifndef GL_AMD_sample_positions -#define GL_AMD_sample_positions 1 -#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F -typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); -#endif -#endif /* GL_AMD_sample_positions */ - -#ifndef GL_AMD_seamless_cubemap_per_texture -#define GL_AMD_seamless_cubemap_per_texture 1 -#endif /* GL_AMD_seamless_cubemap_per_texture */ - -#ifndef GL_AMD_shader_atomic_counter_ops -#define GL_AMD_shader_atomic_counter_ops 1 -#endif /* GL_AMD_shader_atomic_counter_ops */ - -#ifndef GL_AMD_shader_stencil_export -#define GL_AMD_shader_stencil_export 1 -#endif /* GL_AMD_shader_stencil_export */ - -#ifndef GL_AMD_shader_trinary_minmax -#define GL_AMD_shader_trinary_minmax 1 -#endif /* GL_AMD_shader_trinary_minmax */ - -#ifndef GL_AMD_sparse_texture -#define GL_AMD_sparse_texture 1 -#define GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195 -#define GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196 -#define GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197 -#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198 -#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199 -#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A -#define GL_MIN_SPARSE_LEVEL_AMD 0x919B -#define GL_MIN_LOD_WARNING_AMD 0x919C -#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 -typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); -typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); -GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); -#endif -#endif /* GL_AMD_sparse_texture */ - -#ifndef GL_AMD_stencil_operation_extended -#define GL_AMD_stencil_operation_extended 1 -#define GL_SET_AMD 0x874A -#define GL_REPLACE_VALUE_AMD 0x874B -#define GL_STENCIL_OP_VALUE_AMD 0x874C -#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D -typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); -#endif -#endif /* GL_AMD_stencil_operation_extended */ - -#ifndef GL_AMD_texture_texture4 -#define GL_AMD_texture_texture4 1 -#endif /* GL_AMD_texture_texture4 */ - -#ifndef GL_AMD_transform_feedback3_lines_triangles -#define GL_AMD_transform_feedback3_lines_triangles 1 -#endif /* GL_AMD_transform_feedback3_lines_triangles */ - -#ifndef GL_AMD_vertex_shader_layer -#define GL_AMD_vertex_shader_layer 1 -#endif /* GL_AMD_vertex_shader_layer */ - -#ifndef GL_AMD_vertex_shader_tessellator -#define GL_AMD_vertex_shader_tessellator 1 -#define GL_SAMPLER_BUFFER_AMD 0x9001 -#define GL_INT_SAMPLER_BUFFER_AMD 0x9002 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 -#define GL_TESSELLATION_MODE_AMD 0x9004 -#define GL_TESSELLATION_FACTOR_AMD 0x9005 -#define GL_DISCRETE_AMD 0x9006 -#define GL_CONTINUOUS_AMD 0x9007 -typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); -typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); -GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); -#endif -#endif /* GL_AMD_vertex_shader_tessellator */ - -#ifndef GL_AMD_vertex_shader_viewport_index -#define GL_AMD_vertex_shader_viewport_index 1 -#endif /* GL_AMD_vertex_shader_viewport_index */ - -#ifndef GL_APPLE_aux_depth_stencil -#define GL_APPLE_aux_depth_stencil 1 -#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 -#endif /* GL_APPLE_aux_depth_stencil */ - -#ifndef GL_APPLE_client_storage -#define GL_APPLE_client_storage 1 -#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 -#endif /* GL_APPLE_client_storage */ - -#ifndef GL_APPLE_element_array -#define GL_APPLE_element_array 1 -#define GL_ELEMENT_ARRAY_APPLE 0x8A0C -#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D -#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E -typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer); -typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer); -GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); -#endif -#endif /* GL_APPLE_element_array */ - -#ifndef GL_APPLE_fence -#define GL_APPLE_fence 1 -#define GL_DRAW_PIXELS_APPLE 0x8A0A -#define GL_FENCE_APPLE 0x8A0B -typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); -typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); -typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); -typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); -GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); -GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); -GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); -GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); -#endif -#endif /* GL_APPLE_fence */ - -#ifndef GL_APPLE_float_pixels -#define GL_APPLE_float_pixels 1 -#define GL_HALF_APPLE 0x140B -#define GL_RGBA_FLOAT32_APPLE 0x8814 -#define GL_RGB_FLOAT32_APPLE 0x8815 -#define GL_ALPHA_FLOAT32_APPLE 0x8816 -#define GL_INTENSITY_FLOAT32_APPLE 0x8817 -#define GL_LUMINANCE_FLOAT32_APPLE 0x8818 -#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 -#define GL_RGBA_FLOAT16_APPLE 0x881A -#define GL_RGB_FLOAT16_APPLE 0x881B -#define GL_ALPHA_FLOAT16_APPLE 0x881C -#define GL_INTENSITY_FLOAT16_APPLE 0x881D -#define GL_LUMINANCE_FLOAT16_APPLE 0x881E -#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F -#define GL_COLOR_FLOAT_APPLE 0x8A0F -#endif /* GL_APPLE_float_pixels */ - -#ifndef GL_APPLE_flush_buffer_range -#define GL_APPLE_flush_buffer_range 1 -#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 -#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 -typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); -#endif -#endif /* GL_APPLE_flush_buffer_range */ - -#ifndef GL_APPLE_object_purgeable -#define GL_APPLE_object_purgeable 1 -#define GL_BUFFER_OBJECT_APPLE 0x85B3 -#define GL_RELEASED_APPLE 0x8A19 -#define GL_VOLATILE_APPLE 0x8A1A -#define GL_RETAINED_APPLE 0x8A1B -#define GL_UNDEFINED_APPLE 0x8A1C -#define GL_PURGEABLE_APPLE 0x8A1D -typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); -typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); -GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); -GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); -#endif -#endif /* GL_APPLE_object_purgeable */ - -#ifndef GL_APPLE_rgb_422 -#define GL_APPLE_rgb_422 1 -#define GL_RGB_422_APPLE 0x8A1F -#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB -#define GL_RGB_RAW_422_APPLE 0x8A51 -#endif /* GL_APPLE_rgb_422 */ - -#ifndef GL_APPLE_row_bytes -#define GL_APPLE_row_bytes 1 -#define GL_PACK_ROW_BYTES_APPLE 0x8A15 -#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 -#endif /* GL_APPLE_row_bytes */ - -#ifndef GL_APPLE_specular_vector -#define GL_APPLE_specular_vector 1 -#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 -#endif /* GL_APPLE_specular_vector */ - -#ifndef GL_APPLE_texture_range -#define GL_APPLE_texture_range 1 -#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 -#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 -#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC -#define GL_STORAGE_PRIVATE_APPLE 0x85BD -#define GL_STORAGE_CACHED_APPLE 0x85BE -#define GL_STORAGE_SHARED_APPLE 0x85BF -typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer); -GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params); -#endif -#endif /* GL_APPLE_texture_range */ - -#ifndef GL_APPLE_transform_hint -#define GL_APPLE_transform_hint 1 -#define GL_TRANSFORM_HINT_APPLE 0x85B1 -#endif /* GL_APPLE_transform_hint */ - -#ifndef GL_APPLE_vertex_array_object -#define GL_APPLE_vertex_array_object 1 -#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); -GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); -#endif -#endif /* GL_APPLE_vertex_array_object */ - -#ifndef GL_APPLE_vertex_array_range -#define GL_APPLE_vertex_array_range 1 -#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D -#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E -#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F -#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 -#define GL_STORAGE_CLIENT_APPLE 0x85B4 -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); -typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer); -GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer); -GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); -#endif -#endif /* GL_APPLE_vertex_array_range */ - -#ifndef GL_APPLE_vertex_program_evaluators -#define GL_APPLE_vertex_program_evaluators 1 -#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 -#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 -#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 -#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 -#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 -#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 -#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 -#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 -#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 -#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); -typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); -GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); -GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); -GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -#endif -#endif /* GL_APPLE_vertex_program_evaluators */ - -#ifndef GL_APPLE_ycbcr_422 -#define GL_APPLE_ycbcr_422 1 -#define GL_YCBCR_422_APPLE 0x85B9 -#endif /* GL_APPLE_ycbcr_422 */ - -#ifndef GL_ATI_draw_buffers -#define GL_ATI_draw_buffers 1 -#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 -#define GL_DRAW_BUFFER0_ATI 0x8825 -#define GL_DRAW_BUFFER1_ATI 0x8826 -#define GL_DRAW_BUFFER2_ATI 0x8827 -#define GL_DRAW_BUFFER3_ATI 0x8828 -#define GL_DRAW_BUFFER4_ATI 0x8829 -#define GL_DRAW_BUFFER5_ATI 0x882A -#define GL_DRAW_BUFFER6_ATI 0x882B -#define GL_DRAW_BUFFER7_ATI 0x882C -#define GL_DRAW_BUFFER8_ATI 0x882D -#define GL_DRAW_BUFFER9_ATI 0x882E -#define GL_DRAW_BUFFER10_ATI 0x882F -#define GL_DRAW_BUFFER11_ATI 0x8830 -#define GL_DRAW_BUFFER12_ATI 0x8831 -#define GL_DRAW_BUFFER13_ATI 0x8832 -#define GL_DRAW_BUFFER14_ATI 0x8833 -#define GL_DRAW_BUFFER15_ATI 0x8834 -typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); -#endif -#endif /* GL_ATI_draw_buffers */ - -#ifndef GL_ATI_element_array -#define GL_ATI_element_array 1 -#define GL_ELEMENT_ARRAY_ATI 0x8768 -#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 -#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A -typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer); -typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer); -GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); -GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); -#endif -#endif /* GL_ATI_element_array */ - -#ifndef GL_ATI_envmap_bumpmap -#define GL_ATI_envmap_bumpmap 1 -#define GL_BUMP_ROT_MATRIX_ATI 0x8775 -#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 -#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 -#define GL_BUMP_TEX_UNITS_ATI 0x8778 -#define GL_DUDV_ATI 0x8779 -#define GL_DU8DV8_ATI 0x877A -#define GL_BUMP_ENVMAP_ATI 0x877B -#define GL_BUMP_TARGET_ATI 0x877C -typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); -GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); -GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); -#endif -#endif /* GL_ATI_envmap_bumpmap */ - -#ifndef GL_ATI_fragment_shader -#define GL_ATI_fragment_shader 1 -#define GL_FRAGMENT_SHADER_ATI 0x8920 -#define GL_REG_0_ATI 0x8921 -#define GL_REG_1_ATI 0x8922 -#define GL_REG_2_ATI 0x8923 -#define GL_REG_3_ATI 0x8924 -#define GL_REG_4_ATI 0x8925 -#define GL_REG_5_ATI 0x8926 -#define GL_REG_6_ATI 0x8927 -#define GL_REG_7_ATI 0x8928 -#define GL_REG_8_ATI 0x8929 -#define GL_REG_9_ATI 0x892A -#define GL_REG_10_ATI 0x892B -#define GL_REG_11_ATI 0x892C -#define GL_REG_12_ATI 0x892D -#define GL_REG_13_ATI 0x892E -#define GL_REG_14_ATI 0x892F -#define GL_REG_15_ATI 0x8930 -#define GL_REG_16_ATI 0x8931 -#define GL_REG_17_ATI 0x8932 -#define GL_REG_18_ATI 0x8933 -#define GL_REG_19_ATI 0x8934 -#define GL_REG_20_ATI 0x8935 -#define GL_REG_21_ATI 0x8936 -#define GL_REG_22_ATI 0x8937 -#define GL_REG_23_ATI 0x8938 -#define GL_REG_24_ATI 0x8939 -#define GL_REG_25_ATI 0x893A -#define GL_REG_26_ATI 0x893B -#define GL_REG_27_ATI 0x893C -#define GL_REG_28_ATI 0x893D -#define GL_REG_29_ATI 0x893E -#define GL_REG_30_ATI 0x893F -#define GL_REG_31_ATI 0x8940 -#define GL_CON_0_ATI 0x8941 -#define GL_CON_1_ATI 0x8942 -#define GL_CON_2_ATI 0x8943 -#define GL_CON_3_ATI 0x8944 -#define GL_CON_4_ATI 0x8945 -#define GL_CON_5_ATI 0x8946 -#define GL_CON_6_ATI 0x8947 -#define GL_CON_7_ATI 0x8948 -#define GL_CON_8_ATI 0x8949 -#define GL_CON_9_ATI 0x894A -#define GL_CON_10_ATI 0x894B -#define GL_CON_11_ATI 0x894C -#define GL_CON_12_ATI 0x894D -#define GL_CON_13_ATI 0x894E -#define GL_CON_14_ATI 0x894F -#define GL_CON_15_ATI 0x8950 -#define GL_CON_16_ATI 0x8951 -#define GL_CON_17_ATI 0x8952 -#define GL_CON_18_ATI 0x8953 -#define GL_CON_19_ATI 0x8954 -#define GL_CON_20_ATI 0x8955 -#define GL_CON_21_ATI 0x8956 -#define GL_CON_22_ATI 0x8957 -#define GL_CON_23_ATI 0x8958 -#define GL_CON_24_ATI 0x8959 -#define GL_CON_25_ATI 0x895A -#define GL_CON_26_ATI 0x895B -#define GL_CON_27_ATI 0x895C -#define GL_CON_28_ATI 0x895D -#define GL_CON_29_ATI 0x895E -#define GL_CON_30_ATI 0x895F -#define GL_CON_31_ATI 0x8960 -#define GL_MOV_ATI 0x8961 -#define GL_ADD_ATI 0x8963 -#define GL_MUL_ATI 0x8964 -#define GL_SUB_ATI 0x8965 -#define GL_DOT3_ATI 0x8966 -#define GL_DOT4_ATI 0x8967 -#define GL_MAD_ATI 0x8968 -#define GL_LERP_ATI 0x8969 -#define GL_CND_ATI 0x896A -#define GL_CND0_ATI 0x896B -#define GL_DOT2_ADD_ATI 0x896C -#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D -#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E -#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F -#define GL_NUM_PASSES_ATI 0x8970 -#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 -#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 -#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 -#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 -#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 -#define GL_SWIZZLE_STR_ATI 0x8976 -#define GL_SWIZZLE_STQ_ATI 0x8977 -#define GL_SWIZZLE_STR_DR_ATI 0x8978 -#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 -#define GL_SWIZZLE_STRQ_ATI 0x897A -#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B -#define GL_RED_BIT_ATI 0x00000001 -#define GL_GREEN_BIT_ATI 0x00000002 -#define GL_BLUE_BIT_ATI 0x00000004 -#define GL_2X_BIT_ATI 0x00000001 -#define GL_4X_BIT_ATI 0x00000002 -#define GL_8X_BIT_ATI 0x00000004 -#define GL_HALF_BIT_ATI 0x00000008 -#define GL_QUARTER_BIT_ATI 0x00000010 -#define GL_EIGHTH_BIT_ATI 0x00000020 -#define GL_SATURATE_BIT_ATI 0x00000040 -#define GL_COMP_BIT_ATI 0x00000002 -#define GL_NEGATE_BIT_ATI 0x00000004 -#define GL_BIAS_BIT_ATI 0x00000008 -typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); -typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); -typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); -typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); -typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); -typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); -GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); -GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); -GLAPI void APIENTRY glBeginFragmentShaderATI (void); -GLAPI void APIENTRY glEndFragmentShaderATI (void); -GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); -GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); -GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); -#endif -#endif /* GL_ATI_fragment_shader */ - -#ifndef GL_ATI_map_object_buffer -#define GL_ATI_map_object_buffer 1 -typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); -#endif -#endif /* GL_ATI_map_object_buffer */ - -#ifndef GL_ATI_meminfo -#define GL_ATI_meminfo 1 -#define GL_VBO_FREE_MEMORY_ATI 0x87FB -#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC -#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD -#endif /* GL_ATI_meminfo */ - -#ifndef GL_ATI_pixel_format_float -#define GL_ATI_pixel_format_float 1 -#define GL_RGBA_FLOAT_MODE_ATI 0x8820 -#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 -#endif /* GL_ATI_pixel_format_float */ - -#ifndef GL_ATI_pn_triangles -#define GL_ATI_pn_triangles 1 -#define GL_PN_TRIANGLES_ATI 0x87F0 -#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 -#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 -#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 -#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 -#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 -#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 -#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 -#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 -typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); -GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); -#endif -#endif /* GL_ATI_pn_triangles */ - -#ifndef GL_ATI_separate_stencil -#define GL_ATI_separate_stencil 1 -#define GL_STENCIL_BACK_FUNC_ATI 0x8800 -#define GL_STENCIL_BACK_FAIL_ATI 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); -#endif -#endif /* GL_ATI_separate_stencil */ - -#ifndef GL_ATI_text_fragment_shader -#define GL_ATI_text_fragment_shader 1 -#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 -#endif /* GL_ATI_text_fragment_shader */ - -#ifndef GL_ATI_texture_env_combine3 -#define GL_ATI_texture_env_combine3 1 -#define GL_MODULATE_ADD_ATI 0x8744 -#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 -#define GL_MODULATE_SUBTRACT_ATI 0x8746 -#endif /* GL_ATI_texture_env_combine3 */ - -#ifndef GL_ATI_texture_float -#define GL_ATI_texture_float 1 -#define GL_RGBA_FLOAT32_ATI 0x8814 -#define GL_RGB_FLOAT32_ATI 0x8815 -#define GL_ALPHA_FLOAT32_ATI 0x8816 -#define GL_INTENSITY_FLOAT32_ATI 0x8817 -#define GL_LUMINANCE_FLOAT32_ATI 0x8818 -#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 -#define GL_RGBA_FLOAT16_ATI 0x881A -#define GL_RGB_FLOAT16_ATI 0x881B -#define GL_ALPHA_FLOAT16_ATI 0x881C -#define GL_INTENSITY_FLOAT16_ATI 0x881D -#define GL_LUMINANCE_FLOAT16_ATI 0x881E -#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F -#endif /* GL_ATI_texture_float */ - -#ifndef GL_ATI_texture_mirror_once -#define GL_ATI_texture_mirror_once 1 -#define GL_MIRROR_CLAMP_ATI 0x8742 -#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 -#endif /* GL_ATI_texture_mirror_once */ - -#ifndef GL_ATI_vertex_array_object -#define GL_ATI_vertex_array_object 1 -#define GL_STATIC_ATI 0x8760 -#define GL_DYNAMIC_ATI 0x8761 -#define GL_PRESERVE_ATI 0x8762 -#define GL_DISCARD_ATI 0x8763 -#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 -#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 -#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 -#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 -typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage); -typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); -typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage); -GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); -GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); -GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); -#endif -#endif /* GL_ATI_vertex_array_object */ - -#ifndef GL_ATI_vertex_attrib_array_object -#define GL_ATI_vertex_attrib_array_object 1 -typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); -#endif -#endif /* GL_ATI_vertex_attrib_array_object */ - -#ifndef GL_ATI_vertex_streams -#define GL_ATI_vertex_streams 1 -#define GL_MAX_VERTEX_STREAMS_ATI 0x876B -#define GL_VERTEX_STREAM0_ATI 0x876C -#define GL_VERTEX_STREAM1_ATI 0x876D -#define GL_VERTEX_STREAM2_ATI 0x876E -#define GL_VERTEX_STREAM3_ATI 0x876F -#define GL_VERTEX_STREAM4_ATI 0x8770 -#define GL_VERTEX_STREAM5_ATI 0x8771 -#define GL_VERTEX_STREAM6_ATI 0x8772 -#define GL_VERTEX_STREAM7_ATI 0x8773 -#define GL_VERTEX_SOURCE_ATI 0x8774 -typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); -typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); -GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); -GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); -GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); -GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); -GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); -GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); -GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); -GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); -GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); -GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); -GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); -GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); -GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); -#endif -#endif /* GL_ATI_vertex_streams */ - -#ifndef GL_EXT_422_pixels -#define GL_EXT_422_pixels 1 -#define GL_422_EXT 0x80CC -#define GL_422_REV_EXT 0x80CD -#define GL_422_AVERAGE_EXT 0x80CE -#define GL_422_REV_AVERAGE_EXT 0x80CF -#endif /* GL_EXT_422_pixels */ - -#ifndef GL_EXT_abgr -#define GL_EXT_abgr 1 -#define GL_ABGR_EXT 0x8000 -#endif /* GL_EXT_abgr */ - -#ifndef GL_EXT_bgra -#define GL_EXT_bgra 1 -#define GL_BGR_EXT 0x80E0 -#define GL_BGRA_EXT 0x80E1 -#endif /* GL_EXT_bgra */ - -#ifndef GL_EXT_bindable_uniform -#define GL_EXT_bindable_uniform 1 -#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 -#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 -#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 -#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED -#define GL_UNIFORM_BUFFER_EXT 0x8DEE -#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF -typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); -typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); -typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); -GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); -GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); -#endif -#endif /* GL_EXT_bindable_uniform */ - -#ifndef GL_EXT_blend_color -#define GL_EXT_blend_color 1 -#define GL_CONSTANT_COLOR_EXT 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 -#define GL_CONSTANT_ALPHA_EXT 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 -#define GL_BLEND_COLOR_EXT 0x8005 -typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -#endif -#endif /* GL_EXT_blend_color */ - -#ifndef GL_EXT_blend_equation_separate -#define GL_EXT_blend_equation_separate 1 -#define GL_BLEND_EQUATION_RGB_EXT 0x8009 -#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); -#endif -#endif /* GL_EXT_blend_equation_separate */ - -#ifndef GL_EXT_blend_func_separate -#define GL_EXT_blend_func_separate 1 -#define GL_BLEND_DST_RGB_EXT 0x80C8 -#define GL_BLEND_SRC_RGB_EXT 0x80C9 -#define GL_BLEND_DST_ALPHA_EXT 0x80CA -#define GL_BLEND_SRC_ALPHA_EXT 0x80CB -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif -#endif /* GL_EXT_blend_func_separate */ - -#ifndef GL_EXT_blend_logic_op -#define GL_EXT_blend_logic_op 1 -#endif /* GL_EXT_blend_logic_op */ - -#ifndef GL_EXT_blend_minmax -#define GL_EXT_blend_minmax 1 -#define GL_MIN_EXT 0x8007 -#define GL_MAX_EXT 0x8008 -#define GL_FUNC_ADD_EXT 0x8006 -#define GL_BLEND_EQUATION_EXT 0x8009 -typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); -#endif -#endif /* GL_EXT_blend_minmax */ - -#ifndef GL_EXT_blend_subtract -#define GL_EXT_blend_subtract 1 -#define GL_FUNC_SUBTRACT_EXT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B -#endif /* GL_EXT_blend_subtract */ - -#ifndef GL_EXT_clip_volume_hint -#define GL_EXT_clip_volume_hint 1 -#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 -#endif /* GL_EXT_clip_volume_hint */ - -#ifndef GL_EXT_cmyka -#define GL_EXT_cmyka 1 -#define GL_CMYK_EXT 0x800C -#define GL_CMYKA_EXT 0x800D -#define GL_PACK_CMYK_HINT_EXT 0x800E -#define GL_UNPACK_CMYK_HINT_EXT 0x800F -#endif /* GL_EXT_cmyka */ - -#ifndef GL_EXT_color_subtable -#define GL_EXT_color_subtable 1 -typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -#endif -#endif /* GL_EXT_color_subtable */ - -#ifndef GL_EXT_compiled_vertex_array -#define GL_EXT_compiled_vertex_array 1 -#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 -#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 -typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); -GLAPI void APIENTRY glUnlockArraysEXT (void); -#endif -#endif /* GL_EXT_compiled_vertex_array */ - -#ifndef GL_EXT_convolution -#define GL_EXT_convolution 1 -#define GL_CONVOLUTION_1D_EXT 0x8010 -#define GL_CONVOLUTION_2D_EXT 0x8011 -#define GL_SEPARABLE_2D_EXT 0x8012 -#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 -#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 -#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 -#define GL_REDUCE_EXT 0x8016 -#define GL_CONVOLUTION_FORMAT_EXT 0x8017 -#define GL_CONVOLUTION_WIDTH_EXT 0x8018 -#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 -#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A -#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B -#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C -#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D -#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E -#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F -#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 -#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 -#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 -#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); -GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); -GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); -GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); -GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image); -GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); -GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); -#endif -#endif /* GL_EXT_convolution */ - -#ifndef GL_EXT_coordinate_frame -#define GL_EXT_coordinate_frame 1 -#define GL_TANGENT_ARRAY_EXT 0x8439 -#define GL_BINORMAL_ARRAY_EXT 0x843A -#define GL_CURRENT_TANGENT_EXT 0x843B -#define GL_CURRENT_BINORMAL_EXT 0x843C -#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E -#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F -#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 -#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 -#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 -#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 -#define GL_MAP1_TANGENT_EXT 0x8444 -#define GL_MAP2_TANGENT_EXT 0x8445 -#define GL_MAP1_BINORMAL_EXT 0x8446 -#define GL_MAP2_BINORMAL_EXT 0x8447 -typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); -typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); -typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); -typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); -typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); -typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); -typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); -typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); -typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); -typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); -typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); -GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); -GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); -GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); -GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); -GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); -GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); -GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); -GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); -GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); -GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); -GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); -GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); -GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); -GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer); -#endif -#endif /* GL_EXT_coordinate_frame */ - -#ifndef GL_EXT_copy_texture -#define GL_EXT_copy_texture 1 -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif -#endif /* GL_EXT_copy_texture */ - -#ifndef GL_EXT_cull_vertex -#define GL_EXT_cull_vertex 1 -#define GL_CULL_VERTEX_EXT 0x81AA -#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB -#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC -typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); -GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); -#endif -#endif /* GL_EXT_cull_vertex */ - -#ifndef GL_EXT_debug_label -#define GL_EXT_debug_label 1 -#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F -#define GL_PROGRAM_OBJECT_EXT 0x8B40 -#define GL_SHADER_OBJECT_EXT 0x8B48 -#define GL_BUFFER_OBJECT_EXT 0x9151 -#define GL_QUERY_OBJECT_EXT 0x9153 -#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 -typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); -typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); -GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); -#endif -#endif /* GL_EXT_debug_label */ - -#ifndef GL_EXT_debug_marker -#define GL_EXT_debug_marker 1 -typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); -typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); -typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); -GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); -GLAPI void APIENTRY glPopGroupMarkerEXT (void); -#endif -#endif /* GL_EXT_debug_marker */ - -#ifndef GL_EXT_depth_bounds_test -#define GL_EXT_depth_bounds_test 1 -#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 -#define GL_DEPTH_BOUNDS_EXT 0x8891 -typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); -#endif -#endif /* GL_EXT_depth_bounds_test */ - -#ifndef GL_EXT_direct_state_access -#define GL_EXT_direct_state_access 1 -#define GL_PROGRAM_MATRIX_EXT 0x8E2D -#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E -#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F -typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); -typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data); -typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); -typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); -typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); -typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param); -typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); -GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); -GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); -GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); -GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); -GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data); -GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); -GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); -GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img); -GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img); -GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); -GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); -GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params); -GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params); -GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); -GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string); -GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); -GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); -GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); -GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array); -GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); -GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); -GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); -GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param); -GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param); -GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); -GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); -GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); -GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); -GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor); -#endif -#endif /* GL_EXT_direct_state_access */ - -#ifndef GL_EXT_draw_buffers2 -#define GL_EXT_draw_buffers2 1 -typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -#endif -#endif /* GL_EXT_draw_buffers2 */ - -#ifndef GL_EXT_draw_instanced -#define GL_EXT_draw_instanced 1 -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); -#endif -#endif /* GL_EXT_draw_instanced */ - -#ifndef GL_EXT_draw_range_elements -#define GL_EXT_draw_range_elements 1 -#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 -#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -#endif -#endif /* GL_EXT_draw_range_elements */ - -#ifndef GL_EXT_fog_coord -#define GL_EXT_fog_coord 1 -#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 -#define GL_FOG_COORDINATE_EXT 0x8451 -#define GL_FRAGMENT_DEPTH_EXT 0x8452 -#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 -#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 -typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); -typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); -typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); -GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); -GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); -GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer); -#endif -#endif /* GL_EXT_fog_coord */ - -#ifndef GL_EXT_framebuffer_blit -#define GL_EXT_framebuffer_blit 1 -#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif -#endif /* GL_EXT_framebuffer_blit */ - -#ifndef GL_EXT_framebuffer_multisample -#define GL_EXT_framebuffer_multisample 1 -#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 -#define GL_MAX_SAMPLES_EXT 0x8D57 -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#endif -#endif /* GL_EXT_framebuffer_multisample */ - -#ifndef GL_EXT_framebuffer_multisample_blit_scaled -#define GL_EXT_framebuffer_multisample_blit_scaled 1 -#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA -#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB -#endif /* GL_EXT_framebuffer_multisample_blit_scaled */ - -#ifndef GL_EXT_framebuffer_object -#define GL_EXT_framebuffer_object 1 -#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 -#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 -#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 -#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF -#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 -#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 -#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 -#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 -#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 -#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 -#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 -#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 -#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 -#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 -#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA -#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB -#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC -#define GL_COLOR_ATTACHMENT13_EXT 0x8CED -#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE -#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF -#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 -#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 -#define GL_FRAMEBUFFER_EXT 0x8D40 -#define GL_RENDERBUFFER_EXT 0x8D41 -#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 -#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 -#define GL_STENCIL_INDEX1_EXT 0x8D46 -#define GL_STENCIL_INDEX4_EXT 0x8D47 -#define GL_STENCIL_INDEX8_EXT 0x8D48 -#define GL_STENCIL_INDEX16_EXT 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); -#endif -#endif /* GL_EXT_framebuffer_object */ - -#ifndef GL_EXT_framebuffer_sRGB -#define GL_EXT_framebuffer_sRGB 1 -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 -#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA -#endif /* GL_EXT_framebuffer_sRGB */ - -#ifndef GL_EXT_geometry_shader4 -#define GL_EXT_geometry_shader4 1 -#define GL_GEOMETRY_SHADER_EXT 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD -#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE -#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 -#define GL_LINES_ADJACENCY_EXT 0x000A -#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B -#define GL_TRIANGLES_ADJACENCY_EXT 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 -#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); -#endif -#endif /* GL_EXT_geometry_shader4 */ - -#ifndef GL_EXT_gpu_program_parameters -#define GL_EXT_gpu_program_parameters 1 -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -#endif -#endif /* GL_EXT_gpu_program_parameters */ - -#ifndef GL_EXT_gpu_shader4 -#define GL_EXT_gpu_shader4 1 -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD -#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 -#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 -#define GL_SAMPLER_BUFFER_EXT 0x8DC2 -#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 -#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 -#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 -#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 -#define GL_INT_SAMPLER_1D_EXT 0x8DC9 -#define GL_INT_SAMPLER_2D_EXT 0x8DCA -#define GL_INT_SAMPLER_3D_EXT 0x8DCB -#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC -#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD -#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF -#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 -#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 -typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); -#endif -#endif /* GL_EXT_gpu_shader4 */ - -#ifndef GL_EXT_histogram -#define GL_EXT_histogram 1 -#define GL_HISTOGRAM_EXT 0x8024 -#define GL_PROXY_HISTOGRAM_EXT 0x8025 -#define GL_HISTOGRAM_WIDTH_EXT 0x8026 -#define GL_HISTOGRAM_FORMAT_EXT 0x8027 -#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 -#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 -#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A -#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B -#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C -#define GL_HISTOGRAM_SINK_EXT 0x802D -#define GL_MINMAX_EXT 0x802E -#define GL_MINMAX_FORMAT_EXT 0x802F -#define GL_MINMAX_SINK_EXT 0x8030 -#define GL_TABLE_TOO_LARGE_EXT 0x8031 -typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); -GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glResetHistogramEXT (GLenum target); -GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); -#endif -#endif /* GL_EXT_histogram */ - -#ifndef GL_EXT_index_array_formats -#define GL_EXT_index_array_formats 1 -#define GL_IUI_V2F_EXT 0x81AD -#define GL_IUI_V3F_EXT 0x81AE -#define GL_IUI_N3F_V2F_EXT 0x81AF -#define GL_IUI_N3F_V3F_EXT 0x81B0 -#define GL_T2F_IUI_V2F_EXT 0x81B1 -#define GL_T2F_IUI_V3F_EXT 0x81B2 -#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 -#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 -#endif /* GL_EXT_index_array_formats */ - -#ifndef GL_EXT_index_func -#define GL_EXT_index_func 1 -#define GL_INDEX_TEST_EXT 0x81B5 -#define GL_INDEX_TEST_FUNC_EXT 0x81B6 -#define GL_INDEX_TEST_REF_EXT 0x81B7 -typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); -#endif -#endif /* GL_EXT_index_func */ - -#ifndef GL_EXT_index_material -#define GL_EXT_index_material 1 -#define GL_INDEX_MATERIAL_EXT 0x81B8 -#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 -#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA -typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); -#endif -#endif /* GL_EXT_index_material */ - -#ifndef GL_EXT_index_texture -#define GL_EXT_index_texture 1 -#endif /* GL_EXT_index_texture */ - -#ifndef GL_EXT_light_texture -#define GL_EXT_light_texture 1 -#define GL_FRAGMENT_MATERIAL_EXT 0x8349 -#define GL_FRAGMENT_NORMAL_EXT 0x834A -#define GL_FRAGMENT_COLOR_EXT 0x834C -#define GL_ATTENUATION_EXT 0x834D -#define GL_SHADOW_ATTENUATION_EXT 0x834E -#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F -#define GL_TEXTURE_LIGHT_EXT 0x8350 -#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 -#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 -typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); -GLAPI void APIENTRY glTextureLightEXT (GLenum pname); -GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); -#endif -#endif /* GL_EXT_light_texture */ - -#ifndef GL_EXT_misc_attribute -#define GL_EXT_misc_attribute 1 -#endif /* GL_EXT_misc_attribute */ - -#ifndef GL_EXT_multi_draw_arrays -#define GL_EXT_multi_draw_arrays 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); -#endif -#endif /* GL_EXT_multi_draw_arrays */ - -#ifndef GL_EXT_multisample -#define GL_EXT_multisample 1 -#define GL_MULTISAMPLE_EXT 0x809D -#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F -#define GL_SAMPLE_MASK_EXT 0x80A0 -#define GL_1PASS_EXT 0x80A1 -#define GL_2PASS_0_EXT 0x80A2 -#define GL_2PASS_1_EXT 0x80A3 -#define GL_4PASS_0_EXT 0x80A4 -#define GL_4PASS_1_EXT 0x80A5 -#define GL_4PASS_2_EXT 0x80A6 -#define GL_4PASS_3_EXT 0x80A7 -#define GL_SAMPLE_BUFFERS_EXT 0x80A8 -#define GL_SAMPLES_EXT 0x80A9 -#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA -#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB -#define GL_SAMPLE_PATTERN_EXT 0x80AC -#define GL_MULTISAMPLE_BIT_EXT 0x20000000 -typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); -#endif -#endif /* GL_EXT_multisample */ - -#ifndef GL_EXT_packed_depth_stencil -#define GL_EXT_packed_depth_stencil 1 -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif /* GL_EXT_packed_depth_stencil */ - -#ifndef GL_EXT_packed_float -#define GL_EXT_packed_float 1 -#define GL_R11F_G11F_B10F_EXT 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B -#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C -#endif /* GL_EXT_packed_float */ - -#ifndef GL_EXT_packed_pixels -#define GL_EXT_packed_pixels 1 -#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 -#endif /* GL_EXT_packed_pixels */ - -#ifndef GL_EXT_paletted_texture -#define GL_EXT_paletted_texture 1 -#define GL_COLOR_INDEX1_EXT 0x80E2 -#define GL_COLOR_INDEX2_EXT 0x80E3 -#define GL_COLOR_INDEX4_EXT 0x80E4 -#define GL_COLOR_INDEX8_EXT 0x80E5 -#define GL_COLOR_INDEX12_EXT 0x80E6 -#define GL_COLOR_INDEX16_EXT 0x80E7 -#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED -typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); -GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data); -GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -#endif -#endif /* GL_EXT_paletted_texture */ - -#ifndef GL_EXT_pixel_buffer_object -#define GL_EXT_pixel_buffer_object 1 -#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF -#endif /* GL_EXT_pixel_buffer_object */ - -#ifndef GL_EXT_pixel_transform -#define GL_EXT_pixel_transform 1 -#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 -#define GL_PIXEL_MAG_FILTER_EXT 0x8331 -#define GL_PIXEL_MIN_FILTER_EXT 0x8332 -#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 -#define GL_CUBIC_EXT 0x8334 -#define GL_AVERAGE_EXT 0x8335 -#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 -#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 -#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -#endif -#endif /* GL_EXT_pixel_transform */ - -#ifndef GL_EXT_pixel_transform_color_table -#define GL_EXT_pixel_transform_color_table 1 -#endif /* GL_EXT_pixel_transform_color_table */ - -#ifndef GL_EXT_point_parameters -#define GL_EXT_point_parameters 1 -#define GL_POINT_SIZE_MIN_EXT 0x8126 -#define GL_POINT_SIZE_MAX_EXT 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 -#define GL_DISTANCE_ATTENUATION_EXT 0x8129 -typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); -#endif -#endif /* GL_EXT_point_parameters */ - -#ifndef GL_EXT_polygon_offset -#define GL_EXT_polygon_offset 1 -#define GL_POLYGON_OFFSET_EXT 0x8037 -#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 -#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 -typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); -#endif -#endif /* GL_EXT_polygon_offset */ - -#ifndef GL_EXT_provoking_vertex -#define GL_EXT_provoking_vertex 1 -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D -#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E -#define GL_PROVOKING_VERTEX_EXT 0x8E4F -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); -#endif -#endif /* GL_EXT_provoking_vertex */ - -#ifndef GL_EXT_rescale_normal -#define GL_EXT_rescale_normal 1 -#define GL_RESCALE_NORMAL_EXT 0x803A -#endif /* GL_EXT_rescale_normal */ - -#ifndef GL_EXT_secondary_color -#define GL_EXT_secondary_color 1 -#define GL_COLOR_SUM_EXT 0x8458 -#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D -#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); -GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); -GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); -GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); -GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); -GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); -GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); -GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); -GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); -GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); -GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); -GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); -GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); -#endif -#endif /* GL_EXT_secondary_color */ - -#ifndef GL_EXT_separate_shader_objects -#define GL_EXT_separate_shader_objects 1 -#define GL_ACTIVE_PROGRAM_EXT 0x8B8D -typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); -typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); -GLAPI void APIENTRY glActiveProgramEXT (GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); -#endif -#endif /* GL_EXT_separate_shader_objects */ - -#ifndef GL_EXT_separate_specular_color -#define GL_EXT_separate_specular_color 1 -#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 -#define GL_SINGLE_COLOR_EXT 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA -#endif /* GL_EXT_separate_specular_color */ - -#ifndef GL_EXT_shader_image_load_store -#define GL_EXT_shader_image_load_store 1 -#define GL_MAX_IMAGE_UNITS_EXT 0x8F38 -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 -#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A -#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B -#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C -#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D -#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E -#define GL_IMAGE_1D_EXT 0x904C -#define GL_IMAGE_2D_EXT 0x904D -#define GL_IMAGE_3D_EXT 0x904E -#define GL_IMAGE_2D_RECT_EXT 0x904F -#define GL_IMAGE_CUBE_EXT 0x9050 -#define GL_IMAGE_BUFFER_EXT 0x9051 -#define GL_IMAGE_1D_ARRAY_EXT 0x9052 -#define GL_IMAGE_2D_ARRAY_EXT 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 -#define GL_INT_IMAGE_1D_EXT 0x9057 -#define GL_INT_IMAGE_2D_EXT 0x9058 -#define GL_INT_IMAGE_3D_EXT 0x9059 -#define GL_INT_IMAGE_2D_RECT_EXT 0x905A -#define GL_INT_IMAGE_CUBE_EXT 0x905B -#define GL_INT_IMAGE_BUFFER_EXT 0x905C -#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D -#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C -#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D -#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 -#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 -#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); -typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); -GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); -#endif -#endif /* GL_EXT_shader_image_load_store */ - -#ifndef GL_EXT_shader_integer_mix -#define GL_EXT_shader_integer_mix 1 -#endif /* GL_EXT_shader_integer_mix */ - -#ifndef GL_EXT_shadow_funcs -#define GL_EXT_shadow_funcs 1 -#endif /* GL_EXT_shadow_funcs */ - -#ifndef GL_EXT_shared_texture_palette -#define GL_EXT_shared_texture_palette 1 -#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB -#endif /* GL_EXT_shared_texture_palette */ - -#ifndef GL_EXT_stencil_clear_tag -#define GL_EXT_stencil_clear_tag 1 -#define GL_STENCIL_TAG_BITS_EXT 0x88F2 -#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 -typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); -#endif -#endif /* GL_EXT_stencil_clear_tag */ - -#ifndef GL_EXT_stencil_two_side -#define GL_EXT_stencil_two_side 1 -#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 -#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 -typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); -#endif -#endif /* GL_EXT_stencil_two_side */ - -#ifndef GL_EXT_stencil_wrap -#define GL_EXT_stencil_wrap 1 -#define GL_INCR_WRAP_EXT 0x8507 -#define GL_DECR_WRAP_EXT 0x8508 -#endif /* GL_EXT_stencil_wrap */ - -#ifndef GL_EXT_subtexture -#define GL_EXT_subtexture 1 -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -#endif -#endif /* GL_EXT_subtexture */ - -#ifndef GL_EXT_texture -#define GL_EXT_texture 1 -#define GL_ALPHA4_EXT 0x803B -#define GL_ALPHA8_EXT 0x803C -#define GL_ALPHA12_EXT 0x803D -#define GL_ALPHA16_EXT 0x803E -#define GL_LUMINANCE4_EXT 0x803F -#define GL_LUMINANCE8_EXT 0x8040 -#define GL_LUMINANCE12_EXT 0x8041 -#define GL_LUMINANCE16_EXT 0x8042 -#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 -#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 -#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 -#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 -#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 -#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 -#define GL_INTENSITY_EXT 0x8049 -#define GL_INTENSITY4_EXT 0x804A -#define GL_INTENSITY8_EXT 0x804B -#define GL_INTENSITY12_EXT 0x804C -#define GL_INTENSITY16_EXT 0x804D -#define GL_RGB2_EXT 0x804E -#define GL_RGB4_EXT 0x804F -#define GL_RGB5_EXT 0x8050 -#define GL_RGB8_EXT 0x8051 -#define GL_RGB10_EXT 0x8052 -#define GL_RGB12_EXT 0x8053 -#define GL_RGB16_EXT 0x8054 -#define GL_RGBA2_EXT 0x8055 -#define GL_RGBA4_EXT 0x8056 -#define GL_RGB5_A1_EXT 0x8057 -#define GL_RGBA8_EXT 0x8058 -#define GL_RGB10_A2_EXT 0x8059 -#define GL_RGBA12_EXT 0x805A -#define GL_RGBA16_EXT 0x805B -#define GL_TEXTURE_RED_SIZE_EXT 0x805C -#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D -#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E -#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F -#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 -#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 -#define GL_REPLACE_EXT 0x8062 -#define GL_PROXY_TEXTURE_1D_EXT 0x8063 -#define GL_PROXY_TEXTURE_2D_EXT 0x8064 -#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 -#endif /* GL_EXT_texture */ - -#ifndef GL_EXT_texture3D -#define GL_EXT_texture3D 1 -#define GL_PACK_SKIP_IMAGES_EXT 0x806B -#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C -#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D -#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E -#define GL_TEXTURE_3D_EXT 0x806F -#define GL_PROXY_TEXTURE_3D_EXT 0x8070 -#define GL_TEXTURE_DEPTH_EXT 0x8071 -#define GL_TEXTURE_WRAP_R_EXT 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 -typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -#endif -#endif /* GL_EXT_texture3D */ - -#ifndef GL_EXT_texture_array -#define GL_EXT_texture_array 1 -#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 -#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D -#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF -#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E -#endif /* GL_EXT_texture_array */ - -#ifndef GL_EXT_texture_buffer_object -#define GL_EXT_texture_buffer_object 1 -#define GL_TEXTURE_BUFFER_EXT 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E -typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); -#endif -#endif /* GL_EXT_texture_buffer_object */ - -#ifndef GL_EXT_texture_compression_latc -#define GL_EXT_texture_compression_latc 1 -#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 -#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 -#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 -#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 -#endif /* GL_EXT_texture_compression_latc */ - -#ifndef GL_EXT_texture_compression_rgtc -#define GL_EXT_texture_compression_rgtc 1 -#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#endif /* GL_EXT_texture_compression_rgtc */ - -#ifndef GL_EXT_texture_compression_s3tc -#define GL_EXT_texture_compression_s3tc 1 -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#endif /* GL_EXT_texture_compression_s3tc */ - -#ifndef GL_EXT_texture_cube_map -#define GL_EXT_texture_cube_map 1 -#define GL_NORMAL_MAP_EXT 0x8511 -#define GL_REFLECTION_MAP_EXT 0x8512 -#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C -#endif /* GL_EXT_texture_cube_map */ - -#ifndef GL_EXT_texture_env_add -#define GL_EXT_texture_env_add 1 -#endif /* GL_EXT_texture_env_add */ - -#ifndef GL_EXT_texture_env_combine -#define GL_EXT_texture_env_combine 1 -#define GL_COMBINE_EXT 0x8570 -#define GL_COMBINE_RGB_EXT 0x8571 -#define GL_COMBINE_ALPHA_EXT 0x8572 -#define GL_RGB_SCALE_EXT 0x8573 -#define GL_ADD_SIGNED_EXT 0x8574 -#define GL_INTERPOLATE_EXT 0x8575 -#define GL_CONSTANT_EXT 0x8576 -#define GL_PRIMARY_COLOR_EXT 0x8577 -#define GL_PREVIOUS_EXT 0x8578 -#define GL_SOURCE0_RGB_EXT 0x8580 -#define GL_SOURCE1_RGB_EXT 0x8581 -#define GL_SOURCE2_RGB_EXT 0x8582 -#define GL_SOURCE0_ALPHA_EXT 0x8588 -#define GL_SOURCE1_ALPHA_EXT 0x8589 -#define GL_SOURCE2_ALPHA_EXT 0x858A -#define GL_OPERAND0_RGB_EXT 0x8590 -#define GL_OPERAND1_RGB_EXT 0x8591 -#define GL_OPERAND2_RGB_EXT 0x8592 -#define GL_OPERAND0_ALPHA_EXT 0x8598 -#define GL_OPERAND1_ALPHA_EXT 0x8599 -#define GL_OPERAND2_ALPHA_EXT 0x859A -#endif /* GL_EXT_texture_env_combine */ - -#ifndef GL_EXT_texture_env_dot3 -#define GL_EXT_texture_env_dot3 1 -#define GL_DOT3_RGB_EXT 0x8740 -#define GL_DOT3_RGBA_EXT 0x8741 -#endif /* GL_EXT_texture_env_dot3 */ - -#ifndef GL_EXT_texture_filter_anisotropic -#define GL_EXT_texture_filter_anisotropic 1 -#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#endif /* GL_EXT_texture_filter_anisotropic */ - -#ifndef GL_EXT_texture_integer -#define GL_EXT_texture_integer 1 -#define GL_RGBA32UI_EXT 0x8D70 -#define GL_RGB32UI_EXT 0x8D71 -#define GL_ALPHA32UI_EXT 0x8D72 -#define GL_INTENSITY32UI_EXT 0x8D73 -#define GL_LUMINANCE32UI_EXT 0x8D74 -#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 -#define GL_RGBA16UI_EXT 0x8D76 -#define GL_RGB16UI_EXT 0x8D77 -#define GL_ALPHA16UI_EXT 0x8D78 -#define GL_INTENSITY16UI_EXT 0x8D79 -#define GL_LUMINANCE16UI_EXT 0x8D7A -#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B -#define GL_RGBA8UI_EXT 0x8D7C -#define GL_RGB8UI_EXT 0x8D7D -#define GL_ALPHA8UI_EXT 0x8D7E -#define GL_INTENSITY8UI_EXT 0x8D7F -#define GL_LUMINANCE8UI_EXT 0x8D80 -#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 -#define GL_RGBA32I_EXT 0x8D82 -#define GL_RGB32I_EXT 0x8D83 -#define GL_ALPHA32I_EXT 0x8D84 -#define GL_INTENSITY32I_EXT 0x8D85 -#define GL_LUMINANCE32I_EXT 0x8D86 -#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 -#define GL_RGBA16I_EXT 0x8D88 -#define GL_RGB16I_EXT 0x8D89 -#define GL_ALPHA16I_EXT 0x8D8A -#define GL_INTENSITY16I_EXT 0x8D8B -#define GL_LUMINANCE16I_EXT 0x8D8C -#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D -#define GL_RGBA8I_EXT 0x8D8E -#define GL_RGB8I_EXT 0x8D8F -#define GL_ALPHA8I_EXT 0x8D90 -#define GL_INTENSITY8I_EXT 0x8D91 -#define GL_LUMINANCE8I_EXT 0x8D92 -#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 -#define GL_RED_INTEGER_EXT 0x8D94 -#define GL_GREEN_INTEGER_EXT 0x8D95 -#define GL_BLUE_INTEGER_EXT 0x8D96 -#define GL_ALPHA_INTEGER_EXT 0x8D97 -#define GL_RGB_INTEGER_EXT 0x8D98 -#define GL_RGBA_INTEGER_EXT 0x8D99 -#define GL_BGR_INTEGER_EXT 0x8D9A -#define GL_BGRA_INTEGER_EXT 0x8D9B -#define GL_LUMINANCE_INTEGER_EXT 0x8D9C -#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D -#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); -typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); -GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); -#endif -#endif /* GL_EXT_texture_integer */ - -#ifndef GL_EXT_texture_lod_bias -#define GL_EXT_texture_lod_bias 1 -#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD -#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 -#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 -#endif /* GL_EXT_texture_lod_bias */ - -#ifndef GL_EXT_texture_mirror_clamp -#define GL_EXT_texture_mirror_clamp 1 -#define GL_MIRROR_CLAMP_EXT 0x8742 -#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 -#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 -#endif /* GL_EXT_texture_mirror_clamp */ - -#ifndef GL_EXT_texture_object -#define GL_EXT_texture_object 1 -#define GL_TEXTURE_PRIORITY_EXT 0x8066 -#define GL_TEXTURE_RESIDENT_EXT 0x8067 -#define GL_TEXTURE_1D_BINDING_EXT 0x8068 -#define GL_TEXTURE_2D_BINDING_EXT 0x8069 -#define GL_TEXTURE_3D_BINDING_EXT 0x806A -typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); -typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); -typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); -typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); -GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); -GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); -GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); -GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); -GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); -#endif -#endif /* GL_EXT_texture_object */ - -#ifndef GL_EXT_texture_perturb_normal -#define GL_EXT_texture_perturb_normal 1 -#define GL_PERTURB_EXT 0x85AE -#define GL_TEXTURE_NORMAL_EXT 0x85AF -typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); -#endif -#endif /* GL_EXT_texture_perturb_normal */ - -#ifndef GL_EXT_texture_sRGB -#define GL_EXT_texture_sRGB 1 -#define GL_SRGB_EXT 0x8C40 -#define GL_SRGB8_EXT 0x8C41 -#define GL_SRGB_ALPHA_EXT 0x8C42 -#define GL_SRGB8_ALPHA8_EXT 0x8C43 -#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 -#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 -#define GL_SLUMINANCE_EXT 0x8C46 -#define GL_SLUMINANCE8_EXT 0x8C47 -#define GL_COMPRESSED_SRGB_EXT 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 -#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B -#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F -#endif /* GL_EXT_texture_sRGB */ - -#ifndef GL_EXT_texture_sRGB_decode -#define GL_EXT_texture_sRGB_decode 1 -#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define GL_DECODE_EXT 0x8A49 -#define GL_SKIP_DECODE_EXT 0x8A4A -#endif /* GL_EXT_texture_sRGB_decode */ - -#ifndef GL_EXT_texture_shared_exponent -#define GL_EXT_texture_shared_exponent 1 -#define GL_RGB9_E5_EXT 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E -#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F -#endif /* GL_EXT_texture_shared_exponent */ - -#ifndef GL_EXT_texture_snorm -#define GL_EXT_texture_snorm 1 -#define GL_ALPHA_SNORM 0x9010 -#define GL_LUMINANCE_SNORM 0x9011 -#define GL_LUMINANCE_ALPHA_SNORM 0x9012 -#define GL_INTENSITY_SNORM 0x9013 -#define GL_ALPHA8_SNORM 0x9014 -#define GL_LUMINANCE8_SNORM 0x9015 -#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 -#define GL_INTENSITY8_SNORM 0x9017 -#define GL_ALPHA16_SNORM 0x9018 -#define GL_LUMINANCE16_SNORM 0x9019 -#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A -#define GL_INTENSITY16_SNORM 0x901B -#define GL_RED_SNORM 0x8F90 -#define GL_RG_SNORM 0x8F91 -#define GL_RGB_SNORM 0x8F92 -#define GL_RGBA_SNORM 0x8F93 -#endif /* GL_EXT_texture_snorm */ - -#ifndef GL_EXT_texture_swizzle -#define GL_EXT_texture_swizzle 1 -#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 -#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 -#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 -#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 -#endif /* GL_EXT_texture_swizzle */ - -#ifndef GL_EXT_timer_query -#define GL_EXT_timer_query 1 -#define GL_TIME_ELAPSED_EXT 0x88BF -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params); -#endif -#endif /* GL_EXT_timer_query */ - -#ifndef GL_EXT_transform_feedback -#define GL_EXT_transform_feedback 1 -#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F -#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C -#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D -#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 -#define GL_RASTERIZER_DISCARD_EXT 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedbackEXT (void); -GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -#endif -#endif /* GL_EXT_transform_feedback */ - -#ifndef GL_EXT_vertex_array -#define GL_EXT_vertex_array 1 -#define GL_VERTEX_ARRAY_EXT 0x8074 -#define GL_NORMAL_ARRAY_EXT 0x8075 -#define GL_COLOR_ARRAY_EXT 0x8076 -#define GL_INDEX_ARRAY_EXT 0x8077 -#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 -#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 -#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A -#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B -#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C -#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D -#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E -#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F -#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 -#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 -#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 -#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 -#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 -#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 -#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 -#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 -#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 -#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 -#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A -#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B -#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C -#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D -#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E -#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F -#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 -#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 -#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 -#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 -typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); -typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); -typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); -typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params); -typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); -typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glArrayElementEXT (GLint i); -GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); -GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); -GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params); -GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); -GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); -GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); -GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); -#endif -#endif /* GL_EXT_vertex_array */ - -#ifndef GL_EXT_vertex_array_bgra -#define GL_EXT_vertex_array_bgra 1 -#endif /* GL_EXT_vertex_array_bgra */ - -#ifndef GL_EXT_vertex_attrib_64bit -#define GL_EXT_vertex_attrib_64bit 1 -#define GL_DOUBLE_VEC2_EXT 0x8FFC -#define GL_DOUBLE_VEC3_EXT 0x8FFD -#define GL_DOUBLE_VEC4_EXT 0x8FFE -#define GL_DOUBLE_MAT2_EXT 0x8F46 -#define GL_DOUBLE_MAT3_EXT 0x8F47 -#define GL_DOUBLE_MAT4_EXT 0x8F48 -#define GL_DOUBLE_MAT2x3_EXT 0x8F49 -#define GL_DOUBLE_MAT2x4_EXT 0x8F4A -#define GL_DOUBLE_MAT3x2_EXT 0x8F4B -#define GL_DOUBLE_MAT3x4_EXT 0x8F4C -#define GL_DOUBLE_MAT4x2_EXT 0x8F4D -#define GL_DOUBLE_MAT4x3_EXT 0x8F4E -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); -#endif -#endif /* GL_EXT_vertex_attrib_64bit */ - -#ifndef GL_EXT_vertex_shader -#define GL_EXT_vertex_shader 1 -#define GL_VERTEX_SHADER_EXT 0x8780 -#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 -#define GL_OP_INDEX_EXT 0x8782 -#define GL_OP_NEGATE_EXT 0x8783 -#define GL_OP_DOT3_EXT 0x8784 -#define GL_OP_DOT4_EXT 0x8785 -#define GL_OP_MUL_EXT 0x8786 -#define GL_OP_ADD_EXT 0x8787 -#define GL_OP_MADD_EXT 0x8788 -#define GL_OP_FRAC_EXT 0x8789 -#define GL_OP_MAX_EXT 0x878A -#define GL_OP_MIN_EXT 0x878B -#define GL_OP_SET_GE_EXT 0x878C -#define GL_OP_SET_LT_EXT 0x878D -#define GL_OP_CLAMP_EXT 0x878E -#define GL_OP_FLOOR_EXT 0x878F -#define GL_OP_ROUND_EXT 0x8790 -#define GL_OP_EXP_BASE_2_EXT 0x8791 -#define GL_OP_LOG_BASE_2_EXT 0x8792 -#define GL_OP_POWER_EXT 0x8793 -#define GL_OP_RECIP_EXT 0x8794 -#define GL_OP_RECIP_SQRT_EXT 0x8795 -#define GL_OP_SUB_EXT 0x8796 -#define GL_OP_CROSS_PRODUCT_EXT 0x8797 -#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 -#define GL_OP_MOV_EXT 0x8799 -#define GL_OUTPUT_VERTEX_EXT 0x879A -#define GL_OUTPUT_COLOR0_EXT 0x879B -#define GL_OUTPUT_COLOR1_EXT 0x879C -#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D -#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E -#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F -#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 -#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 -#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 -#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 -#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 -#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 -#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 -#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 -#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 -#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 -#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA -#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB -#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC -#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD -#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE -#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF -#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 -#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 -#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 -#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 -#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 -#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 -#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 -#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 -#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 -#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 -#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA -#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB -#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC -#define GL_OUTPUT_FOG_EXT 0x87BD -#define GL_SCALAR_EXT 0x87BE -#define GL_VECTOR_EXT 0x87BF -#define GL_MATRIX_EXT 0x87C0 -#define GL_VARIANT_EXT 0x87C1 -#define GL_INVARIANT_EXT 0x87C2 -#define GL_LOCAL_CONSTANT_EXT 0x87C3 -#define GL_LOCAL_EXT 0x87C4 -#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 -#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 -#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 -#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 -#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE -#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF -#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 -#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 -#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 -#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 -#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 -#define GL_X_EXT 0x87D5 -#define GL_Y_EXT 0x87D6 -#define GL_Z_EXT 0x87D7 -#define GL_W_EXT 0x87D8 -#define GL_NEGATIVE_X_EXT 0x87D9 -#define GL_NEGATIVE_Y_EXT 0x87DA -#define GL_NEGATIVE_Z_EXT 0x87DB -#define GL_NEGATIVE_W_EXT 0x87DC -#define GL_ZERO_EXT 0x87DD -#define GL_ONE_EXT 0x87DE -#define GL_NEGATIVE_ONE_EXT 0x87DF -#define GL_NORMALIZED_RANGE_EXT 0x87E0 -#define GL_FULL_RANGE_EXT 0x87E1 -#define GL_CURRENT_VERTEX_EXT 0x87E2 -#define GL_MVP_MATRIX_EXT 0x87E3 -#define GL_VARIANT_VALUE_EXT 0x87E4 -#define GL_VARIANT_DATATYPE_EXT 0x87E5 -#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 -#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 -#define GL_VARIANT_ARRAY_EXT 0x87E8 -#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 -#define GL_INVARIANT_VALUE_EXT 0x87EA -#define GL_INVARIANT_DATATYPE_EXT 0x87EB -#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC -#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED -typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); -typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); -typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); -typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); -typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); -typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); -typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); -typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); -typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); -typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); -typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr); -typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr); -typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); -typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); -typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); -typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); -typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); -typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); -typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); -typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); -typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr); -typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); -typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); -typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); -typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); -typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data); -typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginVertexShaderEXT (void); -GLAPI void APIENTRY glEndVertexShaderEXT (void); -GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); -GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); -GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); -GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); -GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); -GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); -GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); -GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); -GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr); -GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr); -GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); -GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); -GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); -GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); -GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); -GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); -GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); -GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); -GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr); -GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); -GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); -GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); -GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); -GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); -GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); -GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); -GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); -GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data); -GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -#endif -#endif /* GL_EXT_vertex_shader */ - -#ifndef GL_EXT_vertex_weighting -#define GL_EXT_vertex_weighting 1 -#define GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 -#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 -#define GL_MODELVIEW0_MATRIX_EXT 0x0BA6 -#define GL_MODELVIEW1_MATRIX_EXT 0x8506 -#define GL_VERTEX_WEIGHTING_EXT 0x8509 -#define GL_MODELVIEW0_EXT 0x1700 -#define GL_MODELVIEW1_EXT 0x850A -#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B -#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C -#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D -#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E -#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F -#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 -typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); -GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); -GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); -#endif -#endif /* GL_EXT_vertex_weighting */ - -#ifndef GL_EXT_x11_sync_object -#define GL_EXT_x11_sync_object 1 -#define GL_SYNC_X11_FENCE_EXT 0x90E1 -typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); -#endif -#endif /* GL_EXT_x11_sync_object */ - -#ifndef GL_GREMEDY_frame_terminator -#define GL_GREMEDY_frame_terminator 1 -typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); -#endif -#endif /* GL_GREMEDY_frame_terminator */ - -#ifndef GL_GREMEDY_string_marker -#define GL_GREMEDY_string_marker 1 -typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string); -#endif -#endif /* GL_GREMEDY_string_marker */ - -#ifndef GL_HP_convolution_border_modes -#define GL_HP_convolution_border_modes 1 -#define GL_IGNORE_BORDER_HP 0x8150 -#define GL_CONSTANT_BORDER_HP 0x8151 -#define GL_REPLICATE_BORDER_HP 0x8153 -#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 -#endif /* GL_HP_convolution_border_modes */ - -#ifndef GL_HP_image_transform -#define GL_HP_image_transform 1 -#define GL_IMAGE_SCALE_X_HP 0x8155 -#define GL_IMAGE_SCALE_Y_HP 0x8156 -#define GL_IMAGE_TRANSLATE_X_HP 0x8157 -#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 -#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 -#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A -#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B -#define GL_IMAGE_MAG_FILTER_HP 0x815C -#define GL_IMAGE_MIN_FILTER_HP 0x815D -#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E -#define GL_CUBIC_HP 0x815F -#define GL_AVERAGE_HP 0x8160 -#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 -#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 -#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); -#endif -#endif /* GL_HP_image_transform */ - -#ifndef GL_HP_occlusion_test -#define GL_HP_occlusion_test 1 -#define GL_OCCLUSION_TEST_HP 0x8165 -#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 -#endif /* GL_HP_occlusion_test */ - -#ifndef GL_HP_texture_lighting -#define GL_HP_texture_lighting 1 -#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 -#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 -#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 -#endif /* GL_HP_texture_lighting */ - -#ifndef GL_IBM_cull_vertex -#define GL_IBM_cull_vertex 1 -#define GL_CULL_VERTEX_IBM 103050 -#endif /* GL_IBM_cull_vertex */ - -#ifndef GL_IBM_multimode_draw_arrays -#define GL_IBM_multimode_draw_arrays 1 -typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); -#endif -#endif /* GL_IBM_multimode_draw_arrays */ - -#ifndef GL_IBM_rasterpos_clip -#define GL_IBM_rasterpos_clip 1 -#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 -#endif /* GL_IBM_rasterpos_clip */ - -#ifndef GL_IBM_static_data -#define GL_IBM_static_data 1 -#define GL_ALL_STATIC_DATA_IBM 103060 -#define GL_STATIC_VERTEX_ARRAY_IBM 103061 -typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target); -#endif -#endif /* GL_IBM_static_data */ - -#ifndef GL_IBM_texture_mirrored_repeat -#define GL_IBM_texture_mirrored_repeat 1 -#define GL_MIRRORED_REPEAT_IBM 0x8370 -#endif /* GL_IBM_texture_mirrored_repeat */ - -#ifndef GL_IBM_vertex_array_lists -#define GL_IBM_vertex_array_lists 1 -#define GL_VERTEX_ARRAY_LIST_IBM 103070 -#define GL_NORMAL_ARRAY_LIST_IBM 103071 -#define GL_COLOR_ARRAY_LIST_IBM 103072 -#define GL_INDEX_ARRAY_LIST_IBM 103073 -#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 -#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 -#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 -#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 -#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 -#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 -#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 -#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 -#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 -#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 -#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 -#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 -typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride); -GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); -GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); -GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); -GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); -#endif -#endif /* GL_IBM_vertex_array_lists */ - -#ifndef GL_INGR_blend_func_separate -#define GL_INGR_blend_func_separate 1 -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif -#endif /* GL_INGR_blend_func_separate */ - -#ifndef GL_INGR_color_clamp -#define GL_INGR_color_clamp 1 -#define GL_RED_MIN_CLAMP_INGR 0x8560 -#define GL_GREEN_MIN_CLAMP_INGR 0x8561 -#define GL_BLUE_MIN_CLAMP_INGR 0x8562 -#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 -#define GL_RED_MAX_CLAMP_INGR 0x8564 -#define GL_GREEN_MAX_CLAMP_INGR 0x8565 -#define GL_BLUE_MAX_CLAMP_INGR 0x8566 -#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 -#endif /* GL_INGR_color_clamp */ - -#ifndef GL_INGR_interlace_read -#define GL_INGR_interlace_read 1 -#define GL_INTERLACE_READ_INGR 0x8568 -#endif /* GL_INGR_interlace_read */ - -#ifndef GL_INTEL_fragment_shader_ordering -#define GL_INTEL_fragment_shader_ordering 1 -#endif /* GL_INTEL_fragment_shader_ordering */ - -#ifndef GL_INTEL_map_texture -#define GL_INTEL_map_texture 1 -#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF -#define GL_LAYOUT_DEFAULT_INTEL 0 -#define GL_LAYOUT_LINEAR_INTEL 1 -#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 -typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); -typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); -typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture); -GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level); -GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); -#endif -#endif /* GL_INTEL_map_texture */ - -#ifndef GL_INTEL_parallel_arrays -#define GL_INTEL_parallel_arrays 1 -#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 -#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 -#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 -#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 -#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 -typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer); -typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer); -GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer); -GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer); -GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer); -#endif -#endif /* GL_INTEL_parallel_arrays */ - -#ifndef GL_INTEL_performance_query -#define GL_INTEL_performance_query 1 -#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 -#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 -#define GL_PERFQUERY_WAIT_INTEL 0x83FB -#define GL_PERFQUERY_FLUSH_INTEL 0x83FA -#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 -#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 -#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 -#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 -#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 -#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 -#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 -#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 -#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 -#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA -#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB -#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC -#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD -#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE -#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF -#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 -typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); -typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); -typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); -typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); -typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); -typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); -typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); -typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); -typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); -typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); -GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); -GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); -GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); -GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); -GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); -GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); -GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); -GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); -GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); -#endif -#endif /* GL_INTEL_performance_query */ - -#ifndef GL_MESAX_texture_stack -#define GL_MESAX_texture_stack 1 -#define GL_TEXTURE_1D_STACK_MESAX 0x8759 -#define GL_TEXTURE_2D_STACK_MESAX 0x875A -#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B -#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C -#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D -#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E -#endif /* GL_MESAX_texture_stack */ - -#ifndef GL_MESA_pack_invert -#define GL_MESA_pack_invert 1 -#define GL_PACK_INVERT_MESA 0x8758 -#endif /* GL_MESA_pack_invert */ - -#ifndef GL_MESA_resize_buffers -#define GL_MESA_resize_buffers 1 -typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glResizeBuffersMESA (void); -#endif -#endif /* GL_MESA_resize_buffers */ - -#ifndef GL_MESA_window_pos -#define GL_MESA_window_pos 1 -typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); -GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); -GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); -#endif -#endif /* GL_MESA_window_pos */ - -#ifndef GL_MESA_ycbcr_texture -#define GL_MESA_ycbcr_texture 1 -#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB -#define GL_YCBCR_MESA 0x8757 -#endif /* GL_MESA_ycbcr_texture */ - -#ifndef GL_NVX_conditional_render -#define GL_NVX_conditional_render 1 -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id); -GLAPI void APIENTRY glEndConditionalRenderNVX (void); -#endif -#endif /* GL_NVX_conditional_render */ - -#ifndef GL_NV_bindless_multi_draw_indirect -#define GL_NV_bindless_multi_draw_indirect 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -#endif -#endif /* GL_NV_bindless_multi_draw_indirect */ - -#ifndef GL_NV_bindless_texture -#define GL_NV_bindless_texture 1 -typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); -typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); -typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); -typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture); -GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); -GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); -GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); -GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); -GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); -GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); -GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); -GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); -GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); -#endif -#endif /* GL_NV_bindless_texture */ - -#ifndef GL_NV_blend_equation_advanced -#define GL_NV_blend_equation_advanced 1 -#define GL_BLEND_OVERLAP_NV 0x9281 -#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 -#define GL_BLUE_NV 0x1905 -#define GL_COLORBURN_NV 0x929A -#define GL_COLORDODGE_NV 0x9299 -#define GL_CONJOINT_NV 0x9284 -#define GL_CONTRAST_NV 0x92A1 -#define GL_DARKEN_NV 0x9297 -#define GL_DIFFERENCE_NV 0x929E -#define GL_DISJOINT_NV 0x9283 -#define GL_DST_ATOP_NV 0x928F -#define GL_DST_IN_NV 0x928B -#define GL_DST_NV 0x9287 -#define GL_DST_OUT_NV 0x928D -#define GL_DST_OVER_NV 0x9289 -#define GL_EXCLUSION_NV 0x92A0 -#define GL_GREEN_NV 0x1904 -#define GL_HARDLIGHT_NV 0x929B -#define GL_HARDMIX_NV 0x92A9 -#define GL_HSL_COLOR_NV 0x92AF -#define GL_HSL_HUE_NV 0x92AD -#define GL_HSL_LUMINOSITY_NV 0x92B0 -#define GL_HSL_SATURATION_NV 0x92AE -#define GL_INVERT_OVG_NV 0x92B4 -#define GL_INVERT_RGB_NV 0x92A3 -#define GL_LIGHTEN_NV 0x9298 -#define GL_LINEARBURN_NV 0x92A5 -#define GL_LINEARDODGE_NV 0x92A4 -#define GL_LINEARLIGHT_NV 0x92A7 -#define GL_MINUS_CLAMPED_NV 0x92B3 -#define GL_MINUS_NV 0x929F -#define GL_MULTIPLY_NV 0x9294 -#define GL_OVERLAY_NV 0x9296 -#define GL_PINLIGHT_NV 0x92A8 -#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 -#define GL_PLUS_CLAMPED_NV 0x92B1 -#define GL_PLUS_DARKER_NV 0x9292 -#define GL_PLUS_NV 0x9291 -#define GL_RED_NV 0x1903 -#define GL_SCREEN_NV 0x9295 -#define GL_SOFTLIGHT_NV 0x929C -#define GL_SRC_ATOP_NV 0x928E -#define GL_SRC_IN_NV 0x928A -#define GL_SRC_NV 0x9286 -#define GL_SRC_OUT_NV 0x928C -#define GL_SRC_OVER_NV 0x9288 -#define GL_UNCORRELATED_NV 0x9282 -#define GL_VIVIDLIGHT_NV 0x92A6 -#define GL_XOR_NV 0x1506 -typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value); -GLAPI void APIENTRY glBlendBarrierNV (void); -#endif -#endif /* GL_NV_blend_equation_advanced */ - -#ifndef GL_NV_blend_equation_advanced_coherent -#define GL_NV_blend_equation_advanced_coherent 1 -#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 -#endif /* GL_NV_blend_equation_advanced_coherent */ - -#ifndef GL_NV_blend_square -#define GL_NV_blend_square 1 -#endif /* GL_NV_blend_square */ - -#ifndef GL_NV_compute_program5 -#define GL_NV_compute_program5 1 -#define GL_COMPUTE_PROGRAM_NV 0x90FB -#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC -#endif /* GL_NV_compute_program5 */ - -#ifndef GL_NV_conditional_render -#define GL_NV_conditional_render 1 -#define GL_QUERY_WAIT_NV 0x8E13 -#define GL_QUERY_NO_WAIT_NV 0x8E14 -#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRenderNV (void); -#endif -#endif /* GL_NV_conditional_render */ - -#ifndef GL_NV_copy_depth_to_color -#define GL_NV_copy_depth_to_color 1 -#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E -#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F -#endif /* GL_NV_copy_depth_to_color */ - -#ifndef GL_NV_copy_image -#define GL_NV_copy_image 1 -typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif -#endif /* GL_NV_copy_image */ - -#ifndef GL_NV_deep_texture3D -#define GL_NV_deep_texture3D 1 -#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0 -#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1 -#endif /* GL_NV_deep_texture3D */ - -#ifndef GL_NV_depth_buffer_float -#define GL_NV_depth_buffer_float 1 -#define GL_DEPTH_COMPONENT32F_NV 0x8DAB -#define GL_DEPTH32F_STENCIL8_NV 0x8DAC -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD -#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF -typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); -typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); -GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); -#endif -#endif /* GL_NV_depth_buffer_float */ - -#ifndef GL_NV_depth_clamp -#define GL_NV_depth_clamp 1 -#define GL_DEPTH_CLAMP_NV 0x864F -#endif /* GL_NV_depth_clamp */ - -#ifndef GL_NV_draw_texture -#define GL_NV_draw_texture 1 -typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); -#endif -#endif /* GL_NV_draw_texture */ - -#ifndef GL_NV_evaluators -#define GL_NV_evaluators 1 -#define GL_EVAL_2D_NV 0x86C0 -#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 -#define GL_MAP_TESSELLATION_NV 0x86C2 -#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 -#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 -#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 -#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 -#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 -#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 -#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 -#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA -#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB -#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC -#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD -#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE -#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF -#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 -#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 -#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 -#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 -#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 -#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 -#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 -#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 -typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); -typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); -typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); -GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); -GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); -#endif -#endif /* GL_NV_evaluators */ - -#ifndef GL_NV_explicit_multisample -#define GL_NV_explicit_multisample 1 -#define GL_SAMPLE_POSITION_NV 0x8E50 -#define GL_SAMPLE_MASK_NV 0x8E51 -#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 -#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 -#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 -#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 -#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 -#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 -#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 -#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); -typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); -GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); -#endif -#endif /* GL_NV_explicit_multisample */ - -#ifndef GL_NV_fence -#define GL_NV_fence 1 -#define GL_ALL_COMPLETED_NV 0x84F2 -#define GL_FENCE_STATUS_NV 0x84F3 -#define GL_FENCE_CONDITION_NV 0x84F4 -typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); -typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); -typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); -GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); -GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); -GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); -GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); -GLAPI void APIENTRY glFinishFenceNV (GLuint fence); -GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); -#endif -#endif /* GL_NV_fence */ - -#ifndef GL_NV_float_buffer -#define GL_NV_float_buffer 1 -#define GL_FLOAT_R_NV 0x8880 -#define GL_FLOAT_RG_NV 0x8881 -#define GL_FLOAT_RGB_NV 0x8882 -#define GL_FLOAT_RGBA_NV 0x8883 -#define GL_FLOAT_R16_NV 0x8884 -#define GL_FLOAT_R32_NV 0x8885 -#define GL_FLOAT_RG16_NV 0x8886 -#define GL_FLOAT_RG32_NV 0x8887 -#define GL_FLOAT_RGB16_NV 0x8888 -#define GL_FLOAT_RGB32_NV 0x8889 -#define GL_FLOAT_RGBA16_NV 0x888A -#define GL_FLOAT_RGBA32_NV 0x888B -#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C -#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D -#define GL_FLOAT_RGBA_MODE_NV 0x888E -#endif /* GL_NV_float_buffer */ - -#ifndef GL_NV_fog_distance -#define GL_NV_fog_distance 1 -#define GL_FOG_DISTANCE_MODE_NV 0x855A -#define GL_EYE_RADIAL_NV 0x855B -#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C -#endif /* GL_NV_fog_distance */ - -#ifndef GL_NV_fragment_program -#define GL_NV_fragment_program 1 -#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 -#define GL_FRAGMENT_PROGRAM_NV 0x8870 -#define GL_MAX_TEXTURE_COORDS_NV 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 -#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 -#define GL_PROGRAM_ERROR_STRING_NV 0x8874 -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); -typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); -GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); -GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); -GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#endif -#endif /* GL_NV_fragment_program */ - -#ifndef GL_NV_fragment_program2 -#define GL_NV_fragment_program2 1 -#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 -#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 -#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 -#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 -#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 -#endif /* GL_NV_fragment_program2 */ - -#ifndef GL_NV_fragment_program4 -#define GL_NV_fragment_program4 1 -#endif /* GL_NV_fragment_program4 */ - -#ifndef GL_NV_fragment_program_option -#define GL_NV_fragment_program_option 1 -#endif /* GL_NV_fragment_program_option */ - -#ifndef GL_NV_framebuffer_multisample_coverage -#define GL_NV_framebuffer_multisample_coverage 1 -#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB -#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 -#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 -#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -#endif -#endif /* GL_NV_framebuffer_multisample_coverage */ - -#ifndef GL_NV_geometry_program4 -#define GL_NV_geometry_program4 1 -#define GL_GEOMETRY_PROGRAM_NV 0x8C26 -#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 -#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 -typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); -GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif -#endif /* GL_NV_geometry_program4 */ - -#ifndef GL_NV_geometry_shader4 -#define GL_NV_geometry_shader4 1 -#endif /* GL_NV_geometry_shader4 */ - -#ifndef GL_NV_gpu_program4 -#define GL_NV_gpu_program4 1 -#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 -#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 -#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 -#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 -#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 -#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 -#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); -#endif -#endif /* GL_NV_gpu_program4 */ - -#ifndef GL_NV_gpu_program5 -#define GL_NV_gpu_program5 1 -#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C -#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F -#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 -#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 -typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); -#endif -#endif /* GL_NV_gpu_program5 */ - -#ifndef GL_NV_gpu_program5_mem_extended -#define GL_NV_gpu_program5_mem_extended 1 -#endif /* GL_NV_gpu_program5_mem_extended */ - -#ifndef GL_NV_gpu_shader5 -#define GL_NV_gpu_shader5 1 -typedef int64_t GLint64EXT; -#define GL_INT64_NV 0x140E -#define GL_UNSIGNED_INT64_NV 0x140F -#define GL_INT8_NV 0x8FE0 -#define GL_INT8_VEC2_NV 0x8FE1 -#define GL_INT8_VEC3_NV 0x8FE2 -#define GL_INT8_VEC4_NV 0x8FE3 -#define GL_INT16_NV 0x8FE4 -#define GL_INT16_VEC2_NV 0x8FE5 -#define GL_INT16_VEC3_NV 0x8FE6 -#define GL_INT16_VEC4_NV 0x8FE7 -#define GL_INT64_VEC2_NV 0x8FE9 -#define GL_INT64_VEC3_NV 0x8FEA -#define GL_INT64_VEC4_NV 0x8FEB -#define GL_UNSIGNED_INT8_NV 0x8FEC -#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED -#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE -#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF -#define GL_UNSIGNED_INT16_NV 0x8FF0 -#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 -#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 -#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 -#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 -#define GL_FLOAT16_NV 0x8FF8 -#define GL_FLOAT16_VEC2_NV 0x8FF9 -#define GL_FLOAT16_VEC3_NV 0x8FFA -#define GL_FLOAT16_VEC4_NV 0x8FFB -typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); -GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); -GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); -GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); -GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); -GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif -#endif /* GL_NV_gpu_shader5 */ - -#ifndef GL_NV_half_float -#define GL_NV_half_float 1 -typedef unsigned short GLhalfNV; -#define GL_HALF_FLOAT_NV 0x140B -typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); -typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); -typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); -typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); -typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); -typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); -typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); -typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); -typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); -GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); -GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); -GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); -GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); -GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); -GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); -GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); -GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); -GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); -GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); -GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); -GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); -GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); -GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); -GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); -GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); -GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -#endif -#endif /* GL_NV_half_float */ - -#ifndef GL_NV_light_max_exponent -#define GL_NV_light_max_exponent 1 -#define GL_MAX_SHININESS_NV 0x8504 -#define GL_MAX_SPOT_EXPONENT_NV 0x8505 -#endif /* GL_NV_light_max_exponent */ - -#ifndef GL_NV_multisample_coverage -#define GL_NV_multisample_coverage 1 -#define GL_COLOR_SAMPLES_NV 0x8E20 -#endif /* GL_NV_multisample_coverage */ - -#ifndef GL_NV_multisample_filter_hint -#define GL_NV_multisample_filter_hint 1 -#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 -#endif /* GL_NV_multisample_filter_hint */ - -#ifndef GL_NV_occlusion_query -#define GL_NV_occlusion_query 1 -#define GL_PIXEL_COUNTER_BITS_NV 0x8864 -#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 -#define GL_PIXEL_COUNT_NV 0x8866 -#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 -typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); -typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); -GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); -GLAPI void APIENTRY glEndOcclusionQueryNV (void); -GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); -#endif -#endif /* GL_NV_occlusion_query */ - -#ifndef GL_NV_packed_depth_stencil -#define GL_NV_packed_depth_stencil 1 -#define GL_DEPTH_STENCIL_NV 0x84F9 -#define GL_UNSIGNED_INT_24_8_NV 0x84FA -#endif /* GL_NV_packed_depth_stencil */ - -#ifndef GL_NV_parameter_buffer_object -#define GL_NV_parameter_buffer_object 1 -#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 -#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 -#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 -#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 -#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); -#endif -#endif /* GL_NV_parameter_buffer_object */ - -#ifndef GL_NV_parameter_buffer_object2 -#define GL_NV_parameter_buffer_object2 1 -#endif /* GL_NV_parameter_buffer_object2 */ - -#ifndef GL_NV_path_rendering -#define GL_NV_path_rendering 1 -#define GL_PATH_FORMAT_SVG_NV 0x9070 -#define GL_PATH_FORMAT_PS_NV 0x9071 -#define GL_STANDARD_FONT_NAME_NV 0x9072 -#define GL_SYSTEM_FONT_NAME_NV 0x9073 -#define GL_FILE_NAME_NV 0x9074 -#define GL_PATH_STROKE_WIDTH_NV 0x9075 -#define GL_PATH_END_CAPS_NV 0x9076 -#define GL_PATH_INITIAL_END_CAP_NV 0x9077 -#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 -#define GL_PATH_JOIN_STYLE_NV 0x9079 -#define GL_PATH_MITER_LIMIT_NV 0x907A -#define GL_PATH_DASH_CAPS_NV 0x907B -#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C -#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D -#define GL_PATH_DASH_OFFSET_NV 0x907E -#define GL_PATH_CLIENT_LENGTH_NV 0x907F -#define GL_PATH_FILL_MODE_NV 0x9080 -#define GL_PATH_FILL_MASK_NV 0x9081 -#define GL_PATH_FILL_COVER_MODE_NV 0x9082 -#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 -#define GL_PATH_STROKE_MASK_NV 0x9084 -#define GL_COUNT_UP_NV 0x9088 -#define GL_COUNT_DOWN_NV 0x9089 -#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A -#define GL_CONVEX_HULL_NV 0x908B -#define GL_BOUNDING_BOX_NV 0x908D -#define GL_TRANSLATE_X_NV 0x908E -#define GL_TRANSLATE_Y_NV 0x908F -#define GL_TRANSLATE_2D_NV 0x9090 -#define GL_TRANSLATE_3D_NV 0x9091 -#define GL_AFFINE_2D_NV 0x9092 -#define GL_AFFINE_3D_NV 0x9094 -#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 -#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 -#define GL_UTF8_NV 0x909A -#define GL_UTF16_NV 0x909B -#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C -#define GL_PATH_COMMAND_COUNT_NV 0x909D -#define GL_PATH_COORD_COUNT_NV 0x909E -#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F -#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 -#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 -#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 -#define GL_SQUARE_NV 0x90A3 -#define GL_ROUND_NV 0x90A4 -#define GL_TRIANGULAR_NV 0x90A5 -#define GL_BEVEL_NV 0x90A6 -#define GL_MITER_REVERT_NV 0x90A7 -#define GL_MITER_TRUNCATE_NV 0x90A8 -#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 -#define GL_USE_MISSING_GLYPH_NV 0x90AA -#define GL_PATH_ERROR_POSITION_NV 0x90AB -#define GL_PATH_FOG_GEN_MODE_NV 0x90AC -#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD -#define GL_ADJACENT_PAIRS_NV 0x90AE -#define GL_FIRST_TO_REST_NV 0x90AF -#define GL_PATH_GEN_MODE_NV 0x90B0 -#define GL_PATH_GEN_COEFF_NV 0x90B1 -#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 -#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 -#define GL_PATH_STENCIL_FUNC_NV 0x90B7 -#define GL_PATH_STENCIL_REF_NV 0x90B8 -#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 -#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD -#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE -#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF -#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 -#define GL_MOVE_TO_RESETS_NV 0x90B5 -#define GL_MOVE_TO_CONTINUES_NV 0x90B6 -#define GL_CLOSE_PATH_NV 0x00 -#define GL_MOVE_TO_NV 0x02 -#define GL_RELATIVE_MOVE_TO_NV 0x03 -#define GL_LINE_TO_NV 0x04 -#define GL_RELATIVE_LINE_TO_NV 0x05 -#define GL_HORIZONTAL_LINE_TO_NV 0x06 -#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 -#define GL_VERTICAL_LINE_TO_NV 0x08 -#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 -#define GL_QUADRATIC_CURVE_TO_NV 0x0A -#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B -#define GL_CUBIC_CURVE_TO_NV 0x0C -#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D -#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E -#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F -#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 -#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 -#define GL_SMALL_CCW_ARC_TO_NV 0x12 -#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 -#define GL_SMALL_CW_ARC_TO_NV 0x14 -#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 -#define GL_LARGE_CCW_ARC_TO_NV 0x16 -#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 -#define GL_LARGE_CW_ARC_TO_NV 0x18 -#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 -#define GL_RESTART_PATH_NV 0xF0 -#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 -#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 -#define GL_RECT_NV 0xF6 -#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 -#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA -#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC -#define GL_ARC_TO_NV 0xFE -#define GL_RELATIVE_ARC_TO_NV 0xFF -#define GL_BOLD_BIT_NV 0x01 -#define GL_ITALIC_BIT_NV 0x02 -#define GL_GLYPH_WIDTH_BIT_NV 0x01 -#define GL_GLYPH_HEIGHT_BIT_NV 0x02 -#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 -#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 -#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 -#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 -#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 -#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 -#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 -#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 -#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 -#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 -#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 -#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 -#define GL_FONT_ASCENDER_BIT_NV 0x00200000 -#define GL_FONT_DESCENDER_BIT_NV 0x00400000 -#define GL_FONT_HEIGHT_BIT_NV 0x00800000 -#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 -#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 -#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 -#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 -#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 -#define GL_PRIMARY_COLOR_NV 0x852C -#define GL_SECONDARY_COLOR_NV 0x852D -typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); -typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); -typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); -typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); -typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); -typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); -typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); -typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); -typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); -typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); -typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); -typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); -typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); -GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); -GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); -GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); -GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); -GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); -GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); -GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); -GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); -GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); -GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); -GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); -GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); -GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); -GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); -GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); -GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); -GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); -GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); -GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); -GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); -GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); -GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); -GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -#endif -#endif /* GL_NV_path_rendering */ - -#ifndef GL_NV_pixel_data_range -#define GL_NV_pixel_data_range 1 -#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 -#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 -#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A -#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B -#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C -#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D -typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer); -typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer); -GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); -#endif -#endif /* GL_NV_pixel_data_range */ - -#ifndef GL_NV_point_sprite -#define GL_NV_point_sprite 1 -#define GL_POINT_SPRITE_NV 0x8861 -#define GL_COORD_REPLACE_NV 0x8862 -#define GL_POINT_SPRITE_R_MODE_NV 0x8863 -typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); -#endif -#endif /* GL_NV_point_sprite */ - -#ifndef GL_NV_present_video -#define GL_NV_present_video 1 -#define GL_FRAME_NV 0x8E26 -#define GL_FIELDS_NV 0x8E27 -#define GL_CURRENT_TIME_NV 0x8E28 -#define GL_NUM_FILL_STREAMS_NV 0x8E29 -#define GL_PRESENT_TIME_NV 0x8E2A -#define GL_PRESENT_DURATION_NV 0x8E2B -typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); -typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); -typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); -GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); -GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); -GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); -#endif -#endif /* GL_NV_present_video */ - -#ifndef GL_NV_primitive_restart -#define GL_NV_primitive_restart 1 -#define GL_PRIMITIVE_RESTART_NV 0x8558 -#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPrimitiveRestartNV (void); -GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); -#endif -#endif /* GL_NV_primitive_restart */ - -#ifndef GL_NV_register_combiners -#define GL_NV_register_combiners 1 -#define GL_REGISTER_COMBINERS_NV 0x8522 -#define GL_VARIABLE_A_NV 0x8523 -#define GL_VARIABLE_B_NV 0x8524 -#define GL_VARIABLE_C_NV 0x8525 -#define GL_VARIABLE_D_NV 0x8526 -#define GL_VARIABLE_E_NV 0x8527 -#define GL_VARIABLE_F_NV 0x8528 -#define GL_VARIABLE_G_NV 0x8529 -#define GL_CONSTANT_COLOR0_NV 0x852A -#define GL_CONSTANT_COLOR1_NV 0x852B -#define GL_SPARE0_NV 0x852E -#define GL_SPARE1_NV 0x852F -#define GL_DISCARD_NV 0x8530 -#define GL_E_TIMES_F_NV 0x8531 -#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 -#define GL_UNSIGNED_IDENTITY_NV 0x8536 -#define GL_UNSIGNED_INVERT_NV 0x8537 -#define GL_EXPAND_NORMAL_NV 0x8538 -#define GL_EXPAND_NEGATE_NV 0x8539 -#define GL_HALF_BIAS_NORMAL_NV 0x853A -#define GL_HALF_BIAS_NEGATE_NV 0x853B -#define GL_SIGNED_IDENTITY_NV 0x853C -#define GL_SIGNED_NEGATE_NV 0x853D -#define GL_SCALE_BY_TWO_NV 0x853E -#define GL_SCALE_BY_FOUR_NV 0x853F -#define GL_SCALE_BY_ONE_HALF_NV 0x8540 -#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 -#define GL_COMBINER_INPUT_NV 0x8542 -#define GL_COMBINER_MAPPING_NV 0x8543 -#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 -#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 -#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 -#define GL_COMBINER_MUX_SUM_NV 0x8547 -#define GL_COMBINER_SCALE_NV 0x8548 -#define GL_COMBINER_BIAS_NV 0x8549 -#define GL_COMBINER_AB_OUTPUT_NV 0x854A -#define GL_COMBINER_CD_OUTPUT_NV 0x854B -#define GL_COMBINER_SUM_OUTPUT_NV 0x854C -#define GL_MAX_GENERAL_COMBINERS_NV 0x854D -#define GL_NUM_GENERAL_COMBINERS_NV 0x854E -#define GL_COLOR_SUM_CLAMP_NV 0x854F -#define GL_COMBINER0_NV 0x8550 -#define GL_COMBINER1_NV 0x8551 -#define GL_COMBINER2_NV 0x8552 -#define GL_COMBINER3_NV 0x8553 -#define GL_COMBINER4_NV 0x8554 -#define GL_COMBINER5_NV 0x8555 -#define GL_COMBINER6_NV 0x8556 -#define GL_COMBINER7_NV 0x8557 -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); -typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); -GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); -GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); -GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); -GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); -#endif -#endif /* GL_NV_register_combiners */ - -#ifndef GL_NV_register_combiners2 -#define GL_NV_register_combiners2 1 -#define GL_PER_STAGE_CONSTANTS_NV 0x8535 -typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); -#endif -#endif /* GL_NV_register_combiners2 */ - -#ifndef GL_NV_shader_atomic_counters -#define GL_NV_shader_atomic_counters 1 -#endif /* GL_NV_shader_atomic_counters */ - -#ifndef GL_NV_shader_atomic_float -#define GL_NV_shader_atomic_float 1 -#endif /* GL_NV_shader_atomic_float */ - -#ifndef GL_NV_shader_buffer_load -#define GL_NV_shader_buffer_load 1 -#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D -#define GL_GPU_ADDRESS_NV 0x8F34 -#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 -typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); -typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); -typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); -typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); -typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); -GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); -GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); -GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); -GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); -GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); -GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); -GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); -GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); -GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); -GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif -#endif /* GL_NV_shader_buffer_load */ - -#ifndef GL_NV_shader_buffer_store -#define GL_NV_shader_buffer_store 1 -#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 -#endif /* GL_NV_shader_buffer_store */ - -#ifndef GL_NV_shader_storage_buffer_object -#define GL_NV_shader_storage_buffer_object 1 -#endif /* GL_NV_shader_storage_buffer_object */ - -#ifndef GL_NV_tessellation_program5 -#define GL_NV_tessellation_program5 1 -#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 -#define GL_TESS_CONTROL_PROGRAM_NV 0x891E -#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F -#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 -#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 -#endif /* GL_NV_tessellation_program5 */ - -#ifndef GL_NV_texgen_emboss -#define GL_NV_texgen_emboss 1 -#define GL_EMBOSS_LIGHT_NV 0x855D -#define GL_EMBOSS_CONSTANT_NV 0x855E -#define GL_EMBOSS_MAP_NV 0x855F -#endif /* GL_NV_texgen_emboss */ - -#ifndef GL_NV_texgen_reflection -#define GL_NV_texgen_reflection 1 -#define GL_NORMAL_MAP_NV 0x8511 -#define GL_REFLECTION_MAP_NV 0x8512 -#endif /* GL_NV_texgen_reflection */ - -#ifndef GL_NV_texture_barrier -#define GL_NV_texture_barrier 1 -typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureBarrierNV (void); -#endif -#endif /* GL_NV_texture_barrier */ - -#ifndef GL_NV_texture_compression_vtc -#define GL_NV_texture_compression_vtc 1 -#endif /* GL_NV_texture_compression_vtc */ - -#ifndef GL_NV_texture_env_combine4 -#define GL_NV_texture_env_combine4 1 -#define GL_COMBINE4_NV 0x8503 -#define GL_SOURCE3_RGB_NV 0x8583 -#define GL_SOURCE3_ALPHA_NV 0x858B -#define GL_OPERAND3_RGB_NV 0x8593 -#define GL_OPERAND3_ALPHA_NV 0x859B -#endif /* GL_NV_texture_env_combine4 */ - -#ifndef GL_NV_texture_expand_normal -#define GL_NV_texture_expand_normal 1 -#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F -#endif /* GL_NV_texture_expand_normal */ - -#ifndef GL_NV_texture_multisample -#define GL_NV_texture_multisample 1 -#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 -#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -#endif -#endif /* GL_NV_texture_multisample */ - -#ifndef GL_NV_texture_rectangle -#define GL_NV_texture_rectangle 1 -#define GL_TEXTURE_RECTANGLE_NV 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 -#endif /* GL_NV_texture_rectangle */ - -#ifndef GL_NV_texture_shader -#define GL_NV_texture_shader 1 -#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C -#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D -#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E -#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 -#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA -#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB -#define GL_DSDT_MAG_INTENSITY_NV 0x86DC -#define GL_SHADER_CONSISTENT_NV 0x86DD -#define GL_TEXTURE_SHADER_NV 0x86DE -#define GL_SHADER_OPERATION_NV 0x86DF -#define GL_CULL_MODES_NV 0x86E0 -#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 -#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 -#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 -#define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1 -#define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2 -#define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3 -#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 -#define GL_CONST_EYE_NV 0x86E5 -#define GL_PASS_THROUGH_NV 0x86E6 -#define GL_CULL_FRAGMENT_NV 0x86E7 -#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 -#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 -#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA -#define GL_DOT_PRODUCT_NV 0x86EC -#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED -#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE -#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 -#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 -#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 -#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 -#define GL_HILO_NV 0x86F4 -#define GL_DSDT_NV 0x86F5 -#define GL_DSDT_MAG_NV 0x86F6 -#define GL_DSDT_MAG_VIB_NV 0x86F7 -#define GL_HILO16_NV 0x86F8 -#define GL_SIGNED_HILO_NV 0x86F9 -#define GL_SIGNED_HILO16_NV 0x86FA -#define GL_SIGNED_RGBA_NV 0x86FB -#define GL_SIGNED_RGBA8_NV 0x86FC -#define GL_SIGNED_RGB_NV 0x86FE -#define GL_SIGNED_RGB8_NV 0x86FF -#define GL_SIGNED_LUMINANCE_NV 0x8701 -#define GL_SIGNED_LUMINANCE8_NV 0x8702 -#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 -#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 -#define GL_SIGNED_ALPHA_NV 0x8705 -#define GL_SIGNED_ALPHA8_NV 0x8706 -#define GL_SIGNED_INTENSITY_NV 0x8707 -#define GL_SIGNED_INTENSITY8_NV 0x8708 -#define GL_DSDT8_NV 0x8709 -#define GL_DSDT8_MAG8_NV 0x870A -#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B -#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C -#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D -#define GL_HI_SCALE_NV 0x870E -#define GL_LO_SCALE_NV 0x870F -#define GL_DS_SCALE_NV 0x8710 -#define GL_DT_SCALE_NV 0x8711 -#define GL_MAGNITUDE_SCALE_NV 0x8712 -#define GL_VIBRANCE_SCALE_NV 0x8713 -#define GL_HI_BIAS_NV 0x8714 -#define GL_LO_BIAS_NV 0x8715 -#define GL_DS_BIAS_NV 0x8716 -#define GL_DT_BIAS_NV 0x8717 -#define GL_MAGNITUDE_BIAS_NV 0x8718 -#define GL_VIBRANCE_BIAS_NV 0x8719 -#define GL_TEXTURE_BORDER_VALUES_NV 0x871A -#define GL_TEXTURE_HI_SIZE_NV 0x871B -#define GL_TEXTURE_LO_SIZE_NV 0x871C -#define GL_TEXTURE_DS_SIZE_NV 0x871D -#define GL_TEXTURE_DT_SIZE_NV 0x871E -#define GL_TEXTURE_MAG_SIZE_NV 0x871F -#endif /* GL_NV_texture_shader */ - -#ifndef GL_NV_texture_shader2 -#define GL_NV_texture_shader2 1 -#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF -#endif /* GL_NV_texture_shader2 */ - -#ifndef GL_NV_texture_shader3 -#define GL_NV_texture_shader3 1 -#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 -#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 -#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 -#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 -#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 -#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 -#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 -#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 -#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 -#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 -#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A -#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B -#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C -#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D -#define GL_HILO8_NV 0x885E -#define GL_SIGNED_HILO8_NV 0x885F -#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 -#endif /* GL_NV_texture_shader3 */ - -#ifndef GL_NV_transform_feedback -#define GL_NV_transform_feedback 1 -#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 -#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 -#define GL_TEXTURE_COORD_NV 0x8C79 -#define GL_CLIP_DISTANCE_NV 0x8C7A -#define GL_VERTEX_ID_NV 0x8C7B -#define GL_PRIMITIVE_ID_NV 0x8C7C -#define GL_GENERIC_ATTRIB_NV 0x8C7D -#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 -#define GL_ACTIVE_VARYINGS_NV 0x8C81 -#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 -#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 -#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 -#define GL_PRIMITIVES_GENERATED_NV 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 -#define GL_RASTERIZER_DISCARD_NV 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B -#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C -#define GL_SEPARATE_ATTRIBS_NV 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F -#define GL_LAYER_NV 0x8DAA -#define GL_NEXT_BUFFER_NV -2 -#define GL_SKIP_COMPONENTS4_NV -3 -#define GL_SKIP_COMPONENTS3_NV -4 -#define GL_SKIP_COMPONENTS2_NV -5 -#define GL_SKIP_COMPONENTS1_NV -6 -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); -typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedbackNV (void); -GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); -GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); -GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); -GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); -GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); -#endif -#endif /* GL_NV_transform_feedback */ - -#ifndef GL_NV_transform_feedback2 -#define GL_NV_transform_feedback2 1 -#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedbackNV (void); -GLAPI void APIENTRY glResumeTransformFeedbackNV (void); -GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); -#endif -#endif /* GL_NV_transform_feedback2 */ - -#ifndef GL_NV_vdpau_interop -#define GL_NV_vdpau_interop 1 -typedef GLintptr GLvdpauSurfaceNV; -#define GL_SURFACE_STATE_NV 0x86EB -#define GL_SURFACE_REGISTERED_NV 0x86FD -#define GL_SURFACE_MAPPED_NV 0x8700 -#define GL_WRITE_DISCARD_NV 0x88BE -typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress); -typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); -typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); -typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); -typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); -typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress); -GLAPI void APIENTRY glVDPAUFiniNV (void); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); -GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); -GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); -GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); -GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); -#endif -#endif /* GL_NV_vdpau_interop */ - -#ifndef GL_NV_vertex_array_range -#define GL_NV_vertex_array_range 1 -#define GL_VERTEX_ARRAY_RANGE_NV 0x851D -#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E -#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F -#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 -#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); -GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer); -#endif -#endif /* GL_NV_vertex_array_range */ - -#ifndef GL_NV_vertex_array_range2 -#define GL_NV_vertex_array_range2 1 -#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 -#endif /* GL_NV_vertex_array_range2 */ - -#ifndef GL_NV_vertex_attrib_integer_64bit -#define GL_NV_vertex_attrib_integer_64bit 1 -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); -GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); -GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -#endif -#endif /* GL_NV_vertex_attrib_integer_64bit */ - -#ifndef GL_NV_vertex_buffer_unified_memory -#define GL_NV_vertex_buffer_unified_memory 1 -#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E -#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F -#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 -#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 -#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 -#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 -#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 -#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 -#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 -#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 -#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 -#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 -#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A -#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B -#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C -#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D -#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E -#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F -#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 -#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 -#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 -#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 -#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 -#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 -#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 -typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); -GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); -#endif -#endif /* GL_NV_vertex_buffer_unified_memory */ - -#ifndef GL_NV_vertex_program -#define GL_NV_vertex_program 1 -#define GL_VERTEX_PROGRAM_NV 0x8620 -#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 -#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 -#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 -#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 -#define GL_CURRENT_ATTRIB_NV 0x8626 -#define GL_PROGRAM_LENGTH_NV 0x8627 -#define GL_PROGRAM_STRING_NV 0x8628 -#define GL_MODELVIEW_PROJECTION_NV 0x8629 -#define GL_IDENTITY_NV 0x862A -#define GL_INVERSE_NV 0x862B -#define GL_TRANSPOSE_NV 0x862C -#define GL_INVERSE_TRANSPOSE_NV 0x862D -#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E -#define GL_MAX_TRACK_MATRICES_NV 0x862F -#define GL_MATRIX0_NV 0x8630 -#define GL_MATRIX1_NV 0x8631 -#define GL_MATRIX2_NV 0x8632 -#define GL_MATRIX3_NV 0x8633 -#define GL_MATRIX4_NV 0x8634 -#define GL_MATRIX5_NV 0x8635 -#define GL_MATRIX6_NV 0x8636 -#define GL_MATRIX7_NV 0x8637 -#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 -#define GL_CURRENT_MATRIX_NV 0x8641 -#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 -#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 -#define GL_PROGRAM_PARAMETER_NV 0x8644 -#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 -#define GL_PROGRAM_TARGET_NV 0x8646 -#define GL_PROGRAM_RESIDENT_NV 0x8647 -#define GL_TRACK_MATRIX_NV 0x8648 -#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 -#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A -#define GL_PROGRAM_ERROR_POSITION_NV 0x864B -#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 -#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 -#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 -#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 -#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 -#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 -#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 -#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 -#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 -#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 -#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A -#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B -#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C -#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D -#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E -#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F -#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 -#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 -#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 -#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 -#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 -#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 -#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 -#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 -#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 -#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 -#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A -#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B -#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C -#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D -#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E -#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F -#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 -#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 -#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 -#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 -#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 -#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 -#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 -#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 -#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 -#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 -#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A -#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B -#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C -#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D -#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E -#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F -typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); -typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); -typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); -typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); -typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); -GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); -GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); -GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); -GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer); -GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); -GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); -GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); -GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); -GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); -GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); -#endif -#endif /* GL_NV_vertex_program */ - -#ifndef GL_NV_vertex_program1_1 -#define GL_NV_vertex_program1_1 1 -#endif /* GL_NV_vertex_program1_1 */ - -#ifndef GL_NV_vertex_program2 -#define GL_NV_vertex_program2 1 -#endif /* GL_NV_vertex_program2 */ - -#ifndef GL_NV_vertex_program2_option -#define GL_NV_vertex_program2_option 1 -#endif /* GL_NV_vertex_program2_option */ - -#ifndef GL_NV_vertex_program3 -#define GL_NV_vertex_program3 1 -#endif /* GL_NV_vertex_program3 */ - -#ifndef GL_NV_vertex_program4 -#define GL_NV_vertex_program4 1 -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); -#endif -#endif /* GL_NV_vertex_program4 */ - -#ifndef GL_NV_video_capture -#define GL_NV_video_capture 1 -#define GL_VIDEO_BUFFER_NV 0x9020 -#define GL_VIDEO_BUFFER_BINDING_NV 0x9021 -#define GL_FIELD_UPPER_NV 0x9022 -#define GL_FIELD_LOWER_NV 0x9023 -#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 -#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 -#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 -#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 -#define GL_VIDEO_BUFFER_PITCH_NV 0x9028 -#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 -#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A -#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B -#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C -#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D -#define GL_PARTIAL_SUCCESS_NV 0x902E -#define GL_SUCCESS_NV 0x902F -#define GL_FAILURE_NV 0x9030 -#define GL_YCBYCR8_422_NV 0x9031 -#define GL_YCBAYCR8A_4224_NV 0x9032 -#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 -#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 -#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 -#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 -#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 -#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 -#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 -#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A -#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B -#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C -typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); -typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); -typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); -typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); -GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); -GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); -GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); -GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); -GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); -GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); -GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); -#endif -#endif /* GL_NV_video_capture */ - -#ifndef GL_OML_interlace -#define GL_OML_interlace 1 -#define GL_INTERLACE_OML 0x8980 -#define GL_INTERLACE_READ_OML 0x8981 -#endif /* GL_OML_interlace */ - -#ifndef GL_OML_resample -#define GL_OML_resample 1 -#define GL_PACK_RESAMPLE_OML 0x8984 -#define GL_UNPACK_RESAMPLE_OML 0x8985 -#define GL_RESAMPLE_REPLICATE_OML 0x8986 -#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 -#define GL_RESAMPLE_AVERAGE_OML 0x8988 -#define GL_RESAMPLE_DECIMATE_OML 0x8989 -#endif /* GL_OML_resample */ - -#ifndef GL_OML_subsample -#define GL_OML_subsample 1 -#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 -#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 -#endif /* GL_OML_subsample */ - -#ifndef GL_PGI_misc_hints -#define GL_PGI_misc_hints 1 -#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 -#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD -#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE -#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 -#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 -#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 -#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C -#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D -#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E -#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F -#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 -#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 -#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 -#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 -#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 -#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 -#define GL_CLIP_NEAR_HINT_PGI 0x1A220 -#define GL_CLIP_FAR_HINT_PGI 0x1A221 -#define GL_WIDE_LINE_HINT_PGI 0x1A222 -#define GL_BACK_NORMALS_HINT_PGI 0x1A223 -typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); -#endif -#endif /* GL_PGI_misc_hints */ - -#ifndef GL_PGI_vertex_hints -#define GL_PGI_vertex_hints 1 -#define GL_VERTEX_DATA_HINT_PGI 0x1A22A -#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B -#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C -#define GL_MAX_VERTEX_HINT_PGI 0x1A22D -#define GL_COLOR3_BIT_PGI 0x00010000 -#define GL_COLOR4_BIT_PGI 0x00020000 -#define GL_EDGEFLAG_BIT_PGI 0x00040000 -#define GL_INDEX_BIT_PGI 0x00080000 -#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 -#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 -#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 -#define GL_MAT_EMISSION_BIT_PGI 0x00800000 -#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 -#define GL_MAT_SHININESS_BIT_PGI 0x02000000 -#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 -#define GL_NORMAL_BIT_PGI 0x08000000 -#define GL_TEXCOORD1_BIT_PGI 0x10000000 -#define GL_TEXCOORD2_BIT_PGI 0x20000000 -#define GL_TEXCOORD3_BIT_PGI 0x40000000 -#define GL_TEXCOORD4_BIT_PGI 0x80000000 -#define GL_VERTEX23_BIT_PGI 0x00000004 -#define GL_VERTEX4_BIT_PGI 0x00000008 -#endif /* GL_PGI_vertex_hints */ - -#ifndef GL_REND_screen_coordinates -#define GL_REND_screen_coordinates 1 -#define GL_SCREEN_COORDINATES_REND 0x8490 -#define GL_INVERTED_SCREEN_W_REND 0x8491 -#endif /* GL_REND_screen_coordinates */ - -#ifndef GL_S3_s3tc -#define GL_S3_s3tc 1 -#define GL_RGB_S3TC 0x83A0 -#define GL_RGB4_S3TC 0x83A1 -#define GL_RGBA_S3TC 0x83A2 -#define GL_RGBA4_S3TC 0x83A3 -#define GL_RGBA_DXT5_S3TC 0x83A4 -#define GL_RGBA4_DXT5_S3TC 0x83A5 -#endif /* GL_S3_s3tc */ - -#ifndef GL_SGIS_detail_texture -#define GL_SGIS_detail_texture 1 -#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 -#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 -#define GL_LINEAR_DETAIL_SGIS 0x8097 -#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 -#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 -#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A -#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B -#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C -typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); -#endif -#endif /* GL_SGIS_detail_texture */ - -#ifndef GL_SGIS_fog_function -#define GL_SGIS_fog_function 1 -#define GL_FOG_FUNC_SGIS 0x812A -#define GL_FOG_FUNC_POINTS_SGIS 0x812B -#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C -typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); -#endif -#endif /* GL_SGIS_fog_function */ - -#ifndef GL_SGIS_generate_mipmap -#define GL_SGIS_generate_mipmap 1 -#define GL_GENERATE_MIPMAP_SGIS 0x8191 -#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 -#endif /* GL_SGIS_generate_mipmap */ - -#ifndef GL_SGIS_multisample -#define GL_SGIS_multisample 1 -#define GL_MULTISAMPLE_SGIS 0x809D -#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F -#define GL_SAMPLE_MASK_SGIS 0x80A0 -#define GL_1PASS_SGIS 0x80A1 -#define GL_2PASS_0_SGIS 0x80A2 -#define GL_2PASS_1_SGIS 0x80A3 -#define GL_4PASS_0_SGIS 0x80A4 -#define GL_4PASS_1_SGIS 0x80A5 -#define GL_4PASS_2_SGIS 0x80A6 -#define GL_4PASS_3_SGIS 0x80A7 -#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 -#define GL_SAMPLES_SGIS 0x80A9 -#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA -#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB -#define GL_SAMPLE_PATTERN_SGIS 0x80AC -typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); -#endif -#endif /* GL_SGIS_multisample */ - -#ifndef GL_SGIS_pixel_texture -#define GL_SGIS_pixel_texture 1 -#define GL_PIXEL_TEXTURE_SGIS 0x8353 -#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 -#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 -#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); -GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); -GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); -GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); -#endif -#endif /* GL_SGIS_pixel_texture */ - -#ifndef GL_SGIS_point_line_texgen -#define GL_SGIS_point_line_texgen 1 -#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 -#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 -#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 -#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 -#define GL_EYE_POINT_SGIS 0x81F4 -#define GL_OBJECT_POINT_SGIS 0x81F5 -#define GL_EYE_LINE_SGIS 0x81F6 -#define GL_OBJECT_LINE_SGIS 0x81F7 -#endif /* GL_SGIS_point_line_texgen */ - -#ifndef GL_SGIS_point_parameters -#define GL_SGIS_point_parameters 1 -#define GL_POINT_SIZE_MIN_SGIS 0x8126 -#define GL_POINT_SIZE_MAX_SGIS 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 -#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 -typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); -#endif -#endif /* GL_SGIS_point_parameters */ - -#ifndef GL_SGIS_sharpen_texture -#define GL_SGIS_sharpen_texture 1 -#define GL_LINEAR_SHARPEN_SGIS 0x80AD -#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE -#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF -#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 -typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); -#endif -#endif /* GL_SGIS_sharpen_texture */ - -#ifndef GL_SGIS_texture4D -#define GL_SGIS_texture4D 1 -#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 -#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 -#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 -#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 -#define GL_TEXTURE_4D_SGIS 0x8134 -#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 -#define GL_TEXTURE_4DSIZE_SGIS 0x8136 -#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 -#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 -#define GL_TEXTURE_4D_BINDING_SGIS 0x814F -typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); -#endif -#endif /* GL_SGIS_texture4D */ - -#ifndef GL_SGIS_texture_border_clamp -#define GL_SGIS_texture_border_clamp 1 -#define GL_CLAMP_TO_BORDER_SGIS 0x812D -#endif /* GL_SGIS_texture_border_clamp */ - -#ifndef GL_SGIS_texture_color_mask -#define GL_SGIS_texture_color_mask 1 -#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF -typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -#endif -#endif /* GL_SGIS_texture_color_mask */ - -#ifndef GL_SGIS_texture_edge_clamp -#define GL_SGIS_texture_edge_clamp 1 -#define GL_CLAMP_TO_EDGE_SGIS 0x812F -#endif /* GL_SGIS_texture_edge_clamp */ - -#ifndef GL_SGIS_texture_filter4 -#define GL_SGIS_texture_filter4 1 -#define GL_FILTER4_SGIS 0x8146 -#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 -typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); -typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); -GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); -#endif -#endif /* GL_SGIS_texture_filter4 */ - -#ifndef GL_SGIS_texture_lod -#define GL_SGIS_texture_lod 1 -#define GL_TEXTURE_MIN_LOD_SGIS 0x813A -#define GL_TEXTURE_MAX_LOD_SGIS 0x813B -#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C -#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D -#endif /* GL_SGIS_texture_lod */ - -#ifndef GL_SGIS_texture_select -#define GL_SGIS_texture_select 1 -#define GL_DUAL_ALPHA4_SGIS 0x8110 -#define GL_DUAL_ALPHA8_SGIS 0x8111 -#define GL_DUAL_ALPHA12_SGIS 0x8112 -#define GL_DUAL_ALPHA16_SGIS 0x8113 -#define GL_DUAL_LUMINANCE4_SGIS 0x8114 -#define GL_DUAL_LUMINANCE8_SGIS 0x8115 -#define GL_DUAL_LUMINANCE12_SGIS 0x8116 -#define GL_DUAL_LUMINANCE16_SGIS 0x8117 -#define GL_DUAL_INTENSITY4_SGIS 0x8118 -#define GL_DUAL_INTENSITY8_SGIS 0x8119 -#define GL_DUAL_INTENSITY12_SGIS 0x811A -#define GL_DUAL_INTENSITY16_SGIS 0x811B -#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C -#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D -#define GL_QUAD_ALPHA4_SGIS 0x811E -#define GL_QUAD_ALPHA8_SGIS 0x811F -#define GL_QUAD_LUMINANCE4_SGIS 0x8120 -#define GL_QUAD_LUMINANCE8_SGIS 0x8121 -#define GL_QUAD_INTENSITY4_SGIS 0x8122 -#define GL_QUAD_INTENSITY8_SGIS 0x8123 -#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 -#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 -#endif /* GL_SGIS_texture_select */ - -#ifndef GL_SGIX_async -#define GL_SGIX_async 1 -#define GL_ASYNC_MARKER_SGIX 0x8329 -typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); -typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); -typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); -typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); -GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); -GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); -GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); -GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); -GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); -#endif -#endif /* GL_SGIX_async */ - -#ifndef GL_SGIX_async_histogram -#define GL_SGIX_async_histogram 1 -#define GL_ASYNC_HISTOGRAM_SGIX 0x832C -#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D -#endif /* GL_SGIX_async_histogram */ - -#ifndef GL_SGIX_async_pixel -#define GL_SGIX_async_pixel 1 -#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C -#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D -#define GL_ASYNC_READ_PIXELS_SGIX 0x835E -#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F -#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 -#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 -#endif /* GL_SGIX_async_pixel */ - -#ifndef GL_SGIX_blend_alpha_minmax -#define GL_SGIX_blend_alpha_minmax 1 -#define GL_ALPHA_MIN_SGIX 0x8320 -#define GL_ALPHA_MAX_SGIX 0x8321 -#endif /* GL_SGIX_blend_alpha_minmax */ - -#ifndef GL_SGIX_calligraphic_fragment -#define GL_SGIX_calligraphic_fragment 1 -#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 -#endif /* GL_SGIX_calligraphic_fragment */ - -#ifndef GL_SGIX_clipmap -#define GL_SGIX_clipmap 1 -#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 -#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 -#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 -#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 -#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 -#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 -#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 -#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 -#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 -#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D -#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E -#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F -#endif /* GL_SGIX_clipmap */ - -#ifndef GL_SGIX_convolution_accuracy -#define GL_SGIX_convolution_accuracy 1 -#define GL_CONVOLUTION_HINT_SGIX 0x8316 -#endif /* GL_SGIX_convolution_accuracy */ - -#ifndef GL_SGIX_depth_pass_instrument -#define GL_SGIX_depth_pass_instrument 1 -#endif /* GL_SGIX_depth_pass_instrument */ - -#ifndef GL_SGIX_depth_texture -#define GL_SGIX_depth_texture 1 -#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 -#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 -#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 -#endif /* GL_SGIX_depth_texture */ - -#ifndef GL_SGIX_flush_raster -#define GL_SGIX_flush_raster 1 -typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushRasterSGIX (void); -#endif -#endif /* GL_SGIX_flush_raster */ - -#ifndef GL_SGIX_fog_offset -#define GL_SGIX_fog_offset 1 -#define GL_FOG_OFFSET_SGIX 0x8198 -#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 -#endif /* GL_SGIX_fog_offset */ - -#ifndef GL_SGIX_fragment_lighting -#define GL_SGIX_fragment_lighting 1 -#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 -#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 -#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 -#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 -#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 -#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 -#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 -#define GL_LIGHT_ENV_MODE_SGIX 0x8407 -#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 -#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 -#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A -#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B -#define GL_FRAGMENT_LIGHT0_SGIX 0x840C -#define GL_FRAGMENT_LIGHT1_SGIX 0x840D -#define GL_FRAGMENT_LIGHT2_SGIX 0x840E -#define GL_FRAGMENT_LIGHT3_SGIX 0x840F -#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 -#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 -#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 -#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 -typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); -GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); -GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); -GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); -GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); -#endif -#endif /* GL_SGIX_fragment_lighting */ - -#ifndef GL_SGIX_framezoom -#define GL_SGIX_framezoom 1 -#define GL_FRAMEZOOM_SGIX 0x818B -#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C -#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D -typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); -#endif -#endif /* GL_SGIX_framezoom */ - -#ifndef GL_SGIX_igloo_interface -#define GL_SGIX_igloo_interface 1 -typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params); -#endif -#endif /* GL_SGIX_igloo_interface */ - -#ifndef GL_SGIX_instruments -#define GL_SGIX_instruments 1 -#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 -#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 -typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); -typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); -typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); -typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); -typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); -typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); -GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); -GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); -GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); -GLAPI void APIENTRY glStartInstrumentsSGIX (void); -GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); -#endif -#endif /* GL_SGIX_instruments */ - -#ifndef GL_SGIX_interlace -#define GL_SGIX_interlace 1 -#define GL_INTERLACE_SGIX 0x8094 -#endif /* GL_SGIX_interlace */ - -#ifndef GL_SGIX_ir_instrument1 -#define GL_SGIX_ir_instrument1 1 -#define GL_IR_INSTRUMENT1_SGIX 0x817F -#endif /* GL_SGIX_ir_instrument1 */ - -#ifndef GL_SGIX_list_priority -#define GL_SGIX_list_priority 1 -#define GL_LIST_PRIORITY_SGIX 0x8182 -typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); -GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); -GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); -GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); -#endif -#endif /* GL_SGIX_list_priority */ - -#ifndef GL_SGIX_pixel_texture -#define GL_SGIX_pixel_texture 1 -#define GL_PIXEL_TEX_GEN_SGIX 0x8139 -#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B -typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); -#endif -#endif /* GL_SGIX_pixel_texture */ - -#ifndef GL_SGIX_pixel_tiles -#define GL_SGIX_pixel_tiles 1 -#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E -#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F -#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 -#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 -#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 -#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 -#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 -#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 -#endif /* GL_SGIX_pixel_tiles */ - -#ifndef GL_SGIX_polynomial_ffd -#define GL_SGIX_polynomial_ffd 1 -#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 -#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 -#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 -#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 -#define GL_DEFORMATIONS_MASK_SGIX 0x8196 -#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 -typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); -typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); -typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); -GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); -GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); -GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); -#endif -#endif /* GL_SGIX_polynomial_ffd */ - -#ifndef GL_SGIX_reference_plane -#define GL_SGIX_reference_plane 1 -#define GL_REFERENCE_PLANE_SGIX 0x817D -#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E -typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); -#endif -#endif /* GL_SGIX_reference_plane */ - -#ifndef GL_SGIX_resample -#define GL_SGIX_resample 1 -#define GL_PACK_RESAMPLE_SGIX 0x842C -#define GL_UNPACK_RESAMPLE_SGIX 0x842D -#define GL_RESAMPLE_REPLICATE_SGIX 0x842E -#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F -#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 -#endif /* GL_SGIX_resample */ - -#ifndef GL_SGIX_scalebias_hint -#define GL_SGIX_scalebias_hint 1 -#define GL_SCALEBIAS_HINT_SGIX 0x8322 -#endif /* GL_SGIX_scalebias_hint */ - -#ifndef GL_SGIX_shadow -#define GL_SGIX_shadow 1 -#define GL_TEXTURE_COMPARE_SGIX 0x819A -#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B -#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C -#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D -#endif /* GL_SGIX_shadow */ - -#ifndef GL_SGIX_shadow_ambient -#define GL_SGIX_shadow_ambient 1 -#define GL_SHADOW_AMBIENT_SGIX 0x80BF -#endif /* GL_SGIX_shadow_ambient */ - -#ifndef GL_SGIX_sprite -#define GL_SGIX_sprite 1 -#define GL_SPRITE_SGIX 0x8148 -#define GL_SPRITE_MODE_SGIX 0x8149 -#define GL_SPRITE_AXIS_SGIX 0x814A -#define GL_SPRITE_TRANSLATION_SGIX 0x814B -#define GL_SPRITE_AXIAL_SGIX 0x814C -#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D -#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E -typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); -GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); -GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); -#endif -#endif /* GL_SGIX_sprite */ - -#ifndef GL_SGIX_subsample -#define GL_SGIX_subsample 1 -#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 -#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 -#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 -#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 -#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 -#endif /* GL_SGIX_subsample */ - -#ifndef GL_SGIX_tag_sample_buffer -#define GL_SGIX_tag_sample_buffer 1 -typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTagSampleBufferSGIX (void); -#endif -#endif /* GL_SGIX_tag_sample_buffer */ - -#ifndef GL_SGIX_texture_add_env -#define GL_SGIX_texture_add_env 1 -#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE -#endif /* GL_SGIX_texture_add_env */ - -#ifndef GL_SGIX_texture_coordinate_clamp -#define GL_SGIX_texture_coordinate_clamp 1 -#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 -#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A -#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B -#endif /* GL_SGIX_texture_coordinate_clamp */ - -#ifndef GL_SGIX_texture_lod_bias -#define GL_SGIX_texture_lod_bias 1 -#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E -#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F -#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 -#endif /* GL_SGIX_texture_lod_bias */ - -#ifndef GL_SGIX_texture_multi_buffer -#define GL_SGIX_texture_multi_buffer 1 -#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E -#endif /* GL_SGIX_texture_multi_buffer */ - -#ifndef GL_SGIX_texture_scale_bias -#define GL_SGIX_texture_scale_bias 1 -#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 -#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A -#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B -#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C -#endif /* GL_SGIX_texture_scale_bias */ - -#ifndef GL_SGIX_vertex_preclip -#define GL_SGIX_vertex_preclip 1 -#define GL_VERTEX_PRECLIP_SGIX 0x83EE -#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF -#endif /* GL_SGIX_vertex_preclip */ - -#ifndef GL_SGIX_ycrcb -#define GL_SGIX_ycrcb 1 -#define GL_YCRCB_422_SGIX 0x81BB -#define GL_YCRCB_444_SGIX 0x81BC -#endif /* GL_SGIX_ycrcb */ - -#ifndef GL_SGIX_ycrcb_subsample -#define GL_SGIX_ycrcb_subsample 1 -#endif /* GL_SGIX_ycrcb_subsample */ - -#ifndef GL_SGIX_ycrcba -#define GL_SGIX_ycrcba 1 -#define GL_YCRCB_SGIX 0x8318 -#define GL_YCRCBA_SGIX 0x8319 -#endif /* GL_SGIX_ycrcba */ - -#ifndef GL_SGI_color_matrix -#define GL_SGI_color_matrix 1 -#define GL_COLOR_MATRIX_SGI 0x80B1 -#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 -#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 -#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 -#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 -#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 -#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 -#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 -#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 -#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA -#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB -#endif /* GL_SGI_color_matrix */ - -#ifndef GL_SGI_color_table -#define GL_SGI_color_table 1 -#define GL_COLOR_TABLE_SGI 0x80D0 -#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 -#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 -#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 -#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 -#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 -#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 -#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 -#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 -#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 -#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA -#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB -#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC -#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD -#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE -#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF -typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); -GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table); -GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); -#endif -#endif /* GL_SGI_color_table */ - -#ifndef GL_SGI_texture_color_table -#define GL_SGI_texture_color_table 1 -#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC -#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD -#endif /* GL_SGI_texture_color_table */ - -#ifndef GL_SUNX_constant_data -#define GL_SUNX_constant_data 1 -#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 -#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 -typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFinishTextureSUNX (void); -#endif -#endif /* GL_SUNX_constant_data */ - -#ifndef GL_SUN_convolution_border_modes -#define GL_SUN_convolution_border_modes 1 -#define GL_WRAP_BORDER_SUN 0x81D4 -#endif /* GL_SUN_convolution_border_modes */ - -#ifndef GL_SUN_global_alpha -#define GL_SUN_global_alpha 1 -#define GL_GLOBAL_ALPHA_SUN 0x81D9 -#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); -GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); -GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); -GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); -GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); -GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); -GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); -GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); -#endif -#endif /* GL_SUN_global_alpha */ - -#ifndef GL_SUN_mesh_array -#define GL_SUN_mesh_array 1 -#define GL_QUAD_MESH_SUN 0x8614 -#define GL_TRIANGLE_MESH_SUN 0x8615 -typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); -#endif -#endif /* GL_SUN_mesh_array */ - -#ifndef GL_SUN_slice_accum -#define GL_SUN_slice_accum 1 -#define GL_SLICE_ACCUM_SUN 0x85CC -#endif /* GL_SUN_slice_accum */ - -#ifndef GL_SUN_triangle_list -#define GL_SUN_triangle_list 1 -#define GL_RESTART_SUN 0x0001 -#define GL_REPLACE_MIDDLE_SUN 0x0002 -#define GL_REPLACE_OLDEST_SUN 0x0003 -#define GL_TRIANGLE_LIST_SUN 0x81D7 -#define GL_REPLACEMENT_CODE_SUN 0x81D8 -#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 -#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 -#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 -#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 -#define GL_R1UI_V3F_SUN 0x85C4 -#define GL_R1UI_C4UB_V3F_SUN 0x85C5 -#define GL_R1UI_C3F_V3F_SUN 0x85C6 -#define GL_R1UI_N3F_V3F_SUN 0x85C7 -#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 -#define GL_R1UI_T2F_V3F_SUN 0x85C9 -#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA -#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); -GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); -GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); -GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); -GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); -GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); -GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer); -#endif -#endif /* GL_SUN_triangle_list */ - -#ifndef GL_SUN_vertex -#define GL_SUN_vertex 1 -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); -GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -#endif -#endif /* GL_SUN_vertex */ - -#ifndef GL_WIN_phong_shading -#define GL_WIN_phong_shading 1 -#define GL_PHONG_WIN 0x80EA -#define GL_PHONG_HINT_WIN 0x80EB -#endif /* GL_WIN_phong_shading */ - -#ifndef GL_WIN_specular_fog -#define GL_WIN_specular_fog 1 -#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC -#endif /* GL_WIN_specular_fog */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/engine/thirdparty/stb/tests/caveview/glext_list.h b/source/engine/thirdparty/stb/tests/caveview/glext_list.h deleted file mode 100644 index 5cdbca5..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/glext_list.h +++ /dev/null @@ -1,34 +0,0 @@ -GLARB(ActiveTexture,ACTIVETEXTURE) -GLARB(ClientActiveTexture,CLIENTACTIVETEXTURE) -GLARB(MultiTexCoord2f,MULTITEXCOORD2F) -GLEXT(TexImage3D,TEXIMAGE3D) -GLEXT(TexSubImage3D,TEXSUBIMAGE3D) -GLEXT(GenerateMipmap,GENERATEMIPMAP) -GLARB(DebugMessageCallback,DEBUGMESSAGECALLBACK) - -GLCORE(VertexAttribIPointer,VERTEXATTRIBIPOINTER) - -GLEXT(BindFramebuffer,BINDFRAMEBUFFER) -GLEXT(DeleteFramebuffers,DELETEFRAMEBUFFERS) -GLEXT(GenFramebuffers,GENFRAMEBUFFERS) -GLEXT(CheckFramebufferStatus,CHECKFRAMEBUFFERSTATUS) -GLEXT(FramebufferTexture2D,FRAMEBUFFERTEXTURE2D) -GLEXT(BindRenderBuffer,BINDRENDERBUFFER) -GLEXT(RenderbufferStorage,RENDERBUFFERSTORAGE) -GLEXT(GenRenderbuffers,GENRENDERBUFFERS) -GLEXT(BindRenderbuffer,BINDRENDERBUFFER) -GLEXT(FramebufferRenderbuffer,FRAMEBUFFERRENDERBUFFER) -GLEXT(GenerateMipmap,GENERATEMIPMAP) - -GLARB(BindBuffer ,BINDBUFFER,) -GLARB(GenBuffers ,GENBUFFERS ) -GLARB(DeleteBuffers,DELETEBUFFERS) -GLARB(BufferData ,BUFFERDATA ) -GLARB(BufferSubData,BUFFERSUBDATA) -GLARB(MapBuffer ,MAPBUFFER ) -GLARB(UnmapBuffer ,UNMAPBUFFER ) -GLARB(TexBuffer ,TEXBUFFER ) - -GLEXT(NamedBufferStorage,NAMEDBUFFERSTORAGE) -GLE(BufferStorage,BUFFERSTORAGE) -GLE(GetStringi,GETSTRINGI) \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/caveview/main.c b/source/engine/thirdparty/stb/tests/caveview/main.c deleted file mode 100644 index e69de29..0000000 diff --git a/source/engine/thirdparty/stb/tests/caveview/stb_gl.h b/source/engine/thirdparty/stb/tests/caveview/stb_gl.h deleted file mode 100644 index 6498e28..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/stb_gl.h +++ /dev/null @@ -1,1103 +0,0 @@ -// stbgl - v0.04 - Sean Barrett 2008 - public domain -// -// Note that the gl extensions support requires glext.h. In fact, it works -// if you just concatenate glext.h onto the end of this file. In that case, -// this file is covered by the SGI FreeB license, and is not public domain. -// -// Extension usage: -// -// 1. Make a file called something like "extlist.txt" which contains stuff like: -// GLE(ShaderSourceARB,SHADERSOURCEARB) -// GLE(Uniform1iARB,UNIFORM1IARB) -// GLARB(ActiveTexture,ACTIVETEXTURE) // same as GLE(ActiveTextureARB,ACTIVETEXTUREARB) -// GLARB(ClientActiveTexture,CLIENTACTIVETEXTURE) -// GLE(MultiTexCoord2f,MULTITEXCOORD2F) -// -// 2. To declare functions (to make a header file), do this: -// #define STB_GLEXT_DECLARE "extlist.txt" -// #include "stb_gl.h" -// -// A good way to do this is to define STB_GLEXT_DECLARE project-wide. -// -// 3. To define functions (implement), do this in some C file: -// #define STB_GLEXT_DEFINE "extlist.txt" -// #include "stb_gl.h" -// -// If you've already defined STB_GLEXT_DECLARE, you can just do: -// #define STB_GLEXT_DEFINE_DECLARE -// #include "stb_gl.h" -// -// 4. Now you need to initialize: -// -// stbgl_initExtensions(); - - -#ifndef INCLUDE_STB_GL_H -#define INCLUDE_STB_GL_H - -#define STB_GL - -#ifdef _WIN32 -#ifndef WINGDIAPI -#define CALLBACK __stdcall -#define WINGDIAPI __declspec(dllimport) -#define APIENTRY __stdcall -#endif -#endif //_WIN32 - -#include - -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846f -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// like gluPerspective, but: -// fov is chosen to satisfy both hfov <= max_hfov & vfov <= max_vfov; -// set one to 179 or 0 to ignore it -// zoom is applied separately, so you can do linear zoom without -// mucking with trig with fov; 1 -> use exact fov -// 'aspect' is inferred from the current viewport, and ignores the -// possibility of non-square pixels -extern void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar); -extern void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float max_hfov, float max_vfov, float znear, float zfar); -extern void stbgl_initCamera_zup_facing_x(void); -extern void stbgl_initCamera_zup_facing_y(void); -extern void stbgl_positionCameraWithEulerAngles(float *loc, float *ang); -extern void stbgl_drawRect(float x0, float y0, float x1, float y1); -extern void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1); -extern void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw); - -extern int stbgl_hasExtension(char *ext); -extern void stbgl_SimpleLight(int index, float bright, float x, float y, float z); -extern void stbgl_GlobalAmbient(float r, float g, float b); - -extern int stbgl_LoadTexture(char *filename, char *props); // only if stb_image is available - -extern int stbgl_TestTexture(int w); -extern int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2); -extern unsigned int stbgl_rand(void); // internal, but exposed just in case; LCG, so use middle bits - -extern int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props); -extern int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data); -// "props" is a series of characters (and blocks of characters), a la fopen()'s mode, -// e.g.: -// GLuint texid = stbgl_LoadTexture("myfile.jpg", "mbc") -// means: load the image "myfile.jpg", and do the following: -// generate mipmaps -// use bilinear filtering (not trilinear) -// use clamp-to-edge on both channels -// -// input descriptor: AT MOST ONE -// TEXT MEANING -// 1 1 channel of input (intensity/alpha) -// 2 2 channels of input (luminance, alpha) -// 3 3 channels of input (RGB) -// 4 4 channels of input (RGBA) -// l 1 channel of input (luminance) -// a 1 channel of input (alpha) -// la 2 channels of input (lum/alpha) -// rgb 3 channels of input (RGB) -// ycocg 3 channels of input (YCoCg - forces YCoCg output) -// ycocgj 4 channels of input (YCoCgJunk - forces YCoCg output) -// rgba 4 channels of input (RGBA) -// -// output descriptor: AT MOST ONE -// TEXT MEANING -// A 1 channel of output (alpha) -// I 1 channel of output (intensity) -// LA 2 channels of output (lum/alpha) -// RGB 3 channels of output (RGB) -// RGBA 4 channels of output (RGBA) -// DXT1 encode as a DXT1 texture (RGB unless input has RGBA) -// DXT3 encode as a DXT3 texture -// DXT5 encode as a DXT5 texture -// YCoCg encode as a DXT5 texture with Y in alpha, CoCg in RG -// D GL_DEPTH_COMPONENT -// NONE no input/output, don't call TexImage2D at all -// -// when reading from a file or using another interface with an explicit -// channel count, the input descriptor is ignored and instead the channel -// count is used as the input descriptor. if the file read is a DXT DDS, -// then it is passed directly to OpenGL in the file format. -// -// if an input descriptor is supplied but no output descriptor, the output -// is assumed to be the same as the input. if an output descriptor is supplied -// but no input descriptor, the input is assumed to be the same as the -// output. if neither is supplied, the input is assumed to be 4-channel. -// If DXT1 or YCoCG output is requested with no input, the input is assumed -// to be 4-channel but the alpha channel is ignored. -// -// filtering descriptor (default is no mipmaps) -// TEXT MEANING -// m generate mipmaps -// M mipmaps are provided, concatenated at end of data (from largest to smallest) -// t use trilinear filtering (default if mipmapped) -// b use bilinear filtering (default if not-mipmapped) -// n use nearest-neighbor sampling -// -// wrapping descriptor -// TEXT MEANING -// w wrap (default) -// c clamp-to-edge -// C GL_CLAMP (uses border color) -// -// If only one wrapping descriptor is supplied, it is applied to both channels. -// -// special: -// TEXT MEANING -// f input data is floats (default unsigned bytes) -// F input&output data is floats (default unsigned bytes) -// p explicitly pre-multiply the alpha -// P pad to power-of-two (default stretches) -// NP2 non-power-of-two -// + can overwrite the texture data with temp data -// ! free the texture data with "free" -// -// the properties string can also include spaces - -#ifdef __cplusplus -} -#endif - - -#ifdef STB_GL_IMPLEMENTATION -#include -#include -#include -#include - -int stbgl_hasExtension(char *ext) -{ - const char *s = glGetString(GL_EXTENSIONS); - for(;;) { - char *e = ext; - for (;;) { - if (*e == 0) { - if (*s == 0 || *s == ' ') return 1; - break; - } - if (*s != *e) - break; - ++s, ++e; - } - while (*s && *s != ' ') ++s; - if (!*s) return 0; - ++s; // skip space - } -} - -void stbgl_drawRect(float x0, float y0, float x1, float y1) -{ - glBegin(GL_POLYGON); - glTexCoord2f(0,0); glVertex2f(x0,y0); - glTexCoord2f(1,0); glVertex2f(x1,y0); - glTexCoord2f(1,1); glVertex2f(x1,y1); - glTexCoord2f(0,1); glVertex2f(x0,y1); - glEnd(); -} - -void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1) -{ - glBegin(GL_POLYGON); - glTexCoord2f(s0,t0); glVertex2f(x0,y0); - glTexCoord2f(s1,t0); glVertex2f(x1,y0); - glTexCoord2f(s1,t1); glVertex2f(x1,y1); - glTexCoord2f(s0,t1); glVertex2f(x0,y1); - glEnd(); -} - -void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw) -{ - float x0,y0,z0,x1,y1,z1; - sx /=2, sy/=2, sz/=2; - x0 = x-sx; y0 = y-sy; z0 = z-sz; - x1 = x+sx; y1 = y+sy; z1 = z+sz; - - glBegin(GL_QUADS); - if (cw) { - glNormal3f(0,0,-1); - glTexCoord2f(0,0); glVertex3f(x0,y0,z0); - glTexCoord2f(1,0); glVertex3f(x1,y0,z0); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - - glNormal3f(0,0,1); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - glTexCoord2f(1,1); glVertex3f(x0,y1,z1); - glTexCoord2f(0,1); glVertex3f(x1,y1,z1); - - glNormal3f(-1,0,0); - glTexCoord2f(0,0); glVertex3f(x0,y1,z1); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - glTexCoord2f(1,1); glVertex3f(x0,y0,z0); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - - glNormal3f(1,0,0); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(1,0); glVertex3f(x1,y1,z1); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(0,1); glVertex3f(x1,y0,z0); - - glNormal3f(0,-1,0); - glTexCoord2f(0,0); glVertex3f(x0,y0,z1); - glTexCoord2f(1,0); glVertex3f(x1,y0,z1); - glTexCoord2f(1,1); glVertex3f(x1,y0,z0); - glTexCoord2f(0,1); glVertex3f(x0,y0,z0); - - glNormal3f(0,1,0); - glTexCoord2f(0,0); glVertex3f(x1,y1,z1); - glTexCoord2f(1,0); glVertex3f(x0,y1,z1); - glTexCoord2f(1,1); glVertex3f(x0,y1,z0); - glTexCoord2f(0,1); glVertex3f(x1,y1,z0); - } else { - glNormal3f(0,0,-1); - glTexCoord2f(0,0); glVertex3f(x0,y0,z0); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(1,0); glVertex3f(x1,y0,z0); - - glNormal3f(0,0,1); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(0,1); glVertex3f(x1,y1,z1); - glTexCoord2f(1,1); glVertex3f(x0,y1,z1); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - - glNormal3f(-1,0,0); - glTexCoord2f(0,0); glVertex3f(x0,y1,z1); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - glTexCoord2f(1,1); glVertex3f(x0,y0,z0); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - - glNormal3f(1,0,0); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(0,1); glVertex3f(x1,y0,z0); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(1,0); glVertex3f(x1,y1,z1); - - glNormal3f(0,-1,0); - glTexCoord2f(0,0); glVertex3f(x0,y0,z1); - glTexCoord2f(0,1); glVertex3f(x0,y0,z0); - glTexCoord2f(1,1); glVertex3f(x1,y0,z0); - glTexCoord2f(1,0); glVertex3f(x1,y0,z1); - - glNormal3f(0,1,0); - glTexCoord2f(0,0); glVertex3f(x1,y1,z1); - glTexCoord2f(0,1); glVertex3f(x1,y1,z0); - glTexCoord2f(1,1); glVertex3f(x0,y1,z0); - glTexCoord2f(1,0); glVertex3f(x0,y1,z1); - } - glEnd(); -} - -void stbgl_SimpleLight(int index, float bright, float x, float y, float z) -{ - float d = (float) (1.0f/sqrt(x*x+y*y+z*z)); - float dir[4] = { x*d,y*d,z*d,0 }, zero[4] = { 0,0,0,0 }; - float c[4] = { bright,bright,bright,0 }; - GLuint light = GL_LIGHT0 + index; - glLightfv(light, GL_POSITION, dir); - glLightfv(light, GL_DIFFUSE, c); - glLightfv(light, GL_AMBIENT, zero); - glLightfv(light, GL_SPECULAR, zero); - glEnable(light); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); -} - -void stbgl_GlobalAmbient(float r, float g, float b) -{ - float v[4] = { r,g,b,0 }; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v); -} - - -#define stbgl_rad2deg(r) ((r)*180.0f / M_PI) -#define stbgl_deg2rad(r) ((r)/180.0f * M_PI) - -void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar) -{ - float unit_width, unit_height, aspect, vfov; - int data[4],w,h; - glGetIntegerv(GL_VIEWPORT, data); - w = data[2]; - h = data[3]; - aspect = (float) w / h; - - if (max_hfov <= 0) max_hfov = 179; - if (max_vfov <= 0) max_vfov = 179; - - // convert max_hfov, max_vfov to worldspace width at depth=1 - unit_width = (float) tan(stbgl_deg2rad(max_hfov/2)) * 2; - unit_height = (float) tan(stbgl_deg2rad(max_vfov/2)) * 2; - // check if hfov = max_hfov is enough to satisfy it - if (unit_width <= aspect * unit_height) { - float height = unit_width / aspect; - vfov = (float) atan(( height/2) / zoom); - } else { - vfov = (float) atan((unit_height/2) / zoom); - } - vfov = (float) stbgl_rad2deg(vfov * 2); - gluPerspective(vfov, aspect, znear, zfar); -} - -void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float min_hfov, float min_vfov, float znear, float zfar) -{ - if (znear <= 0.0001f) znear = 0.0001f; - glViewport(x,y,w,h); - glScissor(x,y,w,h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - stbgl_Perspective(zoom, min_hfov, min_vfov, znear, zfar); - glMatrixMode(GL_MODELVIEW); -} - -// point the camera along the positive X axis, Z-up -void stbgl_initCamera_zup_facing_x(void) -{ - glRotatef(-90, 1,0,0); - glRotatef( 90, 0,0,1); -} - -// point the camera along the positive Y axis, Z-up -void stbgl_initCamera_zup_facing_y(void) -{ - glRotatef(-90, 1,0,0); -} - -// setup a camera using Euler angles -void stbgl_positionCameraWithEulerAngles(float *loc, float *ang) -{ - glRotatef(-ang[1], 0,1,0); - glRotatef(-ang[0], 1,0,0); - glRotatef(-ang[2], 0,0,1); - glTranslatef(-loc[0], -loc[1], -loc[2]); -} - -static int stbgl_m(char *a, char *b) -{ - // skip first character - do { ++a,++b; } while (*b && *a == *b); - return *b == 0; -} - -#ifdef STBI_VERSION -#ifndef STBI_NO_STDIO -int stbgl_LoadTexture(char *filename, char *props) -{ - // @TODO: handle DDS files directly - int res; - void *data; - int w,h,c; - #ifndef STBI_NO_HDR - if (stbi_is_hdr(filename)) { - data = stbi_loadf(filename, &w, &h, &c, 0); - if (!data) return 0; - res = stbgl_TexImage2D_Extra(0, w,h,data, -c, props, 0); - free(data); - return res; - } - #endif - - data = stbi_load(filename, &w, &h, &c, 0); - if (!data) return 0; - res = stbgl_TexImage2D_Extra(0, w,h,data, c, props, 0); - free(data); - return res; -} -#endif -#endif // STBI_VERSION - -int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props) -{ - return stbgl_TexImage2D_Extra(texid, w, h, data, 0, props,1); -} - -int stbgl_TestTexture(int w) -{ - char scale_table[] = { 10,20,30,30,35,40,5,18,25,13,7,5,3,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0 }; - return stbgl_TestTextureEx(w, scale_table, 2, 140,130,200, 180,200,170); -} - -unsigned int stbgl_rand(void) -{ - static unsigned int stbgl__rand_seed = 3248980923; // random typing - return stbgl__rand_seed = stbgl__rand_seed * 2147001325 + 715136305; // BCPL generator -} - -// wish this could be smaller, since it's so frivolous -int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2) -{ - int rt[2] = {r1,r2}, gt[2] = {g1,g2}, bt[2] = {b1,b2}; - signed char modded[256]; - int i,j, m = w-1, s,k,scale; - unsigned char *data = (unsigned char *) malloc(w*w*3); - assert((m & w) == 0); - data[0] = 128; - for (s=0; s < 16; ++s) if ((1 << s) == w) break; - assert(w == (1 << s)); - // plasma fractal noise - for (k=s-1; k >= 0; --k) { - int step = 1 << k; - // interpolate from "parents" - for (j=0; j < w; j += step*2) { - for (i=0; i < w; i += step*2) { - int i1 = i+step, j1=j+step; - int i2 = (i+step*2)&m, j2 = (j+step*2)&m; - int p00 = data[(j*w+i )*3], p01 = data[(j2*w+i )*3]; - int p10 = data[(j*w+i2)*3], p11 = data[(j2*w+i2)*3]; - data[(j*w+i1)*3] = (p00+p10)>>1; - data[(j1*w+i)*3] = (p00+p01)>>1; - data[(j1*w+i1)*3]= (p00+p01+p10+p11)>>2; - } - } - scale = scale_table[s-k+1]; - if (!scale) continue; // just interpolate down the remaining data - for (j=0,i=0; i < 256; i += 2, j == scale ? j=0 : ++j) - modded[i] = j, modded[i+1] = -j; // precompute i%scale (plus sign) - for (j=0; j < w; j += step) - for (i=0; i < w; i += step) { - int x = data[(j*w+i)*3] + modded[(stbgl_rand() >> 12) & 255]; - data[(j*w+i)*3] = x < 0 ? 0 : x > 255 ? 255 : x; - } - } - for (j=0; j < w; ++j) - for (i=0; i < w; ++i) { - int check = ((i^j) & (1 << (s-checks_log2))) == 0; - int v = data[(j*w+i)*3] >> 2; - data[(j*w+i)*3+0] = rt[check]-v; - data[(j*w+i)*3+1] = gt[check]-v; - data[(j*w+i)*3+2] = bt[check]-v; - } - return stbgl_TexImage2D(0, w, w, data, "3m!"); // 3 channels, mipmap, free -} - -#ifdef _WIN32 -#ifndef WINGDIAPI -typedef int (__stdcall *stbgl__voidfunc)(void); -__declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *); -#endif -#define STB__HAS_WGLPROC -static void (__stdcall *stbgl__CompressedTexImage2DARB)(int target, int level, - int internalformat, int width, - int height, int border, - int imageSize, void *data); -static void stbgl__initCompTex(void) -{ - *((void **) &stbgl__CompressedTexImage2DARB) = (void *) wglGetProcAddress("glCompressedTexImage2DARB"); -} -#else -static void (*stbgl__CompressedTexImage2DARB)(int target, int level, - int internalformat, int width, - int height, int border, - int imageSize, void *data); -static void stbgl__initCompTex(void) -{ -} -#endif // _WIN32 - -#define STBGL_COMPRESSED_RGB_S3TC_DXT1 0x83F0 -#define STBGL_COMPRESSED_RGBA_S3TC_DXT1 0x83F1 -#define STBGL_COMPRESSED_RGBA_S3TC_DXT3 0x83F2 -#define STBGL_COMPRESSED_RGBA_S3TC_DXT5 0x83F3 - -#ifdef STB_COMPRESS_DXT_BLOCK -static void stbgl__convert(uint8 *p, uint8 *q, int n, int input_desc, uint8 *end) -{ - int i; - switch (input_desc) { - case GL_RED: - case GL_LUMINANCE: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = q[0], p[3]=255, q+=1; break; - case GL_ALPHA: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = 0, p[3] = q[0], q+=1; break; - case GL_LUMINANCE_ALPHA: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = q[0], p[3]=q[1], q+=2; break; - case GL_RGB: for (i=0; i < n; ++i,p+=4) p[0]=q[0],p[1]=q[1],p[2]=q[2],p[3]=255,q+=3; break; - case GL_RGBA: memcpy(p, q, n*4); break; - case GL_INTENSITY: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = p[3] = q[0], q+=1; break; - } - assert(p <= end); -} - -static void stbgl__compress(uint8 *p, uint8 *rgba, int w, int h, int output_desc, uint8 *end) -{ - int i,j,y,y2; - int alpha = (output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT5); - for (j=0; j < w; j += 4) { - int x=4; - for (i=0; i < h; i += 4) { - uint8 block[16*4]; - if (i+3 >= w) x = w-i; - for (y=0; y < 4; ++y) { - if (j+y >= h) break; - memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4); - } - if (x < 4) { - switch (x) { - case 0: assert(0); - case 1: - for (y2=0; y2 < y; ++y2) { - memcpy(block+y2*16+1*4, block+y2*16+0*4, 4); - memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); - } - break; - case 2: - for (y2=0; y2 < y; ++y2) - memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); - break; - case 3: - for (y2=0; y2 < y; ++y2) - memcpy(block+y2*16+3*4, block+y2*16+1*4, 4); - break; - } - } - y2 = 0; - for(; y<4; ++y,++y2) - memcpy(block+y*16, block+y2*16, 4*4); - stb_compress_dxt_block(p, block, alpha, 10); - p += alpha ? 16 : 8; - } - } - assert(p <= end); -} -#endif // STB_COMPRESS_DXT_BLOCK - -// use the reserved temporary-use enumerant range, since no -// OpenGL enumerants should fall in that range -enum -{ - STBGL_UNDEFINED = 0x6000, - STBGL_YCOCG, - STBGL_YCOCGJ, - STBGL_GEN_MIPMAPS, - STBGL_MIPMAPS, - STBGL_NO_DOWNLOAD, -}; - -#define STBGL_CLAMP_TO_EDGE 0x812F -#define STBGL_CLAMP_TO_BORDER 0x812D - -#define STBGL_DEPTH_COMPONENT16 0x81A5 -#define STBGL_DEPTH_COMPONENT24 0x81A6 -#define STBGL_DEPTH_COMPONENT32 0x81A7 - -int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data) -{ - static int has_s3tc = -1; // haven't checked yet - int free_data = 0, is_compressed = 0; - int pad_to_power_of_two = 0, non_power_of_two = 0; - int premultiply_alpha = 0; // @TODO - int float_tex = 0; // @TODO - int input_type = GL_UNSIGNED_BYTE; - int input_desc = STBGL_UNDEFINED; - int output_desc = STBGL_UNDEFINED; - int mipmaps = STBGL_UNDEFINED; - int filter = STBGL_UNDEFINED, mag_filter; - int wrap_s = STBGL_UNDEFINED, wrap_t = STBGL_UNDEFINED; - - // parse out the properties - if (props == NULL) props = ""; - while (*props) { - switch (*props) { - case '1' : input_desc = GL_LUMINANCE; break; - case '2' : input_desc = GL_LUMINANCE_ALPHA; break; - case '3' : input_desc = GL_RGB; break; - case '4' : input_desc = GL_RGBA; break; - case 'l' : if (props[1] == 'a') { input_desc = GL_LUMINANCE_ALPHA; ++props; } - else input_desc = GL_LUMINANCE; - break; - case 'a' : input_desc = GL_ALPHA; break; - case 'r' : if (stbgl_m(props, "rgba")) { input_desc = GL_RGBA; props += 3; break; } - if (stbgl_m(props, "rgb")) { input_desc = GL_RGB; props += 2; break; } - input_desc = GL_RED; - break; - case 'y' : if (stbgl_m(props, "ycocg")) { - if (props[5] == 'j') { props += 5; input_desc = STBGL_YCOCGJ; } - else { props += 4; input_desc = STBGL_YCOCG; } - break; - } - return 0; - case 'L' : if (props[1] == 'A') { output_desc = GL_LUMINANCE_ALPHA; ++props; } - else output_desc = GL_LUMINANCE; - break; - case 'I' : output_desc = GL_INTENSITY; break; - case 'A' : output_desc = GL_ALPHA; break; - case 'R' : if (stbgl_m(props, "RGBA")) { output_desc = GL_RGBA; props += 3; break; } - if (stbgl_m(props, "RGB")) { output_desc = GL_RGB; props += 2; break; } - output_desc = GL_RED; - break; - case 'Y' : if (stbgl_m(props, "YCoCg") || stbgl_m(props, "YCOCG")) { - props += 4; - output_desc = STBGL_YCOCG; - break; - } - return 0; - case 'D' : if (stbgl_m(props, "DXT")) { - switch (props[3]) { - case '1': output_desc = STBGL_COMPRESSED_RGB_S3TC_DXT1; break; - case '3': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT3; break; - case '5': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5; break; - default: return 0; - } - props += 3; - } else if (stbgl_m(props, "D16")) { - output_desc = STBGL_DEPTH_COMPONENT16; - input_desc = GL_DEPTH_COMPONENT; - props += 2; - } else if (stbgl_m(props, "D24")) { - output_desc = STBGL_DEPTH_COMPONENT24; - input_desc = GL_DEPTH_COMPONENT; - props += 2; - } else if (stbgl_m(props, "D32")) { - output_desc = STBGL_DEPTH_COMPONENT32; - input_desc = GL_DEPTH_COMPONENT; - props += 2; - } else { - output_desc = GL_DEPTH_COMPONENT; - input_desc = GL_DEPTH_COMPONENT; - } - break; - case 'N' : if (stbgl_m(props, "NONE")) { - props += 3; - input_desc = STBGL_NO_DOWNLOAD; - output_desc = STBGL_NO_DOWNLOAD; - break; - } - if (stbgl_m(props, "NP2")) { - non_power_of_two = 1; - props += 2; - break; - } - return 0; - case 'm' : mipmaps = STBGL_GEN_MIPMAPS; break; - case 'M' : mipmaps = STBGL_MIPMAPS; break; - case 't' : filter = GL_LINEAR_MIPMAP_LINEAR; break; - case 'b' : filter = GL_LINEAR; break; - case 'n' : filter = GL_NEAREST; break; - case 'w' : if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT; else wrap_t = GL_REPEAT; break; - case 'C' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_BORDER; else wrap_t = STBGL_CLAMP_TO_BORDER; break; - case 'c' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_EDGE; else wrap_t = STBGL_CLAMP_TO_EDGE; break; - case 'f' : input_type = GL_FLOAT; break; - case 'F' : input_type = GL_FLOAT; float_tex = 1; break; - case 'p' : premultiply_alpha = 1; break; - case 'P' : pad_to_power_of_two = 1; break; - case '+' : preserve_data = 0; break; - case '!' : preserve_data = 0; free_data = 1; break; - case ' ' : break; - case '-' : break; - default : if (free_data) free(data); - return 0; - } - ++props; - } - - // override input_desc based on channel count - if (output_desc != STBGL_NO_DOWNLOAD) { - switch (abs(chan)) { - case 1: input_desc = GL_LUMINANCE; break; - case 2: input_desc = GL_LUMINANCE_ALPHA; break; - case 3: input_desc = GL_RGB; break; - case 4: input_desc = GL_RGBA; break; - case 0: break; - default: return 0; - } - } - - // override input_desc based on channel info - if (chan > 0) { input_type = GL_UNSIGNED_BYTE; } - if (chan < 0) { input_type = GL_FLOAT; } - - if (output_desc == GL_ALPHA) { - if (input_desc == GL_LUMINANCE) - input_desc = GL_ALPHA; - if (input_desc == GL_RGB) { - // force a presumably-mono image to alpha - // @TODO handle 'preserve_data' case? - if (data && !preserve_data && input_type == GL_UNSIGNED_BYTE) { - int i; - unsigned char *p = (unsigned char *) data, *q = p; - for (i=0; i < w*h; ++i) { - *q = (p[0] + 2*p[1] + p[2]) >> 2; - p += 3; - q += 1; - } - input_desc = GL_ALPHA; - } - } - } - - // set undefined input/output based on the other - if (input_desc == STBGL_UNDEFINED && output_desc == STBGL_UNDEFINED) { - input_desc = output_desc = GL_RGBA; - } else if (output_desc == STBGL_UNDEFINED) { - switch (input_desc) { - case GL_LUMINANCE: - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_RGB: - case GL_RGBA: - output_desc = input_desc; - break; - case GL_RED: - output_desc = GL_INTENSITY; - break; - case STBGL_YCOCG: - case STBGL_YCOCGJ: - output_desc = STBGL_YCOCG; - break; - default: assert(0); return 0; - } - } else if (input_desc == STBGL_UNDEFINED) { - switch (output_desc) { - case GL_LUMINANCE: - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_RGB: - case GL_RGBA: - input_desc = output_desc; - break; - case GL_INTENSITY: - input_desc = GL_RED; - break; - case STBGL_YCOCG: - case STBGL_COMPRESSED_RGB_S3TC_DXT1: - case STBGL_COMPRESSED_RGBA_S3TC_DXT3: - case STBGL_COMPRESSED_RGBA_S3TC_DXT5: - input_desc = GL_RGBA; - break; - } - } else { - if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1) { - // if input has alpha, force output alpha - switch (input_desc) { - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5; - break; - } - } - } - - switch(input_desc) { - case GL_LUMINANCE: - case GL_RED: - case GL_ALPHA: - chan = 1; - break; - case GL_LUMINANCE_ALPHA: - chan = 2; - break; - case GL_RGB: - chan = 3; - break; - case GL_RGBA: - chan = 4; - break; - } - - if (pad_to_power_of_two && ((w & (w-1)) || (h & (h-1)))) { - if (output_desc != STBGL_NO_DOWNLOAD && input_type == GL_UNSIGNED_BYTE && chan > 0) { - unsigned char *new_data; - int w2 = w, h2 = h, j; - while (w & (w-1)) - w = (w | (w>>1))+1; - while (h & (h-1)) - h = (h | (h>>1))+1; - new_data = malloc(w * h * chan); - for (j=0; j < h2; ++j) { - memcpy(new_data + j * w * chan, (char *) data+j*w2*chan, w2*chan); - memset(new_data + (j * w+w2) * chan, 0, (w-w2)*chan); - } - for (; j < h; ++j) - memset(new_data + j*w*chan, 0, w*chan); - if (free_data) - free(data); - data = new_data; - free_data = 1; - } - } - - switch (output_desc) { - case STBGL_COMPRESSED_RGB_S3TC_DXT1: - case STBGL_COMPRESSED_RGBA_S3TC_DXT1: - case STBGL_COMPRESSED_RGBA_S3TC_DXT3: - case STBGL_COMPRESSED_RGBA_S3TC_DXT5: - is_compressed = 1; - if (has_s3tc == -1) { - has_s3tc = stbgl_hasExtension("GL_EXT_texture_compression_s3tc"); - if (has_s3tc) stbgl__initCompTex(); - } - if (!has_s3tc) { - is_compressed = 0; - if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1) - output_desc = GL_RGB; - else - output_desc = GL_RGBA; - } - } - - if (output_desc == STBGL_YCOCG) { - assert(0); - output_desc = GL_RGB; // @TODO! - if (free_data) free(data); - return 0; - } - - mag_filter = 0; - if (mipmaps != STBGL_UNDEFINED) { - switch (filter) { - case STBGL_UNDEFINED: filter = GL_LINEAR_MIPMAP_LINEAR; break; - case GL_NEAREST : mag_filter = GL_NEAREST; filter = GL_LINEAR_MIPMAP_LINEAR; break; - case GL_LINEAR : filter = GL_LINEAR_MIPMAP_NEAREST; break; - } - } else { - if (filter == STBGL_UNDEFINED) - filter = GL_LINEAR; - } - - // update filtering - if (!mag_filter) { - if (filter == GL_NEAREST) - mag_filter = GL_NEAREST; - else - mag_filter = GL_LINEAR; - } - - // update wrap/clamp - if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT; - if (wrap_t == STBGL_UNDEFINED) wrap_t = wrap_s; - - // if no texture id, generate one - if (texid == 0) { - GLuint tex; - glGenTextures(1, &tex); - if (tex == 0) { if (free_data) free(data); return 0; } - texid = tex; - } - - if (data == NULL && mipmaps == STBGL_GEN_MIPMAPS) - mipmaps = STBGL_MIPMAPS; - - if (output_desc == STBGL_NO_DOWNLOAD) - mipmaps = STBGL_NO_DOWNLOAD; - - glBindTexture(GL_TEXTURE_2D, texid); - -#ifdef STB_COMPRESS_DXT_BLOCK - if (!is_compressed || !stbgl__CompressedTexImage2DARB || output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT3 || data == NULL) -#endif - { - switch (mipmaps) { - case STBGL_NO_DOWNLOAD: - break; - - case STBGL_UNDEFINED: - // check if actually power-of-two - if (non_power_of_two || ((w & (w-1)) == 0 && (h & (h-1)) == 0)) - glTexImage2D(GL_TEXTURE_2D, 0, output_desc, w, h, 0, input_desc, input_type, data); - else - gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data); - // not power of two, so use glu to resize (generates mipmaps needlessly) - break; - - case STBGL_MIPMAPS: { - int level = 0; - int size = input_type == GL_FLOAT ? sizeof(float) : 1; - if (data == NULL) size = 0; // reuse same block of memory for all mipmaps - assert((w & (w-1)) == 0 && (h & (h-1)) == 0); // verify power-of-two - while (w > 1 && h > 1) { - glTexImage2D(GL_TEXTURE_2D, level, output_desc, w, h, 0, input_desc, input_type, data); - data = (void *) ((char *) data + w * h * size * chan); - if (w > 1) w >>= 1; - if (h > 1) h >>= 1; - ++level; - } - break; - } - case STBGL_GEN_MIPMAPS: - gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data); - break; - - default: - assert(0); - if (free_data) free(data); - return 0; - } -#ifdef STB_COMPRESS_DXT_BLOCK - } else { - uint8 *out, *rgba=0, *end_out, *end_rgba; - int level = 0, alpha = (output_desc != STBGL_COMPRESSED_RGB_S3TC_DXT1); - int size = input_type == GL_FLOAT ? sizeof(float) : 1; - int osize = alpha ? 16 : 8; - if (!free_data && mipmaps == STBGL_GEN_MIPMAPS) { - uint8 *temp = malloc(w*h*chan); - if (!temp) { if (free_data) free(data); return 0; } - memcpy(temp, data, w*h*chan); - if (free_data) free(data); - free_data = 1; - data = temp; - } - if (chan != 4 || size != 1) { - rgba = malloc(w*h*4); - if (!rgba) return 0; - end_rgba = rgba+w*h*4; - } - out = malloc((w+3)*(h+3)/16*osize); // enough storage for the s3tc data - if (!out) return 0; - end_out = out + ((w+3)*(h+3))/16*osize; - - for(;;) { - if (chan != 4) - stbgl__convert(rgba, data, w*h, input_desc, end_rgba); - stbgl__compress(out, rgba ? rgba : data, w, h, output_desc, end_out); - stbgl__CompressedTexImage2DARB(GL_TEXTURE_2D, level, output_desc, w, h, 0, ((w+3)&~3)*((h+3)&~3)/16*osize, out); - //glTexImage2D(GL_TEXTURE_2D, level, alpha?GL_RGBA:GL_RGB, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba ? rgba : data); - - if (mipmaps == STBGL_UNDEFINED) break; - if (w <= 1 && h <= 1) break; - if (mipmaps == STBGL_MIPMAPS) data = (void *) ((char *) data + w * h * size * chan); - if (mipmaps == STBGL_GEN_MIPMAPS) { - int w2 = w>>1, h2=h>>1, i,j,k, s=w*chan; - uint8 *p = data, *q=data; - if (w == 1) { - for (j=0; j < h2; ++j) { - for (k=0; k < chan; ++k) - *p++ = (q[k] + q[s+k] + 1) >> 1; - q += s*2; - } - } else if (h == 1) { - for (i=0; i < w2; ++i) { - for (k=0; k < chan; ++k) - *p++ = (q[k] + q[k+chan] + 1) >> 1; - q += chan*2; - } - } else { - for (j=0; j < h2; ++j) { - for (i=0; i < w2; ++i) { - for (k=0; k < chan; ++k) - *p++ = (q[k] + q[k+chan] + q[s+k] + q[s+k+chan] + 2) >> 2; - q += chan*2; - } - q += s; - } - } - } - if (w > 1) w >>= 1; - if (h > 1) h >>= 1; - ++level; - } - if (out) free(out); - if (rgba) free(rgba); -#endif // STB_COMPRESS_DXT_BLOCK - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - - if (free_data) free(data); - return texid; -} - -#endif // STB_DEFINE -#undef STB_EXTERN - -#endif //INCLUDE_STB_GL_H - -// Extension handling... must be outside the INCLUDE_ brackets - -#if defined(STB_GLEXT_DEFINE) || defined(STB_GLEXT_DECLARE) - -#ifndef STB_GLEXT_SKIP_DURING_RECURSION - -#ifndef GL_GLEXT_VERSION - - // First check if glext.h is concatenated on the end of this file - // (if it's concatenated on the beginning, we'll have GL_GLEXT_VERSION) - - #define STB_GLEXT_SKIP_DURING_RECURSION - #include __FILE__ - #undef STB_GLEXT_SKIP_DURING_RECURSION - - // now check if it's still undefined; if so, try going for it by name; - // if this errors, that's fine, since we can't compile without it - - #ifndef GL_GLEXT_VERSION - #include "glext.h" - #endif -#endif - -#define GLARB(a,b) GLE(a##ARB,b##ARB) -#define GLEXT(a,b) GLE(a##EXT,b##EXT) -#define GLNV(a,b) GLE(a##NV ,b##NV) -#define GLATI(a,b) GLE(a##ATI,b##ATI) -#define GLCORE(a,b) GLE(a,b) - -#ifdef STB_GLEXT_DEFINE_DECLARE -#define STB_GLEXT_DEFINE STB_GLEXT_DECLARE -#endif - -#if defined(STB_GLEXT_DECLARE) && defined(STB_GLEXT_DEFINE) -#undef STB_GLEXT_DECLARE -#endif - -#if defined(STB_GLEXT_DECLARE) && !defined(STB_GLEXT_DEFINE) - #define GLE(a,b) extern PFNGL##b##PROC gl##a; - - #ifdef __cplusplus - extern "C" { - #endif - - extern void stbgl_initExtensions(void); - - #include STB_GLEXT_DECLARE - - #ifdef __cplusplus - }; - #endif - -#else - - #ifndef STB_GLEXT_DEFINE - #error "Header file is screwed up somehow" - #endif - - #ifdef _WIN32 - #ifndef WINGDIAPI - #ifndef STB__HAS_WGLPROC - typedef int (__stdcall *stbgl__voidfunc)(void); - __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *); - #endif - #endif - #define STBGL__GET_FUNC(x) wglGetProcAddress(x) - #endif - - #ifdef GLE - #undef GLE - #endif - - #define GLE(a,b) PFNGL##b##PROC gl##a; - #include STB_GLEXT_DEFINE - - #undef GLE - #define GLE(a,b) gl##a = (PFNGL##b##PROC) STBGL__GET_FUNC("gl" #a ); - - void stbgl_initExtensions(void) - { - #include STB_GLEXT_DEFINE - } - - #undef GLE - -#endif // STB_GLEXT_DECLARE - -#endif // STB_GLEXT_SKIP - -#endif // STB_GLEXT_DEFINE || STB_GLEXT_DECLARE diff --git a/source/engine/thirdparty/stb/tests/caveview/stb_glprog.h b/source/engine/thirdparty/stb/tests/caveview/stb_glprog.h deleted file mode 100644 index 8883a3e..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/stb_glprog.h +++ /dev/null @@ -1,504 +0,0 @@ -// stb_glprog v0.02 public domain functions to reduce GLSL boilerplate -// http://nothings.org/stb/stb_glprog.h especially with GL1 + ARB extensions -// -// Following defines *before* including have following effects: -// -// STB_GLPROG_IMPLEMENTATION -// creates the implementation -// -// STB_GLPROG_STATIC -// forces the implementation to be static (private to file that creates it) -// -// STB_GLPROG_ARB -// uses ARB extension names for GLSL functions and enumerants instead of core names -// -// STB_GLPROG_ARB_DEFINE_EXTENSIONS -// instantiates function pointers needed, static to implementing file -// to avoid collisions (but will collide if implementing file also -// defines any; best to isolate this to its own file in this case). -// This will try to automatically #include glext.h, but if it's not -// in the default include directories you'll need to include it -// yourself and define the next macro. -// -// STB_GLPROG_SUPPRESS_GLEXT_INCLUDE -// disables the automatic #include of glext.h which is normally -// forced by STB_GLPROG_ARB_DEFINE_EXTENSIONS -// -// So, e.g., sample usage on an old Windows compiler: -// -// #define STB_GLPROG_IMPLEMENTATION -// #define STB_GLPROG_ARB_DEFINE_EXTENSIONS -// #include -// #include "gl/gl.h" -// #include "stb_glprog.h" -// -// Note though that the header-file version of this (when you don't define -// STB_GLPROG_IMPLEMENTATION) still uses GLint and such, so you basically -// can only include it in places where you're already including GL, especially -// on Windows where including "gl.h" requires (some of) "windows.h". -// -// See following comment blocks for function documentation. -// -// Version history: -// 2013-12-08 v0.02 slightly simplified API and reduced GL resource usage (@rygorous) -// 2013-12-08 v0.01 initial release - - -// header file section starts here -#if !defined(INCLUDE_STB_GLPROG_H) -#define INCLUDE_STB_GLPROG_H - -#ifndef STB_GLPROG_STATIC -#ifdef __cplusplus -extern "C" { -#endif - -////////////////////////////////////////////////////////////////////////////// - -///////////// SHADER CREATION - - -/// EASY API - -extern GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen); -// This function returns a compiled program or 0 if there's an error. -// To free the created program, call stbgl_delete_program. -// -// stbgl_create_program( -// char **vertex_source, // NULL or one or more strings with the vertex shader source, with a final NULL -// char **frag_source, // NULL or one or more strings with the fragment shader source, with a final NULL -// char **binds, // NULL or zero or more strings with attribute bind names, with a final NULL -// char *error, // output location where compile error message is placed -// int error_buflen) // length of error output buffer -// -// Returns a GLuint with the GL program object handle. -// -// If an individual bind string is "", no name is bound to that slot (this -// allows you to create binds that aren't continuous integers starting at 0). -// -// If the vertex shader is NULL, then fixed-function vertex pipeline -// is used, if that's legal in your version of GL. -// -// If the fragment shader is NULL, then fixed-function fragment pipeline -// is used, if that's legal in your version of GL. - -extern void stgbl_delete_program(GLuint program); -// deletes a program created by stbgl_create_program or stbgl_link_program - - -/// FLEXIBLE API - -extern GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen); -// compiles a shader. returns the shader on success or 0 on failure. -// -// type either: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER -// or GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB -// or STBGL_VERTEX_SHADER or STBGL_FRAGMENT_SHADER -// sources array of strings containing the shader source -// num_sources number of string in sources, or -1 meaning sources is NULL-terminated -// error string to output compiler error to -// error_buflen length of error buffer in chars - -extern GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen); -// links a shader. returns the linked program on success or 0 on failure. -// -// vertex_shader a compiled vertex shader from stbgl_compile_shader, or 0 for fixed-function (if legal) -// fragment_shader a compiled fragment shader from stbgl_compile_shader, or 0 for fixed-function (if legal) -// - -extern void stbgl_delete_shader(GLuint shader); -// deletes a shader created by stbgl_compile_shader - - -///////////// RENDERING WITH SHADERS - -extern GLint stbgl_find_uniform(GLuint prog, char *uniform); - -extern void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms); -// Given the locations array that is num_uniforms long, fills out -// the locations of each of those uniforms for the specified program. -// If num_uniforms is -1, then uniforms[] must be NULL-terminated - -// the following functions just wrap the difference in naming between GL2+ and ARB, -// so you don't need them unless you're using both ARB and GL2+ in the same codebase, -// or you're relying on this lib to provide the extensions -extern void stbglUseProgram(GLuint program); -extern void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer); -extern void stbglEnableVertexAttribArray(GLuint index); -extern void stbglDisableVertexAttribArray(GLuint index); -extern void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v); -extern void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v); -extern void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v); -extern void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v); -extern void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v); -extern void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v); -extern void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v); -extern void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v); -extern void stbglUniform1f(GLint loc, float v0); -extern void stbglUniform2f(GLint loc, float v0, float v1); -extern void stbglUniform3f(GLint loc, float v0, float v1, float v2); -extern void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3); -extern void stbglUniform1i(GLint loc, GLint v0); -extern void stbglUniform2i(GLint loc, GLint v0, GLint v1); -extern void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2); -extern void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3); - - -////////////// END OF FUNCTIONS - -////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} -#endif -#endif // STB_GLPROG_STATIC - -#ifdef STB_GLPROG_ARB -#define STBGL_VERTEX_SHADER GL_VERTEX_SHADER_ARB -#define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER_ARB -#else -#define STBGL_VERTEX_SHADER GL_VERTEX_SHADER -#define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER -#endif - -#endif // INCLUDE_STB_GLPROG_H - - -///////// header file section ends here - - -#ifdef STB_GLPROG_IMPLEMENTATION -#include // strncpy - -#ifdef STB_GLPROG_STATIC -#define STB_GLPROG_DECLARE static -#else -#define STB_GLPROG_DECLARE extern -#endif - -// check if user wants this file to define the GL extensions itself -#ifdef STB_GLPROG_ARB_DEFINE_EXTENSIONS -#define STB_GLPROG_ARB // make sure later code uses the extensions - -#ifndef STB_GLPROG_SUPPRESS_GLEXT_INCLUDE -#include "glext.h" -#endif - -#define STB_GLPROG_EXTENSIONS \ - STB_GLPROG_FUNC(ATTACHOBJECT , AttachObject ) \ - STB_GLPROG_FUNC(BINDATTRIBLOCATION , BindAttribLocation ) \ - STB_GLPROG_FUNC(COMPILESHADER , CompileShader ) \ - STB_GLPROG_FUNC(CREATEPROGRAMOBJECT , CreateProgramObject ) \ - STB_GLPROG_FUNC(CREATESHADEROBJECT , CreateShaderObject ) \ - STB_GLPROG_FUNC(DELETEOBJECT , DeleteObject ) \ - STB_GLPROG_FUNC(DETACHOBJECT , DetachObject ) \ - STB_GLPROG_FUNC(DISABLEVERTEXATTRIBARRAY, DisableVertexAttribArray) \ - STB_GLPROG_FUNC(ENABLEVERTEXATTRIBARRAY, EnableVertexAttribArray ) \ - STB_GLPROG_FUNC(GETATTACHEDOBJECTS , GetAttachedObjects ) \ - STB_GLPROG_FUNC(GETOBJECTPARAMETERIV, GetObjectParameteriv) \ - STB_GLPROG_FUNC(GETINFOLOG , GetInfoLog ) \ - STB_GLPROG_FUNC(GETUNIFORMLOCATION , GetUniformLocation ) \ - STB_GLPROG_FUNC(LINKPROGRAM , LinkProgram ) \ - STB_GLPROG_FUNC(SHADERSOURCE , ShaderSource ) \ - STB_GLPROG_FUNC(UNIFORM1F , Uniform1f ) \ - STB_GLPROG_FUNC(UNIFORM2F , Uniform2f ) \ - STB_GLPROG_FUNC(UNIFORM3F , Uniform3f ) \ - STB_GLPROG_FUNC(UNIFORM4F , Uniform4f ) \ - STB_GLPROG_FUNC(UNIFORM1I , Uniform1i ) \ - STB_GLPROG_FUNC(UNIFORM2I , Uniform2i ) \ - STB_GLPROG_FUNC(UNIFORM3I , Uniform3i ) \ - STB_GLPROG_FUNC(UNIFORM4I , Uniform4i ) \ - STB_GLPROG_FUNC(UNIFORM1FV , Uniform1fv ) \ - STB_GLPROG_FUNC(UNIFORM2FV , Uniform2fv ) \ - STB_GLPROG_FUNC(UNIFORM3FV , Uniform3fv ) \ - STB_GLPROG_FUNC(UNIFORM4FV , Uniform4fv ) \ - STB_GLPROG_FUNC(UNIFORM1IV , Uniform1iv ) \ - STB_GLPROG_FUNC(UNIFORM2IV , Uniform2iv ) \ - STB_GLPROG_FUNC(UNIFORM3IV , Uniform3iv ) \ - STB_GLPROG_FUNC(UNIFORM4IV , Uniform4iv ) \ - STB_GLPROG_FUNC(USEPROGRAMOBJECT , UseProgramObject ) \ - STB_GLPROG_FUNC(VERTEXATTRIBPOINTER , VertexAttribPointer ) - -// define the static function pointers - -#define STB_GLPROG_FUNC(x,y) static PFNGL##x##ARBPROC gl##y##ARB; -STB_GLPROG_EXTENSIONS -#undef STB_GLPROG_FUNC - -// define the GetProcAddress - -#ifdef _WIN32 -#ifndef WINGDIAPI -#ifndef STB__HAS_WGLPROC -typedef int (__stdcall *stbgl__voidfunc)(void); -static __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *); -#endif -#endif -#define STBGL__GET_FUNC(x) wglGetProcAddress(x) -#else -#error "need to define how this platform gets extensions" -#endif - -// create a function that fills out the function pointers - -static void stb_glprog_init(void) -{ - static int initialized = 0; // not thread safe! - if (initialized) return; - #define STB_GLPROG_FUNC(x,y) gl##y##ARB = (PFNGL##x##ARBPROC) STBGL__GET_FUNC("gl" #y "ARB"); - STB_GLPROG_EXTENSIONS - #undef STB_GLPROG_FUNC -} -#undef STB_GLPROG_EXTENSIONS - -#else -static void stb_glprog_init(void) -{ -} -#endif - - -// define generic names for many of the gl functions or extensions for later use; -// note that in some cases there are two functions in core and one function in ARB -#ifdef STB_GLPROG_ARB -#define stbglCreateShader glCreateShaderObjectARB -#define stbglDeleteShader glDeleteObjectARB -#define stbglAttachShader glAttachObjectARB -#define stbglDetachShader glDetachObjectARB -#define stbglShaderSource glShaderSourceARB -#define stbglCompileShader glCompileShaderARB -#define stbglGetShaderStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_COMPILE_STATUS_ARB, b) -#define stbglGetShaderInfoLog glGetInfoLogARB -#define stbglCreateProgram glCreateProgramObjectARB -#define stbglDeleteProgram glDeleteObjectARB -#define stbglLinkProgram glLinkProgramARB -#define stbglGetProgramStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_LINK_STATUS_ARB, b) -#define stbglGetProgramInfoLog glGetInfoLogARB -#define stbglGetAttachedShaders glGetAttachedObjectsARB -#define stbglBindAttribLocation glBindAttribLocationARB -#define stbglGetUniformLocation glGetUniformLocationARB -#define stbgl_UseProgram glUseProgramObjectARB -#else -#define stbglCreateShader glCreateShader -#define stbglDeleteShader glDeleteShader -#define stbglAttachShader glAttachShader -#define stbglDetachShader glDetachShader -#define stbglShaderSource glShaderSource -#define stbglCompileShader glCompileShader -#define stbglGetShaderStatus(a,b) glGetShaderiv(a, GL_COMPILE_STATUS, b) -#define stbglGetShaderInfoLog glGetShaderInfoLog -#define stbglCreateProgram glCreateProgram -#define stbglDeleteProgram glDeleteProgram -#define stbglLinkProgram glLinkProgram -#define stbglGetProgramStatus(a,b) glGetProgramiv(a, GL_LINK_STATUS, b) -#define stbglGetProgramInfoLog glGetProgramInfoLog -#define stbglGetAttachedShaders glGetAttachedShaders -#define stbglBindAttribLocation glBindAttribLocation -#define stbglGetUniformLocation glGetUniformLocation -#define stbgl_UseProgram glUseProgram -#endif - - -// perform a safe strcat of 3 strings, given that we can't rely on portable snprintf -// if you need to break on error, this is the best place to place a breakpoint -static void stb_glprog_error(char *error, int error_buflen, char *str1, char *str2, char *str3) -{ - int n = strlen(str1); - strncpy(error, str1, error_buflen); - if (n < error_buflen && str2) { - strncpy(error+n, str2, error_buflen - n); - n += strlen(str2); - if (n < error_buflen && str3) { - strncpy(error+n, str3, error_buflen - n); - } - } - error[error_buflen-1] = 0; -} - -STB_GLPROG_DECLARE GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen) -{ - char *typename = (type == STBGL_VERTEX_SHADER ? "vertex" : "fragment"); - int len; - GLint result; - GLuint shader; - - // initialize the extensions if we haven't already - stb_glprog_init(); - - // allocate - - shader = stbglCreateShader(type); - if (!shader) { - stb_glprog_error(error, error_buflen, "Couldn't allocate shader object in stbgl_compile_shader for ", typename, NULL); - return 0; - } - - // compile - - // if num_sources is negative, assume source is NULL-terminated and count the non-NULL ones - if (num_sources < 0) - for (num_sources = 0; sources[num_sources] != NULL; ++num_sources) - ; - stbglShaderSource(shader, num_sources, sources, NULL); - stbglCompileShader(shader); - stbglGetShaderStatus(shader, &result); - if (result) - return shader; - - // errors - - stb_glprog_error(error, error_buflen, "Compile error for ", typename, " shader: "); - len = strlen(error); - if (len < error_buflen) - stbglGetShaderInfoLog(shader, error_buflen-len, NULL, error+len); - - stbglDeleteShader(shader); - return 0; -} - -STB_GLPROG_DECLARE GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen) -{ - int len; - GLint result; - - // allocate - - GLuint prog = stbglCreateProgram(); - if (!prog) { - stb_glprog_error(error, error_buflen, "Couldn't allocate program object in stbgl_link_program", NULL, NULL); - return 0; - } - - // attach - - if (vertex_shader) - stbglAttachShader(prog, vertex_shader); - if (fragment_shader) - stbglAttachShader(prog, fragment_shader); - - // attribute binds - - if (binds) { - int i; - // if num_binds is negative, then it is NULL terminated - if (num_binds < 0) - for (num_binds=0; binds[num_binds]; ++num_binds) - ; - for (i=0; i < num_binds; ++i) - if (binds[i] && binds[i][0]) // empty binds can be NULL or "" - stbglBindAttribLocation(prog, i, binds[i]); - } - - // link - - stbglLinkProgram(prog); - - // detach - - if (vertex_shader) - stbglDetachShader(prog, vertex_shader); - if (fragment_shader) - stbglDetachShader(prog, fragment_shader); - - // errors - - stbglGetProgramStatus(prog, &result); - if (result) - return prog; - - stb_glprog_error(error, error_buflen, "Link error: ", NULL, NULL); - len = strlen(error); - if (len < error_buflen) - stbglGetProgramInfoLog(prog, error_buflen-len, NULL, error+len); - - stbglDeleteProgram(prog); - return 0; -} - -STB_GLPROG_DECLARE GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen) -{ - GLuint vertex, fragment, prog=0; - vertex = stbgl_compile_shader(STBGL_VERTEX_SHADER, vertex_source, -1, error, error_buflen); - if (vertex) { - fragment = stbgl_compile_shader(STBGL_FRAGMENT_SHADER, frag_source, -1, error, error_buflen); - if (fragment) - prog = stbgl_link_program(vertex, fragment, binds, -1, error, error_buflen); - if (fragment) - stbglDeleteShader(fragment); - stbglDeleteShader(vertex); - } - return prog; -} - -STB_GLPROG_DECLARE void stbgl_delete_shader(GLuint shader) -{ - stbglDeleteShader(shader); -} - -STB_GLPROG_DECLARE void stgbl_delete_program(GLuint program) -{ - stbglDeleteProgram(program); -} - -GLint stbgl_find_uniform(GLuint prog, char *uniform) -{ - return stbglGetUniformLocation(prog, uniform); -} - -STB_GLPROG_DECLARE void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms) -{ - int i; - if (num_uniforms < 0) - num_uniforms = 999999; - for (i=0; i < num_uniforms && uniforms[i]; ++i) - locations[i] = stbglGetUniformLocation(prog, uniforms[i]); -} - -STB_GLPROG_DECLARE void stbglUseProgram(GLuint program) -{ - stbgl_UseProgram(program); -} - -#ifdef STB_GLPROG_ARB -#define STBGL_ARBIFY(name) name##ARB -#else -#define STBGL_ARBIFY(name) name -#endif - -STB_GLPROG_DECLARE void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer) -{ - STBGL_ARBIFY(glVertexAttribPointer)(index, size, type, normalized, stride, pointer); -} - -STB_GLPROG_DECLARE void stbglEnableVertexAttribArray (GLuint index) { STBGL_ARBIFY(glEnableVertexAttribArray )(index); } -STB_GLPROG_DECLARE void stbglDisableVertexAttribArray(GLuint index) { STBGL_ARBIFY(glDisableVertexAttribArray)(index); } - -STB_GLPROG_DECLARE void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform1fv)(loc,count,v); } -STB_GLPROG_DECLARE void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform2fv)(loc,count,v); } -STB_GLPROG_DECLARE void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform3fv)(loc,count,v); } -STB_GLPROG_DECLARE void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform4fv)(loc,count,v); } - -STB_GLPROG_DECLARE void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform1iv)(loc,count,v); } -STB_GLPROG_DECLARE void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform2iv)(loc,count,v); } -STB_GLPROG_DECLARE void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform3iv)(loc,count,v); } -STB_GLPROG_DECLARE void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform4iv)(loc,count,v); } - -STB_GLPROG_DECLARE void stbglUniform1f(GLint loc, float v0) - { STBGL_ARBIFY(glUniform1f)(loc,v0); } -STB_GLPROG_DECLARE void stbglUniform2f(GLint loc, float v0, float v1) - { STBGL_ARBIFY(glUniform2f)(loc,v0,v1); } -STB_GLPROG_DECLARE void stbglUniform3f(GLint loc, float v0, float v1, float v2) - { STBGL_ARBIFY(glUniform3f)(loc,v0,v1,v2); } -STB_GLPROG_DECLARE void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3) - { STBGL_ARBIFY(glUniform4f)(loc,v0,v1,v2,v3); } - -STB_GLPROG_DECLARE void stbglUniform1i(GLint loc, GLint v0) - { STBGL_ARBIFY(glUniform1i)(loc,v0); } -STB_GLPROG_DECLARE void stbglUniform2i(GLint loc, GLint v0, GLint v1) - { STBGL_ARBIFY(glUniform2i)(loc,v0,v1); } -STB_GLPROG_DECLARE void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2) - { STBGL_ARBIFY(glUniform3i)(loc,v0,v1,v2); } -STB_GLPROG_DECLARE void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3) - { STBGL_ARBIFY(glUniform4i)(loc,v0,v1,v2,v3); } - -#endif diff --git a/source/engine/thirdparty/stb/tests/caveview/win32/SDL_windows_main.c b/source/engine/thirdparty/stb/tests/caveview/win32/SDL_windows_main.c deleted file mode 100644 index 32e316b..0000000 --- a/source/engine/thirdparty/stb/tests/caveview/win32/SDL_windows_main.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98 - - The WinMain function -- calls your program's main() function -*/ -#include "SDL_config.h" - -#ifdef __WIN32__ - -//#include "../../core/windows/SDL_windows.h" - -/* Include this so we define UNICODE properly */ -#if defined(__WIN32__) -#define WIN32_LEAN_AND_MEAN -#define STRICT -#ifndef UNICODE -#define UNICODE 1 -#endif -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */ -#endif - -#include - -/* Routines to convert from UTF8 to native Windows text */ -#if UNICODE -#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR)) -#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (char *)(S), SDL_strlen(S)+1) -#else -/* !!! FIXME: UTF8ToString() can just be a SDL_strdup() here. */ -#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "ASCII", (char *)(S), (SDL_strlen(S)+1)) -#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), SDL_strlen(S)+1) -#endif - -/* Sets an error message based on a given HRESULT */ -extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr); - -/* Sets an error message based on GetLastError(). Always return -1. */ -extern int WIN_SetError(const char *prefix); - -/* Wrap up the oddities of CoInitialize() into a common function. */ -extern HRESULT WIN_CoInitialize(void); -extern void WIN_CoUninitialize(void); - -/* Returns SDL_TRUE if we're running on Windows Vista and newer */ -extern BOOL WIN_IsWindowsVistaOrGreater(); - -#include -#include - -/* Include the SDL main definition header */ -#include "SDL.h" -#include "SDL_main.h" - -#ifdef main -# undef main -#endif /* main */ - -static void -UnEscapeQuotes(char *arg) -{ - char *last = NULL; - - while (*arg) { - if (*arg == '"' && (last != NULL && *last == '\\')) { - char *c_curr = arg; - char *c_last = last; - - while (*c_curr) { - *c_last = *c_curr; - c_last = c_curr; - c_curr++; - } - *c_last = '\0'; - } - last = arg; - arg++; - } -} - -/* Parse a command line buffer into arguments */ -static int -ParseCommandLine(char *cmdline, char **argv) -{ - char *bufp; - char *lastp = NULL; - int argc, last_argc; - - argc = last_argc = 0; - for (bufp = cmdline; *bufp;) { - /* Skip leading whitespace */ - while (SDL_isspace(*bufp)) { - ++bufp; - } - /* Skip over argument */ - if (*bufp == '"') { - ++bufp; - if (*bufp) { - if (argv) { - argv[argc] = bufp; - } - ++argc; - } - /* Skip over word */ - lastp = bufp; - while (*bufp && (*bufp != '"' || *lastp == '\\')) { - lastp = bufp; - ++bufp; - } - } else { - if (*bufp) { - if (argv) { - argv[argc] = bufp; - } - ++argc; - } - /* Skip over word */ - while (*bufp && !SDL_isspace(*bufp)) { - ++bufp; - } - } - if (*bufp) { - if (argv) { - *bufp = '\0'; - } - ++bufp; - } - - /* Strip out \ from \" sequences */ - if (argv && last_argc != argc) { - UnEscapeQuotes(argv[last_argc]); - } - last_argc = argc; - } - if (argv) { - argv[argc] = NULL; - } - return (argc); -} - -/* Show an error message */ -static void -ShowError(const char *title, const char *message) -{ -/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */ -#ifdef USE_MESSAGEBOX - MessageBox(NULL, message, title, MB_ICONEXCLAMATION | MB_OK); -#else - fprintf(stderr, "%s: %s\n", title, message); -#endif -} - -/* Pop up an out of memory message, returns to Windows */ -static BOOL -OutOfMemory(void) -{ - ShowError("Fatal Error", "Out of memory - aborting"); - return FALSE; -} - -#if defined(_MSC_VER) -/* The VC++ compiler needs main defined */ -#define console_main main -#endif - -/* This is where execution begins [console apps] */ -int -console_main(int argc, char *argv[]) -{ - int status; - - SDL_SetMainReady(); - - /* Run the application main() code */ - status = SDL_main(argc, argv); - - /* Exit cleanly, calling atexit() functions */ - exit(status); - - /* Hush little compiler, don't you cry... */ - return 0; -} - -/* This is where execution begins [windowed apps] */ -int WINAPI -WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) -{ - char **argv; - int argc; - char *cmdline; - - /* Grab the command line */ - TCHAR *text = GetCommandLine(); -#if UNICODE - cmdline = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char *)(text), (SDL_wcslen(text)+1)*sizeof(WCHAR)); -#else - cmdline = SDL_strdup(text); -#endif - if (cmdline == NULL) { - return OutOfMemory(); - } - - /* Parse it into argv and argc */ - argc = ParseCommandLine(cmdline, NULL); - argv = SDL_stack_alloc(char *, argc + 1); - if (argv == NULL) { - return OutOfMemory(); - } - ParseCommandLine(cmdline, argv); - - /* Run the main program */ - console_main(argc, argv); - - SDL_stack_free(argv); - - SDL_free(cmdline); - - /* Hush little compiler, don't you cry... */ - return 0; -} - -#endif /* __WIN32__ */ - -/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/engine/thirdparty/stb/tests/fuzz_main.c b/source/engine/thirdparty/stb/tests/fuzz_main.c deleted file mode 100644 index 40c0cc8..0000000 --- a/source/engine/thirdparty/stb/tests/fuzz_main.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include - -/* fuzz target entry point, works without libFuzzer */ - -int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); - -int main(int argc, char **argv) -{ - FILE *f; - char *buf = NULL; - long siz_buf; - - if(argc < 2) - { - fprintf(stderr, "no input file\n"); - goto err; - } - - f = fopen(argv[1], "rb"); - if(f == NULL) - { - fprintf(stderr, "error opening input file %s\n", argv[1]); - goto err; - } - - fseek(f, 0, SEEK_END); - - siz_buf = ftell(f); - rewind(f); - - if(siz_buf < 1) goto err; - - buf = (char*)malloc((size_t)siz_buf); - if(buf == NULL) - { - fprintf(stderr, "malloc() failed\n"); - goto err; - } - - if(fread(buf, (size_t)siz_buf, 1, f) != 1) - { - fprintf(stderr, "fread() failed\n"); - goto err; - } - - (void)LLVMFuzzerTestOneInput((uint8_t*)buf, (size_t)siz_buf); - -err: - free(buf); - - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/grid_reachability.c b/source/engine/thirdparty/stb/tests/grid_reachability.c deleted file mode 100644 index 905f2c2..0000000 --- a/source/engine/thirdparty/stb/tests/grid_reachability.c +++ /dev/null @@ -1,363 +0,0 @@ -#define STB_CONNECTED_COMPONENTS_IMPLEMENTATION -#define STBCC_GRID_COUNT_X_LOG2 10 -#define STBCC_GRID_COUNT_Y_LOG2 10 -#include "stb_connected_components.h" - -#ifdef GRID_TEST - -#include -#include -#include - -//#define STB_DEFINE -#include "stb.h" - -//#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -//#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -typedef struct -{ - uint16 x,y; -} point; - -point leader[1024][1024]; -uint32 color[1024][1024]; - -point find(int x, int y) -{ - point p,q; - p = leader[y][x]; - if (p.x == x && p.y == y) - return p; - q = find(p.x, p.y); - leader[y][x] = q; - return q; -} - -void onion(int x1, int y1, int x2, int y2) -{ - point p = find(x1,y1); - point q = find(x2,y2); - - if (p.x == q.x && p.y == q.y) - return; - - leader[p.y][p.x] = q; -} - -void reference(uint8 *map, int w, int h) -{ - int i,j; - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - leader[j][i].x = i; - leader[j][i].y = j; - } - } - - for (j=1; j < h-1; ++j) { - for (i=1; i < w-1; ++i) { - if (map[j*w+i] == 255) { - if (map[(j+1)*w+i] == 255) onion(i,j, i,j+1); - if (map[(j)*w+i+1] == 255) onion(i,j, i+1,j); - } - } - } - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - uint32 c = 0xff000000; - if (leader[j][i].x == i && leader[j][i].y == j) { - if (map[j*w+i] == 255) - c = stb_randLCG() | 0xff404040; - } - color[j][i] = c; - } - } - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - if (leader[j][i].x != i || leader[j][i].y != j) { - point p = find(i,j); - color[j][i] = color[p.y][p.x]; - } - } - } -} - -void write_map(stbcc_grid *g, int w, int h, char *filename) -{ - int i,j; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - unsigned int c; - c = stbcc_get_unique_id(g,i,j); - c = stb_rehash_improved(c)&0xffffff; - if (c == STBCC_NULL_UNIQUE_ID) - c = 0xff000000; - else - c = (~c)^0x555555; - if (i % 32 == 0 || j %32 == 0) { - int r = (c >> 16) & 255; - int g = (c >> 8) & 255; - int b = c & 255; - r = (r+130)/2; - g = (g+130)/2; - b = (b+130)/2; - c = 0xff000000 + (r<<16) + (g<<8) + b; - } - color[j][i] = c; - } - } - stbi_write_png(filename, w, h, 4, color, 4*w); -} - -void test_connected(stbcc_grid *g) -{ - int n = stbcc_query_grid_node_connection(g, 512, 90, 512, 871); - //printf("%d ", n); -} - -static char *message; -LARGE_INTEGER start; - -void start_timer(char *s) -{ - message = s; - QueryPerformanceCounter(&start); -} - -void end_timer(void) -{ - LARGE_INTEGER end, freq; - double tm; - - QueryPerformanceCounter(&end); - QueryPerformanceFrequency(&freq); - - tm = (end.QuadPart - start.QuadPart) / (double) freq.QuadPart; - printf("%6.4lf ms: %s\n", tm * 1000, message); -} - -extern void quicktest(void); - -int loc[5000][2]; -int main(int argc, char **argv) -{ - stbcc_grid *g; - - int w,h, i,j,k=0, count=0, r; - uint8 *map = stbi_load("data/map_03.png", &w, &h, 0, 1); - - assert(map); - quicktest(); - - for (j=0; j < h; ++j) - for (i=0; i < w; ++i) - map[j*w+i] = ~map[j*w+i]; - - for (i=0; i < w; ++i) - for (j=0; j < h; ++j) - //map[j*w+i] = (((i+1) ^ (j+1)) >> 1) & 1 ? 255 : 0; - map[j*w+i] = stb_max(abs(i-w/2),abs(j-h/2)) & 1 ? 255 : 0; - //map[j*w+i] = (((i ^ j) >> 5) ^ (i ^ j)) & 1 ? 255 : 0; - //map[j*w+i] = stb_rand() & 1 ? 255 : 0; - - #if 1 - for (i=0; i < 100000; ++i) - map[(stb_rand()%h)*w + stb_rand()%w] ^= 255; - #endif - - _mkdir("tests/output/stbcc"); - - stbi_write_png("tests/output/stbcc/reference.png", w, h, 1, map, 0); - - //reference(map, w, h); - - g = malloc(stbcc_grid_sizeof()); - printf("Size: %d\n", stbcc_grid_sizeof()); - -#if 0 - memset(map, 0, w*h); - stbcc_init_grid(g, map, w, h); - { - int n; - char **s = stb_stringfile("c:/x/clockwork_update.txt", &n); - write_map(g, w, h, "tests/output/stbcc/base.png"); - for (i=1; i < n; i += 1) { - int x,y,t; - sscanf(s[i], "%d %d %d", &x, &y, &t); - if (i == 571678) - write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_good.png", i)); - stbcc_update_grid(g, x, y, t); - if (i == 571678) - write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_bad.png", i)); - //if (i > 571648 && i <= 571712) - //write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_%06d.png", i)); - } - write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_%06d.png", i-1)); - } - return 0; -#endif - - - start_timer("init"); - stbcc_init_grid(g, map, w, h); - end_timer(); - //g = stb_file("c:/x/clockwork_path.bin", 0); - write_map(g, w, h, "tests/output/stbcc/base.png"); - - for (i=0; i < 5000;) { - loc[i][0] = stb_rand() % w; - loc[i][1] = stb_rand() % h; - if (stbcc_query_grid_open(g, loc[i][0], loc[i][1])) - ++i; - } - - r = 0; - start_timer("reachable"); - for (i=0; i < 2000; ++i) { - for (j=0; j < 2000; ++j) { - int x1 = loc[i][0], y1 = loc[i][1]; - int x2 = loc[2000+j][0], y2 = loc[2000+j][1]; - r += stbcc_query_grid_node_connection(g, x1,y1, x2,y2); - } - } - end_timer(); - printf("%d reachable\n", r); - - printf("Cluster size: %d,%d\n", STBCC__CLUSTER_SIZE_X, STBCC__CLUSTER_SIZE_Y); - - #if 1 - for (j=0; j < 10; ++j) { - for (i=0; i < 5000; ++i) { - loc[i][0] = stb_rand() % w; - loc[i][1] = stb_rand() % h; - } - start_timer("updating 2500"); - for (i=0; i < 2500; ++i) { - if (stbcc_query_grid_open(g, loc[i][0], loc[i][1])) - stbcc_update_grid(g, loc[i][0], loc[i][1], 1); - else - stbcc_update_grid(g, loc[i][0], loc[i][1], 0); - } - end_timer(); - write_map(g, w, h, stb_sprintf("tests/output/stbcc/update_random_%d.png", j*i)); - } - #endif - - #if 0 - start_timer("removing"); - count = 0; - for (i=0; i < 1800; ++i) { - int x,y,a,b; - x = stb_rand() % (w-32); - y = stb_rand() % (h-32); - - if (i & 1) { - for (a=0; a < 32; ++a) - for (b=0; b < 1; ++b) - if (stbcc_query_grid_open(g, x+a, y+b)) { - stbcc_update_grid(g, x+a, y+b, 1); - ++count; - } - } else { - for (a=0; a < 1; ++a) - for (b=0; b < 32; ++b) - if (stbcc_query_grid_open(g, x+a, y+b)) { - stbcc_update_grid(g, x+a, y+b, 1); - ++count; - } - } - - //if (i % 100 == 0) write_map(g, w, h, stb_sprintf("tests/output/stbcc/open_random_%d.png", i+1)); - } - end_timer(); - printf("Removed %d grid spaces\n", count); - write_map(g, w, h, stb_sprintf("tests/output/stbcc/open_random_%d.png", i)); - - - r = 0; - start_timer("reachable"); - for (i=0; i < 1000; ++i) { - for (j=0; j < 1000; ++j) { - int x1 = loc[i][0], y1 = loc[i][1]; - int x2 = loc[j][0], y2 = loc[j][1]; - r += stbcc_query_grid_node_connection(g, x1,y1, x2,y2); - } - } - end_timer(); - printf("%d reachable\n", r); - - start_timer("adding"); - count = 0; - for (i=0; i < 1800; ++i) { - int x,y,a,b; - x = stb_rand() % (w-32); - y = stb_rand() % (h-32); - - if (i & 1) { - for (a=0; a < 32; ++a) - for (b=0; b < 1; ++b) - if (!stbcc_query_grid_open(g, x+a, y+b)) { - stbcc_update_grid(g, x+a, y+b, 0); - ++count; - } - } else { - for (a=0; a < 1; ++a) - for (b=0; b < 32; ++b) - if (!stbcc_query_grid_open(g, x+a, y+b)) { - stbcc_update_grid(g, x+a, y+b, 0); - ++count; - } - } - - //if (i % 100 == 0) write_map(g, w, h, stb_sprintf("tests/output/stbcc/close_random_%d.png", i+1)); - } - end_timer(); - write_map(g, w, h, stb_sprintf("tests/output/stbcc/close_random_%d.png", i)); - printf("Added %d grid spaces\n", count); - #endif - - - #if 0 // for map_02.png - start_timer("process"); - for (k=0; k < 20; ++k) { - for (j=0; j < h; ++j) { - int any=0; - for (i=0; i < w; ++i) { - if (map[j*w+i] > 10 && map[j*w+i] < 250) { - //start_timer(stb_sprintf("open %d,%d", i,j)); - stbcc_update_grid(g, i, j, 0); - test_connected(g); - //end_timer(); - any = 1; - } - } - if (any) write_map(g, w, h, stb_sprintf("tests/output/stbcc/open_row_%04d.png", j)); - } - - for (j=0; j < h; ++j) { - int any=0; - for (i=0; i < w; ++i) { - if (map[j*w+i] > 10 && map[j*w+i] < 250) { - //start_timer(stb_sprintf("close %d,%d", i,j)); - stbcc_update_grid(g, i, j, 1); - test_connected(g); - //end_timer(); - any = 1; - } - } - if (any) write_map(g, w, h, stb_sprintf("tests/output/stbcc/close_row_%04d.png", j)); - } - } - end_timer(); - #endif - - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/herringbone.dsp b/source/engine/thirdparty/stb/tests/herringbone.dsp deleted file mode 100644 index b82fee4..0000000 --- a/source/engine/thirdparty/stb/tests/herringbone.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="herringbone" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=herringbone - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "herringbone.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "herringbone.mak" CFG="herringbone - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "herringbone - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "herringbone - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "herringbone - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "herringbone - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "herringbone___Win32_Debug" -# PROP BASE Intermediate_Dir "herringbone___Win32_Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "herringbone - Win32 Release" -# Name "herringbone - Win32 Debug" -# Begin Source File - -SOURCE=.\herringbone_generator.c -# End Source File -# Begin Source File - -SOURCE=..\stb_herringbone_wang_tile.h -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/herringbone_generator.c b/source/engine/thirdparty/stb/tests/herringbone_generator.c deleted file mode 100644 index cf2a99e..0000000 --- a/source/engine/thirdparty/stb/tests/herringbone_generator.c +++ /dev/null @@ -1,87 +0,0 @@ -#define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION -#include "stb_herringbone_wang_tile.h" - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -// e 12 1 1 1 1 1 1 4 4 - -int main(int argc, char **argv) -{ - stbhw_config c = { 0 }; - int w,h, num_colors,i; - unsigned char *data; - - if (argc == 1) goto usage; - if (argc < 3) goto error; - - switch (argv[2][0]) { - case 'c': - if (argc < 8 || argc > 10) - goto error; - num_colors = 4; - c.is_corner = 1; - break; - - case 'e': - if (argc < 10 || argc > 12) - goto error; - num_colors = 6; - c.is_corner = 0; - break; - - default: - goto error; - } - - c.short_side_len = atoi(argv[3]); - for (i=0; i < num_colors; ++i) - c.num_color[i] = atoi(argv[4+i]); - - c.num_vary_x = 1; - c.num_vary_y = 1; - - if (argc > 4+i) - c.num_vary_x = atoi(argv[4+i]); - if (argc > 5+i) - c.num_vary_y = atoi(argv[5+i]); - - stbhw_get_template_size(&c, &w, &h); - - data = (unsigned char *) malloc(w*h*3); - - if (stbhw_make_template(&c, data, w, h, w*3)) - stbi_write_png(argv[1], w, h, 3, data, w*3); - else - fprintf(stderr, "Error: %s\n", stbhw_get_last_error()); - return 0; - - error: - fputs("Invalid command-line arguments\n\n", stderr); - usage: - fputs("Usage (see source for corner & edge type definitions):\n\n", stderr); - fputs("herringbone_generator {outfile} c {sidelen} {c0} {c1} {c2} {c3} [{vx} {vy}]\n" - " {outfile} -- filename that template will be written to as PNG\n" - " {sidelen} -- length of short side of rectangle in pixels\n" - " {c0} -- number of colors for corner type 0\n" - " {c1} -- number of colors for corner type 1\n" - " {c2} -- number of colors for corner type 2\n" - " {c3} -- number of colors for corner type 3\n" - " {vx} -- number of color-duplicating variations horizontally in template\n" - " {vy} -- number of color-duplicating variations vertically in template\n" - "\n" - , stderr); - fputs("herringbone_generator {outfile} e {sidelen} {e0} {e1} {e2} {e3} {e4} {e5} [{vx} {vy}]\n" - " {outfile} -- filename that template will be written to as PNG\n" - " {sidelen} -- length of short side of rectangle in pixels\n" - " {e0} -- number of colors for edge type 0\n" - " {e1} -- number of colors for edge type 1\n" - " {e2} -- number of colors for edge type 2\n" - " {e3} -- number of colors for edge type 3\n" - " {e4} -- number of colors for edge type 4\n" - " {e5} -- number of colors for edge type 5\n" - " {vx} -- number of color-duplicating variations horizontally in template\n" - " {vy} -- number of color-duplicating variations vertically in template\n" - , stderr); - return 1; -} diff --git a/source/engine/thirdparty/stb/tests/herringbone_map.c b/source/engine/thirdparty/stb/tests/herringbone_map.c deleted file mode 100644 index 22cc013..0000000 --- a/source/engine/thirdparty/stb/tests/herringbone_map.c +++ /dev/null @@ -1,83 +0,0 @@ -#include - -#define STB_HBWANG_MAX_X 500 -#define STB_HBWANG_MAX_Y 500 - -#define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION -#include "stb_herringbone_wang_tile.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -int main(int argc, char **argv) -{ - if (argc < 5) { - fprintf(stderr, "Usage: herringbone_map {inputfile} {output-width} {output-height} {outputfile}\n"); - return 1; - } else { - char *filename = argv[1]; - int out_w = atoi(argv[2]); - int out_h = atoi(argv[3]); - char *outfile = argv[4]; - - unsigned char *pixels, *out_pixels; - stbhw_tileset ts; - int w,h; - - pixels = stbi_load(filename, &w, &h, 0, 3); - if (pixels == 0) { - fprintf(stderr, "Couldn't open input file '%s'\n", filename); - exit(1); - } - - if (!stbhw_build_tileset_from_image(&ts, pixels, w*3, w, h)) { - fprintf(stderr, "Error: %s\n", stbhw_get_last_error()); - return 1; - } - - free(pixels); - - #ifdef DEBUG_OUTPUT - { - int i,j,k; - // add blue borders to top-left edges of the tiles - int hstride = (ts.short_side_len*2)*3; - int vstride = (ts.short_side_len )*3; - for (i=0; i < ts.num_h_tiles; ++i) { - unsigned char *pix = ts.h_tiles[i]->pixels; - for (j=0; j < ts.short_side_len*2; ++j) - for (k=0; k < 3; ++k) - pix[j*3+k] = (pix[j*3+k]*0.5+100+k*75)/1.5; - for (j=1; j < ts.short_side_len; ++j) - for (k=0; k < 3; ++k) - pix[j*hstride+k] = (pix[j*hstride+k]*0.5+100+k*75)/1.5; - } - for (i=0; i < ts.num_v_tiles; ++i) { - unsigned char *pix = ts.v_tiles[i]->pixels; - for (j=0; j < ts.short_side_len; ++j) - for (k=0; k < 3; ++k) - pix[j*3+k] = (pix[j*3+k]*0.5+100+k*75)/1.5; - for (j=1; j < ts.short_side_len*2; ++j) - for (k=0; k < 3; ++k) - pix[j*vstride+k] = (pix[j*vstride+k]*0.5+100+k*75)/1.5; - } - } - #endif - - out_pixels = malloc(out_w * out_h * 3); - - if (!stbhw_generate_image(&ts, NULL, out_pixels, out_w*3, out_w, out_h)) { - fprintf(stderr, "Error: %s\n", stbhw_get_last_error()); - return 1; - } - - stbi_write_png(argv[4], out_w, out_h, 3, out_pixels, out_w*3); - free(out_pixels); - - stbhw_free_tileset(&ts); - return 0; - } -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/herringbone_map.dsp b/source/engine/thirdparty/stb/tests/herringbone_map.dsp deleted file mode 100644 index 3e26d6d..0000000 --- a/source/engine/thirdparty/stb/tests/herringbone_map.dsp +++ /dev/null @@ -1,94 +0,0 @@ -# Microsoft Developer Studio Project File - Name="herringbone_map" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=herringbone_map - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "herringbone_map.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "herringbone_map.mak" CFG="herringbone_map - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "herringbone_map - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "herringbone_map - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "herringbone_map - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "herringbone_map - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "herringbone_map___Win32_Debug" -# PROP BASE Intermediate_Dir "herringbone_map___Win32_Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "herringbone_map - Win32 Release" -# Name "herringbone_map - Win32 Debug" -# Begin Source File - -SOURCE=.\herringbone_map.c -# End Source File -# Begin Source File - -SOURCE=..\stb_herringbone_wang_tile.h -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/image_test.c b/source/engine/thirdparty/stb/tests/image_test.c deleted file mode 100644 index 9c216cf..0000000 --- a/source/engine/thirdparty/stb/tests/image_test.c +++ /dev/null @@ -1,173 +0,0 @@ -#define STBI_WINDOWS_UTF8 - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#define STB_DEFINE -#include "stb.h" - -//#define PNGSUITE_PRIMARY - -#if 0 -void test_ycbcr(void) -{ - STBI_SIMD_ALIGN(unsigned char, y[256]); - STBI_SIMD_ALIGN(unsigned char, cb[256]); - STBI_SIMD_ALIGN(unsigned char, cr[256]); - STBI_SIMD_ALIGN(unsigned char, out1[256][4]); - STBI_SIMD_ALIGN(unsigned char, out2[256][4]); - - int i,j,k; - int count = 0, bigcount=0, total=0; - - for (i=0; i < 256; ++i) { - for (j=0; j < 256; ++j) { - for (k=0; k < 256; ++k) { - y [k] = k; - cb[k] = j; - cr[k] = i; - } - stbi__YCbCr_to_RGB_row(out1[0], y, cb, cr, 256, 4); - stbi__YCbCr_to_RGB_sse2(out2[0], y, cb, cr, 256, 4); - for (k=0; k < 256; ++k) { - // inaccurate proxy for values outside of RGB cube - if (out1[k][0] == 0 || out1[k][1] == 0 || out1[k][2] == 0 || out1[k][0] == 255 || out1[k][1] == 255 || out1[k][2] == 255) - continue; - ++total; - if (out1[k][0] != out2[k][0] || out1[k][1] != out2[k][1] || out1[k][2] != out2[k][2]) { - int dist1 = abs(out1[k][0] - out2[k][0]); - int dist2 = abs(out1[k][1] - out2[k][1]); - int dist3 = abs(out1[k][2] - out2[k][2]); - ++count; - if (out1[k][1] > out2[k][1]) - ++bigcount; - } - } - } - printf("So far: %d (%d big) of %d\n", count, bigcount, total); - } - printf("Final: %d (%d big) of %d\n", count, bigcount, total); -} -#endif - -float hdr_data[200][200][3]; - -void dummy_write(void *context, void *data, int len) -{ - static char dummy[1024]; - if (len > 1024) len = 1024; - memcpy(dummy, data, len); -} - -extern void image_write_test(void); - -int main(int argc, char **argv) -{ - int w,h; - //test_ycbcr(); - - image_write_test(); - - #if 0 - // test hdr asserts - for (h=0; h < 100; h += 2) - for (w=0; w < 200; ++w) - hdr_data[h][w][0] = (float) rand(), - hdr_data[h][w][1] = (float) rand(), - hdr_data[h][w][2] = (float) rand(); - - stbi_write_hdr("output/test.hdr", 200,200,3,hdr_data[0][0]); - #endif - - if (argc > 1) { - int i, n; - - for (i=1; i < argc; ++i) { - int res; - int w2,h2,n2; - unsigned char *data; - printf("%s\n", argv[i]); - res = stbi_info(argv[i], &w2, &h2, &n2); - data = stbi_load(argv[i], &w, &h, &n, 0); if (data) free(data); else printf("Failed &n\n"); - data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n"); - data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n"); - data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n"); - data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n"); - data = stbi_load(argv[i], &w, &h, &n, 4); - assert(data); - assert(w == w2 && h == h2 && n == n2); - assert(res); - if (data) { - char fname[512]; - stb_splitpath(fname, argv[i], STB_FILE); - stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4); - stbi_write_bmp(stb_sprintf("output/%s.bmp", fname), w, h, 4, data); - stbi_write_tga(stb_sprintf("output/%s.tga", fname), w, h, 4, data); - stbi_write_png_to_func(dummy_write,0, w, h, 4, data, w*4); - stbi_write_bmp_to_func(dummy_write,0, w, h, 4, data); - stbi_write_tga_to_func(dummy_write,0, w, h, 4, data); - free(data); - } else - printf("FAILED 4\n"); - } - } else { - int i; - #ifdef PNGSUITE_PRIMARY - char **files = stb_readdir_files("pngsuite/primary"); - #else - char **files = stb_readdir_files("images"); - #endif - for (i=0; i < stb_arr_len(files); ++i) { - int n; - char **failed = NULL; - unsigned char *data; - printf("."); - //printf("%s\n", files[i]); - data = stbi_load(files[i], &w, &h, &n, 0); if (data) free(data); else stb_arr_push(failed, "&n"); - data = stbi_load(files[i], &w, &h, 0, 1); if (data) free(data); else stb_arr_push(failed, "1"); - data = stbi_load(files[i], &w, &h, 0, 2); if (data) free(data); else stb_arr_push(failed, "2"); - data = stbi_load(files[i], &w, &h, 0, 3); if (data) free(data); else stb_arr_push(failed, "3"); - data = stbi_load(files[i], &w, &h, 0, 4); if (data) ; else stb_arr_push(failed, "4"); - if (data) { - char fname[512]; - - #ifdef PNGSUITE_PRIMARY - int w2,h2; - unsigned char *data2; - stb_splitpath(fname, files[i], STB_FILE_EXT); - data2 = stbi_load(stb_sprintf("pngsuite/primary_check/%s", fname), &w2, &h2, 0, 4); - if (!data2) - printf("FAILED: couldn't load 'pngsuite/primary_check/%s\n", fname); - else { - if (w != w2 || h != w2 || 0 != memcmp(data, data2, w*h*4)) { - int x,y,c; - if (w == w2 && h == h2) - for (y=0; y < h; ++y) - for (x=0; x < w; ++x) - for (c=0; c < 4; ++c) - assert(data[y*w*4+x*4+c] == data2[y*w*4+x*4+c]); - printf("FAILED: %s loaded but didn't match PRIMARY_check 32-bit version\n", files[i]); - } - free(data2); - } - #else - stb_splitpath(fname, files[i], STB_FILE); - stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4); - #endif - free(data); - } - if (failed) { - int j; - printf("FAILED: "); - for (j=0; j < stb_arr_len(failed); ++j) - printf("%s ", failed[j]); - printf(" -- %s\n", files[i]); - } - } - printf("Tested %d files.\n", i); - } - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/image_test.dsp b/source/engine/thirdparty/stb/tests/image_test.dsp deleted file mode 100644 index 65f0aaf..0000000 --- a/source/engine/thirdparty/stb/tests/image_test.dsp +++ /dev/null @@ -1,103 +0,0 @@ -# Microsoft Developer Studio Project File - Name="image_test" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=image_test - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "image_test.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "image_test.mak" CFG="image_test - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "image_test - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "image_test - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "image_test - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /Zi /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 - -!ELSEIF "$(CFG)" == "image_test - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug\image_test" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "image_test - Win32 Release" -# Name "image_test - Win32 Debug" -# Begin Source File - -SOURCE=.\image_test.c -# End Source File -# Begin Source File - -SOURCE=.\image_write_test.c -# End Source File -# Begin Source File - -SOURCE=..\stb_image.h -# End Source File -# Begin Source File - -SOURCE=..\stb_image_write.h -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/image_write_test.c b/source/engine/thirdparty/stb/tests/image_write_test.c deleted file mode 100644 index 4e4a7e8..0000000 --- a/source/engine/thirdparty/stb/tests/image_write_test.c +++ /dev/null @@ -1,60 +0,0 @@ -#ifdef __clang__ -#define STBIWDEF static inline -#endif -#define STB_IMAGE_WRITE_STATIC -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -// using an 'F' since it has no rotational symmetries, and 6x5 -// because it's a small, atypical size likely to trigger edge cases. -// -// conveniently, it's also small enough to fully fit inside a typical -// directory listing thumbnail, which simplifies checking at a glance. -static const char img6x5_template[] = - ".****." - ".*...." - ".***.." - ".*...." - ".*...."; - -void image_write_test(void) -{ - // make a RGB version of the template image - // use red on blue to detect R<->B swaps - unsigned char img6x5_rgb[6*5*3]; - float img6x5_rgbf[6*5*3]; - int i; - - for (i = 0; i < 6*5; i++) { - int on = img6x5_template[i] == '*'; - img6x5_rgb[i*3 + 0] = on ? 255 : 0; - img6x5_rgb[i*3 + 1] = 0; - img6x5_rgb[i*3 + 2] = on ? 0 : 255; - - img6x5_rgbf[i*3 + 0] = on ? 1.0f : 0.0f; - img6x5_rgbf[i*3 + 1] = 0.0f; - img6x5_rgbf[i*3 + 2] = on ? 0.0f : 1.0f; - } - - stbi_write_png("output/wr6x5_regular.png", 6, 5, 3, img6x5_rgb, 6*3); - stbi_write_bmp("output/wr6x5_regular.bmp", 6, 5, 3, img6x5_rgb); - stbi_write_tga("output/wr6x5_regular.tga", 6, 5, 3, img6x5_rgb); - stbi_write_jpg("output/wr6x5_regular.jpg", 6, 5, 3, img6x5_rgb, 95); - stbi_write_hdr("output/wr6x5_regular.hdr", 6, 5, 3, img6x5_rgbf); - - stbi_flip_vertically_on_write(1); - - stbi_write_png("output/wr6x5_flip.png", 6, 5, 3, img6x5_rgb, 6*3); - stbi_write_bmp("output/wr6x5_flip.bmp", 6, 5, 3, img6x5_rgb); - stbi_write_tga("output/wr6x5_flip.tga", 6, 5, 3, img6x5_rgb); - stbi_write_jpg("output/wr6x5_flip.jpg", 6, 5, 3, img6x5_rgb, 95); - stbi_write_hdr("output/wr6x5_flip.hdr", 6, 5, 3, img6x5_rgbf); -} - -#ifdef IWT_TEST -int main(int argc, char **argv) -{ - image_write_test(); - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/ossfuzz.sh b/source/engine/thirdparty/stb/tests/ossfuzz.sh deleted file mode 100755 index 2db2060..0000000 --- a/source/engine/thirdparty/stb/tests/ossfuzz.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -eu -# This script is meant to be run by -# https://github.com/google/oss-fuzz/blob/master/projects/stb/Dockerfile - -$CXX $CXXFLAGS -std=c++11 -I. -DSTBI_ONLY_PNG \ - $SRC/stb/tests/stbi_read_fuzzer.c \ - -o $OUT/stb_png_read_fuzzer $LIB_FUZZING_ENGINE - -$CXX $CXXFLAGS -std=c++11 -I. \ - $SRC/stb/tests/stbi_read_fuzzer.c \ - -o $OUT/stbi_read_fuzzer $LIB_FUZZING_ENGINE - -find $SRC/stb/tests/pngsuite -name "*.png" | \ - xargs zip $OUT/stb_png_read_fuzzer_seed_corpus.zip - -cp $SRC/stb/tests/stb_png.dict $OUT/stb_png_read_fuzzer.dict - -tar xvzf $SRC/stbi/jpg.tar.gz --directory $SRC/stb/tests -tar xvzf $SRC/stbi/gif.tar.gz --directory $SRC/stb/tests -unzip $SRC/stbi/bmp.zip -d $SRC/stb/tests -unzip $SRC/stbi/tga.zip -d $SRC/stb/tests - -find $SRC/stb/tests -name "*.png" -o -name "*.jpg" -o -name "*.gif" \ - -o -name "*.bmp" -o -name "*.tga" -o -name "*.TGA" \ - -o -name "*.ppm" -o -name "*.pgm" \ - | xargs zip $OUT/stbi_read_fuzzer_seed_corpus.zip - -echo "" >> $SRC/stbi/gif.dict -cat $SRC/stbi/gif.dict $SRC/stb/tests/stb_png.dict > $OUT/stbi_read_fuzzer.dict diff --git a/source/engine/thirdparty/stb/tests/oversample/README.md b/source/engine/thirdparty/stb/tests/oversample/README.md deleted file mode 100644 index cdfdfff..0000000 --- a/source/engine/thirdparty/stb/tests/oversample/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# Font character oversampling for rendering from atlas textures - -TL,DR: Run oversample.exe on a windows machine to see the -benefits of oversampling. It will try to use arial.ttf from the -Windows font directory unless you type the name of a .ttf file as -a command-line argument. - -## Benefits of oversampling - -Oversampling is a mechanism for improving subpixel rendering of characters. - -Improving subpixel has a few benefits: - -* With horizontal-oversampling, text can remain sharper while still being sub-pixel positioned for better kerning -* Horizontally-oversampled text significantly reduces aliasing when text animates horizontally -* Vertically-oversampled text significantly reduces aliasing when text animates vertically -* Text oversampled in both directions significantly reduces aliasing when text rotates - -## What text oversampling is - -A common strategy for rendering text is to cache character bitmaps -and reuse them. For hinted characters, every instance of a given -character is always identical, so this works fine. However, stb_truetype -doesn't do hinting. - -For anti-aliased characters, you can actually position the characters -with subpixel precision, and get different bitmaps based on that positioning -if you re-render the vector data. - -However, if you simply cache a single version of the bitmap and -draw it at different subpixel positions with a GPU, you will get -either the exact same result (if you use point-sampling on the -texture) or linear filtering. Linear filtering will cause a sub-pixel -positioned bitmap to blur further, causing a visible de-sharpening -of the character. (And, since the character wasn't hinted, it was -already blurrier than a hinted one would be, and now it gets even -more blurry.) - -You can avoid this by caching multiple variants of a character which -were rendered independently from the vector data. For example, you -might cache 3 versions of a char, at 0, 1/3, and 2/3rds of a pixel -horizontal offset, and always require characters to fall on integer -positions vertically. - -When creating a texture atlas for use on GPUs, which support bilinear -filtering, there is a better approach than caching several independent -positions, which is to allow lerping between the versions to allow -finer subpixel positioning. You can achieve these by interleaving -each of the cached bitmaps, but this turns out to be mathematically -equivalent to a simpler operation: oversampling and prefiltering the -characters. - -So, setting oversampling of 2x2 in stb_truetype is equivalent to caching -each character in 4 different variations, 1 for each subpixel position -in a 2x2 set. - -An advantage of this formulation is that no changes are required to -the rendering code; the exact same quad-rendering code works, it just -uses different texture coordinates. (Note this does potentially increase -texture bandwidth for text rendering since we end up minifying the texture -without using mipmapping, but you probably are not going to be fill-bound -by your text rendering.) - -## What about gamma? - -Gamma-correction for fonts just doesn't work. This doesn't seem to make -much sense -- it's physically correct, it simulates what we'd see if you -shrunk a font down really far, right? - -But you can play with it in the oversample.exe app. If you turn it on, -white-on-black fonts become too thick (i.e. they become too bright), and -black-on-white fonts become too thin (i.e. they are insufficiently dark). There is -no way to adjust the font's inherent thickness (i.e. by switching to -bold) to fix this for both; making the font thicker will make white -text worse, and making the font thinner will make black text worse. -Obviously you could use different fonts for light and dark cases, but -this doesn't seem like a very good way for fonts to work. - -Multiple people who have experimented with this independently (me, -Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all -concluded that correct gamma-correction does not produce the best -results for fonts. Font rendering just generally looks better without -gamma correction (or possibly with some arbitrary power stuck in -there, but it's not really correcting for gamma at that point). Maybe -this is in part a product of how we're used to fonts being on screens -which has changed how we expect them to look (e.g. perhaps hinting -oversharpens them and prevents the real-world thinning you'd see in -a black-on-white text). - -(AGG link on text rendering, including mention of gamma: - http://www.antigrain.com/research/font_rasterization/ ) - -Nevertheless, even if you turn on gamma-correction, you will find that -oversampling still helps in many cases for small fonts. diff --git a/source/engine/thirdparty/stb/tests/oversample/main.c b/source/engine/thirdparty/stb/tests/oversample/main.c deleted file mode 100644 index bc6bd0f..0000000 --- a/source/engine/thirdparty/stb/tests/oversample/main.c +++ /dev/null @@ -1,332 +0,0 @@ -#pragma warning(disable:4244; disable:4305; disable:4018) -#include -#include - -#define STB_WINMAIN -#include "stb_wingraph.h" - -#define STB_TRUETYPE_IMPLEMENTATION -#define STB_RECT_PACK_IMPLEMENTATION -#include "stb_rect_pack.h" -#include "stb_truetype.h" - -#ifndef WINGDIAPI -#define CALLBACK __stdcall -#define WINGDIAPI __declspec(dllimport) -#define APIENTRY __stdcall -#endif - -#include -#include - -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 - -#define SIZE_X 1024 -#define SIZE_Y 768 - -stbtt_packedchar chardata[6][128]; - -int sx=SIZE_X, sy=SIZE_Y; - -#define BITMAP_W 512 -#define BITMAP_H 512 -unsigned char temp_bitmap[BITMAP_W][BITMAP_H]; -unsigned char ttf_buffer[1 << 25]; -GLuint font_tex; - -float scale[2] = { 24.0f, 14.0f }; - -int sf[6] = { 0,1,2, 0,1,2 }; - -void load_fonts(void) -{ - stbtt_pack_context pc; - int i; - FILE *f; - char filename[256]; - char *win = getenv("windir"); - if (win == NULL) win = getenv("SystemRoot"); - - f = fopen(stb_wingraph_commandline, "rb"); - if (!f) { - if (win == NULL) - sprintf(filename, "arial.ttf", win); - else - sprintf(filename, "%s/fonts/arial.ttf", win); - f = fopen(filename, "rb"); - if (!f) exit(0); - } - - fread(ttf_buffer, 1, 1<<25, f); - - stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); - for (i=0; i < 2; ++i) { - stbtt_PackSetOversampling(&pc, 1, 1); - stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+0]+32); - stbtt_PackSetOversampling(&pc, 2, 2); - stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+1]+32); - stbtt_PackSetOversampling(&pc, 3, 1); - stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+2]+32); - } - stbtt_PackEnd(&pc); - - glGenTextures(1, &font_tex); - glBindTexture(GL_TEXTURE_2D, font_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, BITMAP_W, BITMAP_H, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -} - -int black_on_white; - -void draw_init(void) -{ - glDisable(GL_CULL_FACE); - glDisable(GL_TEXTURE_2D); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - - glViewport(0,0,sx,sy); - if (black_on_white) - glClearColor(255,255,255,0); - else - glClearColor(0,0,0,0); - glClear(GL_COLOR_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(0,sx,sy,0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -} - - -void drawBoxTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1) -{ - glTexCoord2f(s0,t0); glVertex2f(x0,y0); - glTexCoord2f(s1,t0); glVertex2f(x1,y0); - glTexCoord2f(s1,t1); glVertex2f(x1,y1); - glTexCoord2f(s0,t1); glVertex2f(x0,y1); -} - -int integer_align; - -void print(float x, float y, int font, char *text) -{ - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, font_tex); - glBegin(GL_QUADS); - while (*text) { - stbtt_aligned_quad q; - stbtt_GetPackedQuad(chardata[font], BITMAP_W, BITMAP_H, *text++, &x, &y, &q, font ? 0 : integer_align); - drawBoxTC(q.x0,q.y0,q.x1,q.y1, q.s0,q.t0,q.s1,q.t1); - } - glEnd(); -} - -int font=3; -int translating; -int rotating=0; -int srgb=0; -float rotate_t, translate_t; -int show_tex; - -void draw_world(void) -{ - int sfont = sf[font]; - float x = 20; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - if (black_on_white) - glColor3f(0,0,0); - else - glColor3f(1,1,1); - - - print(80, 30, sfont, "Controls:"); - print(100, 60, sfont, "S: toggle font size"); - print(100, 85, sfont, "O: toggle oversampling"); - print(100,110, sfont, "T: toggle translation"); - print(100,135, sfont, "R: toggle rotation"); - print(100,160, sfont, "P: toggle pixel-snap (only non-oversampled)"); - print(100,185, sfont, "G: toggle srgb gamma-correction"); - if (black_on_white) - print(100,210, sfont, "B: toggle to white-on-black"); - else - print(100,210, sfont, "B: toggle to black-on-white"); - print(100,235, sfont, "V: view font texture"); - - print(80, 300, sfont, "Current font:"); - - if (!show_tex) { - if (font < 3) - print(100, 350, sfont, "Font height: 24 pixels"); - else - print(100, 350, sfont, "Font height: 14 pixels"); - } - - if (font%3==1) - print(100, 325, sfont, "2x2 oversampled text at 1:1"); - else if (font%3 == 2) - print(100, 325, sfont, "3x1 oversampled text at 1:1"); - else if (integer_align) - print(100, 325, sfont, "1:1 text, one texel = one pixel, snapped to integer coordinates"); - else - print(100, 325, sfont, "1:1 text, one texel = one pixel"); - - if (show_tex) { - glBegin(GL_QUADS); - drawBoxTC(200,400, 200+BITMAP_W,300+BITMAP_H, 0,0,1,1); - glEnd(); - } else { - glMatrixMode(GL_MODELVIEW); - glTranslatef(200,350,0); - - if (translating) - x += fmod(translate_t*8,30); - - if (rotating) { - glTranslatef(100,150,0); - glRotatef(rotate_t*2,0,0,1); - glTranslatef(-100,-150,0); - } - print(x,100, font, "This is a test"); - print(x,130, font, "Now is the time for all good men to come to the aid of their country."); - print(x,160, font, "The quick brown fox jumps over the lazy dog."); - print(x,190, font, "0123456789"); - } -} - -void draw(void) -{ - draw_init(); - draw_world(); - stbwingraph_SwapBuffers(NULL); -} - -static int initialized=0; -static float last_dt; - -int move[4]; -int raw_mouse_x, raw_mouse_y; - -int loopmode(float dt, int real, int in_client) -{ - float actual_dt = dt; - - if (!initialized) return 0; - - rotate_t += dt; - translate_t += dt; - -// music_sim(); - if (!real) - return 0; - - if (dt > 0.25) dt = 0.25; - if (dt < 0.01) dt = 0.01; - - draw(); - - return 0; -} - -int winproc(void *data, stbwingraph_event *e) -{ - switch (e->type) { - case STBWGE_create: - break; - - case STBWGE_char: - switch(e->key) { - case 27: - stbwingraph_ShowCursor(NULL,1); - return STBWINGRAPH_winproc_exit; - break; - case 'o': case 'O': - font = (font+1) % 3 + (font/3)*3; - break; - case 's': case 'S': - font = (font+3) % 6; - break; - case 't': case 'T': - translating = !translating; - translate_t = 0; - break; - case 'r': case 'R': - rotating = !rotating; - rotate_t = 0; - break; - case 'p': case 'P': - integer_align = !integer_align; - break; - case 'g': case 'G': - srgb = !srgb; - if (srgb) - glEnable(GL_FRAMEBUFFER_SRGB_EXT); - else - glDisable(GL_FRAMEBUFFER_SRGB_EXT); - break; - case 'v': case 'V': - show_tex = !show_tex; - break; - case 'b': case 'B': - black_on_white = !black_on_white; - break; - } - break; - - case STBWGE_mousemove: - raw_mouse_x = e->mx; - raw_mouse_y = e->my; - break; - -#if 0 - case STBWGE_mousewheel: do_mouse(e,0,0); break; - case STBWGE_leftdown: do_mouse(e, 1,0); break; - case STBWGE_leftup: do_mouse(e,-1,0); break; - case STBWGE_rightdown: do_mouse(e,0, 1); break; - case STBWGE_rightup: do_mouse(e,0,-1); break; -#endif - - case STBWGE_keydown: - if (e->key == VK_RIGHT) move[0] = 1; - if (e->key == VK_LEFT) move[1] = 1; - if (e->key == VK_UP) move[2] = 1; - if (e->key == VK_DOWN) move[3] = 1; - break; - case STBWGE_keyup: - if (e->key == VK_RIGHT) move[0] = 0; - if (e->key == VK_LEFT) move[1] = 0; - if (e->key == VK_UP) move[2] = 0; - if (e->key == VK_DOWN) move[3] = 0; - break; - - case STBWGE_size: - sx = e->width; - sy = e->height; - loopmode(0,1,0); - break; - - case STBWGE_draw: - if (initialized) - loopmode(0,1,0); - break; - - default: - return STBWINGRAPH_unprocessed; - } - return 0; -} - -void stbwingraph_main(void) -{ - stbwingraph_Priority(2); - stbwingraph_CreateWindow(1, winproc, NULL, "tt", SIZE_X,SIZE_Y, 0, 1, 0, 0); - stbwingraph_ShowCursor(NULL, 0); - load_fonts(); - initialized = 1; - stbwingraph_MainLoop(loopmode, 0.016f); // 30 fps = 0.33 -} - diff --git a/source/engine/thirdparty/stb/tests/oversample/oversample.dsp b/source/engine/thirdparty/stb/tests/oversample/oversample.dsp deleted file mode 100644 index cc1edc3..0000000 --- a/source/engine/thirdparty/stb/tests/oversample/oversample.dsp +++ /dev/null @@ -1,97 +0,0 @@ -# Microsoft Developer Studio Project File - Name="oversample" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=oversample - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "oversample.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "oversample.mak" CFG="oversample - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "oversample - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "oversample - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "oversample - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /WX /GX /O2 /I "c:\sean\prj\stb" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# SUBTRACT LINK32 /map /debug - -!ELSEIF "$(CFG)" == "oversample - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /WX /Gm /GX /Zi /Od /I "c:\sean\prj\stb" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "oversample - Win32 Release" -# Name "oversample - Win32 Debug" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/oversample/oversample.dsw b/source/engine/thirdparty/stb/tests/oversample/oversample.dsw deleted file mode 100644 index 0f5aa7f..0000000 --- a/source/engine/thirdparty/stb/tests/oversample/oversample.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "oversample"=.\oversample.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/source/engine/thirdparty/stb/tests/oversample/oversample.exe b/source/engine/thirdparty/stb/tests/oversample/oversample.exe deleted file mode 100644 index 0040693..0000000 Binary files a/source/engine/thirdparty/stb/tests/oversample/oversample.exe and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/oversample/stb_wingraph.h b/source/engine/thirdparty/stb/tests/oversample/stb_wingraph.h deleted file mode 100644 index 94798eb..0000000 --- a/source/engine/thirdparty/stb/tests/oversample/stb_wingraph.h +++ /dev/null @@ -1,829 +0,0 @@ -// stb_wingraph.h v0.01 - public domain windows graphics programming -// wraps WinMain, ChoosePixelFormat, ChangeDisplayResolution, etc. for -// doing OpenGL graphics -// -// in ONE source file, put '#define STB_DEFINE' before including this -// OR put '#define STB_WINMAIN' to define a WinMain that calls stbwingraph_main(void) -// -// @TODO: -// 2d rendering interface (that can be done easily in software) -// STB_WINGRAPH_SOFTWARE -- 2d software rendering only -// STB_WINGRAPH_OPENGL -- OpenGL only - - -#ifndef INCLUDE_STB_WINGRAPH_H -#define INCLUDE_STB_WINGRAPH_H - -#ifdef STB_WINMAIN - #ifndef STB_DEFINE - #define STB_DEFINE - #define STB_WINGRAPH_DISABLE_DEFINE_AT_END - #endif -#endif - -#ifdef STB_DEFINE - #pragma comment(lib, "opengl32.lib") - #pragma comment(lib, "glu32.lib") - #pragma comment(lib, "winmm.lib") - #pragma comment(lib, "gdi32.lib") - #pragma comment(lib, "user32.lib") -#endif - -#ifdef __cplusplus -#define STB_EXTERN extern "C" -#else -#define STB_EXTERN -#endif - -#ifdef STB_DEFINE -#ifndef _WINDOWS_ - #ifdef APIENTRY - #undef APIENTRY - #endif - #ifdef WINGDIAPI - #undef WINGDIAPI - #endif - #define _WIN32_WINNT 0x0400 // WM_MOUSEWHEEL - #include -#endif -#include -#include -#include -#include -#include -#endif - -typedef void * stbwingraph_hwnd; -typedef void * stbwingraph_hinstance; - -enum -{ - STBWINGRAPH_unprocessed = -(1 << 24), - STBWINGRAPH_do_not_show, - STBWINGRAPH_winproc_exit, - STBWINGRAPH_winproc_update, - STBWINGRAPH_update_exit, - STBWINGRAPH_update_pause, -}; - -typedef enum -{ - STBWGE__none=0, - - STBWGE_create, - STBWGE_create_postshow, - STBWGE_draw, - STBWGE_destroy, - STBWGE_char, - STBWGE_keydown, - STBWGE_syskeydown, - STBWGE_keyup, - STBWGE_syskeyup, - STBWGE_deactivate, - STBWGE_activate, - STBWGE_size, - - STBWGE_mousemove , - STBWGE_leftdown , STBWGE_leftup , - STBWGE_middledown, STBWGE_middleup, - STBWGE_rightdown , STBWGE_rightup , - STBWGE_mousewheel, -} stbwingraph_event_type; - -typedef struct -{ - stbwingraph_event_type type; - - // for input events (mouse, keyboard) - int mx,my; // mouse x & y - int dx,dy; - int shift, ctrl, alt; - - // for keyboard events - int key; - - // for STBWGE_size: - int width, height; - - // for STBWGE_crate - int did_share_lists; // if true, wglShareLists succeeded - - void *handle; - -} stbwingraph_event; - -typedef int (*stbwingraph_window_proc)(void *data, stbwingraph_event *event); - -extern stbwingraph_hinstance stbwingraph_app; -extern stbwingraph_hwnd stbwingraph_primary_window; -extern int stbwingraph_request_fullscreen; -extern int stbwingraph_request_windowed; - -STB_EXTERN void stbwingraph_ods(char *str, ...); -STB_EXTERN int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, - char *caption, char *text, ...); -STB_EXTERN int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, - unsigned int bits, int use_message_box); -STB_EXTERN int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, - int alpha_bits, int depth_bits, int stencil_bits, int accum_bits); -STB_EXTERN int stbwingraph_DefineClass(void *hinstance, char *iconname); -STB_EXTERN void stbwingraph_SwapBuffers(void *win); -STB_EXTERN void stbwingraph_Priority(int n); - -STB_EXTERN void stbwingraph_MakeFonts(void *window, int font_base); -STB_EXTERN void stbwingraph_ShowWindow(void *window); -STB_EXTERN void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil); -STB_EXTERN void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height); -STB_EXTERN void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh); -STB_EXTERN void stbwingraph_DestroyWindow(void *window); -STB_EXTERN void stbwingraph_ShowCursor(void *window, int visible); -STB_EXTERN float stbwingraph_GetTimestep(float minimum_time); -STB_EXTERN void stbwingraph_SetGLWindow(void *win); -typedef int (*stbwingraph_update)(float timestep, int real, int in_client); -STB_EXTERN int stbwingraph_MainLoop(stbwingraph_update func, float mintime); - -#ifdef STB_DEFINE -stbwingraph_hinstance stbwingraph_app; -stbwingraph_hwnd stbwingraph_primary_window; -int stbwingraph_request_fullscreen; -int stbwingraph_request_windowed; - -void stbwingraph_ods(char *str, ...) -{ - char buffer[1024]; - va_list v; - va_start(v,str); - vsprintf(buffer, str, v); - va_end(v); - OutputDebugString(buffer); -} - -int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, char *caption, char *text, ...) -{ - va_list v; - char buffer[1024]; - va_start(v, text); - vsprintf(buffer, text, v); - va_end(v); - return MessageBox(win, buffer, caption, type); -} - -void stbwingraph_Priority(int n) -{ - int p; - switch (n) { - case -1: p = THREAD_PRIORITY_BELOW_NORMAL; break; - case 0: p = THREAD_PRIORITY_NORMAL; break; - case 1: p = THREAD_PRIORITY_ABOVE_NORMAL; break; - default: - if (n < 0) p = THREAD_PRIORITY_LOWEST; - else p = THREAD_PRIORITY_HIGHEST; - } - SetThreadPriority(GetCurrentThread(), p); -} - -static void stbwingraph_ResetResolution(void) -{ - ChangeDisplaySettings(NULL, 0); -} - -static void stbwingraph_RegisterResetResolution(void) -{ - static int done=0; - if (!done) { - done = 1; - atexit(stbwingraph_ResetResolution); - } -} - -int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, unsigned int bits, int use_message_box) -{ - DEVMODE mode; - int res; - - int i, tries=0; - for (i=0; ; ++i) { - int success = EnumDisplaySettings(NULL, i, &mode); - if (!success) break; - if (mode.dmBitsPerPel == bits && mode.dmPelsWidth == w && mode.dmPelsHeight == h) { - ++tries; - success = ChangeDisplaySettings(&mode, CDS_FULLSCREEN); - if (success == DISP_CHANGE_SUCCESSFUL) { - stbwingraph_RegisterResetResolution(); - return TRUE; - } - break; - } - } - - if (!tries) { - if (use_message_box) - stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); - return FALSE; - } - - // we tried but failed, so try explicitly doing it without specifying refresh rate - - // Win95 support logic - mode.dmBitsPerPel = bits; - mode.dmPelsWidth = w; - mode.dmPelsHeight = h; - mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - - res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN); - - switch (res) { - case DISP_CHANGE_SUCCESSFUL: - stbwingraph_RegisterResetResolution(); - return TRUE; - - case DISP_CHANGE_RESTART: - if (use_message_box) - stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "Please set your desktop to %d-bit color and then try again."); - return FALSE; - - case DISP_CHANGE_FAILED: - if (use_message_box) - stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The hardware failed to change modes."); - return FALSE; - - case DISP_CHANGE_BADMODE: - if (use_message_box) - stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); - return FALSE; - - default: - if (use_message_box) - stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "An unknown error prevented a change to a %d x %d x %d-bit display.", w, h, bits); - return FALSE; - } -} - -int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, int alpha_bits, int depth_bits, int stencil_bits, int accum_bits) -{ - HDC dc = GetDC(win); - PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd) }; - int pixel_format; - - pfd.nVersion = 1; - pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; - pfd.dwLayerMask = PFD_MAIN_PLANE; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = color_bits; - pfd.cAlphaBits = alpha_bits; - pfd.cDepthBits = depth_bits; - pfd.cStencilBits = stencil_bits; - pfd.cAccumBits = accum_bits; - - pixel_format = ChoosePixelFormat(dc, &pfd); - if (!pixel_format) return FALSE; - - if (!DescribePixelFormat(dc, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) - return FALSE; - SetPixelFormat(dc, pixel_format, &pfd); - - return TRUE; -} - -typedef struct -{ - // app data - stbwingraph_window_proc func; - void *data; - // creation parameters - int color, alpha, depth, stencil, accum; - HWND share_window; - HWND window; - // internal data - HGLRC rc; - HDC dc; - int hide_mouse; - int in_client; - int active; - int did_share_lists; - int mx,my; // last mouse positions -} stbwingraph__window; - -static void stbwingraph__inclient(stbwingraph__window *win, int state) -{ - if (state != win->in_client) { - win->in_client = state; - if (win->hide_mouse) - ShowCursor(!state); - } -} - -static void stbwingraph__key(stbwingraph_event *e, int type, int key, stbwingraph__window *z) -{ - e->type = type; - e->key = key; - e->shift = (GetKeyState(VK_SHIFT) < 0); - e->ctrl = (GetKeyState(VK_CONTROL) < 0); - e->alt = (GetKeyState(VK_MENU) < 0); - if (z) { - e->mx = z->mx; - e->my = z->my; - } else { - e->mx = e->my = 0; - } - e->dx = e->dy = 0; -} - -static void stbwingraph__mouse(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) -{ - static int captured = 0; - e->type = type; - e->mx = (short) LOWORD(lparam); - e->my = (short) HIWORD(lparam); - if (!z || z->mx == -(1 << 30)) { - e->dx = e->dy = 0; - } else { - e->dx = e->mx - z->mx; - e->dy = e->my - z->my; - } - e->shift = (wparam & MK_SHIFT) != 0; - e->ctrl = (wparam & MK_CONTROL) != 0; - e->alt = (wparam & MK_ALT) != 0; - if (z) { - z->mx = e->mx; - z->my = e->my; - } - if (capture) { - if (!captured && capture == 1) - SetCapture(wnd); - captured += capture; - if (!captured && capture == -1) - ReleaseCapture(); - if (captured < 0) captured = 0; - } -} - -static void stbwingraph__mousewheel(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) -{ - // lparam seems bogus! - static int captured = 0; - e->type = type; - if (z) { - e->mx = z->mx; - e->my = z->my; - } - e->dx = e->dy = 0; - e->shift = (wparam & MK_SHIFT) != 0; - e->ctrl = (wparam & MK_CONTROL) != 0; - e->alt = (GetKeyState(VK_MENU) < 0); - e->key = ((int) wparam >> 16); -} - -int stbwingraph_force_update; -static int WINAPI stbwingraph_WinProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - int allow_default = TRUE; - stbwingraph_event e = { STBWGE__none }; - // the following line is wrong for 64-bit windows, but VC6 doesn't have GetWindowLongPtr - stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(wnd, GWL_USERDATA); - - switch (msg) { - - case WM_CREATE: - { - LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam; - assert(z == NULL); - z = (stbwingraph__window *) lpcs->lpCreateParams; - SetWindowLong(wnd, GWL_USERDATA, (LONG) z); - z->dc = GetDC(wnd); - if (stbwingraph_SetPixelFormat(wnd, z->color, z->alpha, z->depth, z->stencil, z->accum)) { - z->rc = wglCreateContext(z->dc); - if (z->rc) { - e.type = STBWGE_create; - z->did_share_lists = FALSE; - if (z->share_window) { - stbwingraph__window *y = (stbwingraph__window *) GetWindowLong(z->share_window, GWL_USERDATA); - if (wglShareLists(z->rc, y->rc)) - z->did_share_lists = TRUE; - } - wglMakeCurrent(z->dc, z->rc); - return 0; - } - } - return -1; - } - - case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(wnd, &ps); - SelectObject(hdc, GetStockObject(NULL_BRUSH)); - e.type = STBWGE_draw; - e.handle = wnd; - z->func(z->data, &e); - EndPaint(wnd, &ps); - return 0; - } - - case WM_DESTROY: - e.type = STBWGE_destroy; - e.handle = wnd; - if (z && z->func) - z->func(z->data, &e); - wglMakeCurrent(NULL, NULL) ; - if (z) { - if (z->rc) wglDeleteContext(z->rc); - z->dc = 0; - z->rc = 0; - } - if (wnd == stbwingraph_primary_window) - PostQuitMessage (0); - return 0; - - case WM_CHAR: stbwingraph__key(&e, STBWGE_char , wparam, z); break; - case WM_KEYDOWN: stbwingraph__key(&e, STBWGE_keydown, wparam, z); break; - case WM_KEYUP: stbwingraph__key(&e, STBWGE_keyup , wparam, z); break; - - case WM_NCMOUSEMOVE: stbwingraph__inclient(z,0); break; - case WM_MOUSEMOVE: stbwingraph__inclient(z,1); stbwingraph__mouse(&e, STBWGE_mousemove, wparam, lparam,0,wnd, z); break; - case WM_LBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_leftdown, wparam, lparam,1,wnd, z); break; - case WM_MBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_middledown, wparam, lparam,1,wnd, z); break; - case WM_RBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_rightdown, wparam, lparam,1,wnd, z); break; - case WM_LBUTTONUP: stbwingraph__mouse(&e, STBWGE_leftup, wparam, lparam,-1,wnd, z); break; - case WM_MBUTTONUP: stbwingraph__mouse(&e, STBWGE_middleup, wparam, lparam,-1,wnd, z); break; - case WM_RBUTTONUP: stbwingraph__mouse(&e, STBWGE_rightup, wparam, lparam,-1,wnd, z); break; - case WM_MOUSEWHEEL: stbwingraph__mousewheel(&e, STBWGE_mousewheel, wparam, lparam,0,wnd, z); break; - - case WM_ACTIVATE: - allow_default = FALSE; - if (LOWORD(wparam)==WA_INACTIVE ) { - wglMakeCurrent(z->dc, NULL); - e.type = STBWGE_deactivate; - z->active = FALSE; - } else { - wglMakeCurrent(z->dc, z->rc); - e.type = STBWGE_activate; - z->active = TRUE; - } - e.handle = wnd; - z->func(z->data, &e); - return 0; - - case WM_SIZE: { - RECT rect; - allow_default = FALSE; - GetClientRect(wnd, &rect); - e.type = STBWGE_size; - e.width = rect.right; - e.height = rect.bottom; - e.handle = wnd; - z->func(z->data, &e); - return 0; - } - - default: - return DefWindowProc (wnd, msg, wparam, lparam); - } - - if (e.type != STBWGE__none) { - int n; - e.handle = wnd; - n = z->func(z->data, &e); - if (n == STBWINGRAPH_winproc_exit) { - PostQuitMessage(0); - n = 0; - } - if (n == STBWINGRAPH_winproc_update) { - stbwingraph_force_update = TRUE; - return 1; - } - if (n != STBWINGRAPH_unprocessed) - return n; - } - return DefWindowProc (wnd, msg, wparam, lparam); -} - -int stbwingraph_DefineClass(HINSTANCE hInstance, char *iconname) -{ - WNDCLASSEX wndclass; - - stbwingraph_app = hInstance; - - wndclass.cbSize = sizeof(wndclass); - wndclass.style = CS_OWNDC; - wndclass.lpfnWndProc = (WNDPROC) stbwingraph_WinProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = hInstance; - wndclass.hIcon = LoadIcon(hInstance, iconname); - wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); - wndclass.hbrBackground = GetStockObject(NULL_BRUSH); - wndclass.lpszMenuName = "zwingraph"; - wndclass.lpszClassName = "zwingraph"; - wndclass.hIconSm = NULL; - - if (!RegisterClassEx(&wndclass)) - return FALSE; - return TRUE; -} - -void stbwingraph_ShowWindow(void *window) -{ - stbwingraph_event e = { STBWGE_create_postshow }; - stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); - ShowWindow(window, SW_SHOWNORMAL); - InvalidateRect(window, NULL, TRUE); - UpdateWindow(window); - e.handle = window; - z->func(z->data, &e); -} - -void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, - int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil) -{ - HWND win; - DWORD dwstyle; - stbwingraph__window *z = (stbwingraph__window *) malloc(sizeof(*z)); - - if (z == NULL) return NULL; - memset(z, 0, sizeof(*z)); - z->color = 24; - z->depth = 24; - z->alpha = dest_alpha; - z->stencil = stencil; - z->func = func; - z->data = data; - z->mx = -(1 << 30); - z->my = 0; - - if (primary) { - if (stbwingraph_request_windowed) - fullscreen = FALSE; - else if (stbwingraph_request_fullscreen) - fullscreen = TRUE; - } - - if (fullscreen) { - #ifdef STB_SIMPLE - stbwingraph_ChangeResolution(width, height, 32, 1); - #else - if (!stbwingraph_ChangeResolution(width, height, 32, 0)) - return NULL; - #endif - dwstyle = WS_POPUP | WS_CLIPSIBLINGS; - } else { - RECT rect; - dwstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - if (resizeable) - dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; - rect.top = 0; - rect.left = 0; - rect.right = width; - rect.bottom = height; - AdjustWindowRect(&rect, dwstyle, FALSE); - width = rect.right - rect.left; - height = rect.bottom - rect.top; - } - - win = CreateWindow("zwingraph", text ? text : "sample", dwstyle, - CW_USEDEFAULT,0, width, height, - NULL, NULL, stbwingraph_app, z); - - if (win == NULL) return win; - - if (primary) { - if (stbwingraph_primary_window) - stbwingraph_DestroyWindow(stbwingraph_primary_window); - stbwingraph_primary_window = win; - } - - { - stbwingraph_event e = { STBWGE_create }; - stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); - z->window = win; - e.did_share_lists = z->did_share_lists; - e.handle = win; - if (z->func(z->data, &e) != STBWINGRAPH_do_not_show) - stbwingraph_ShowWindow(win); - } - - return win; -} - -void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height) -{ - int fullscreen = 0; - #ifndef _DEBUG - if (width == 640 && height == 480) fullscreen = 1; - if (width == 800 && height == 600) fullscreen = 1; - if (width == 1024 && height == 768) fullscreen = 1; - if (width == 1280 && height == 1024) fullscreen = 1; - if (width == 1600 && height == 1200) fullscreen = 1; - //@TODO: widescreen widths - #endif - return stbwingraph_CreateWindow(1, func, NULL, NULL, width, height, fullscreen, 1, 0, 0); -} - -void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh) -{ - if (fullscreen == -1) { - #ifdef _DEBUG - fullscreen = 0; - #else - fullscreen = 1; - #endif - } - - if (fullscreen) { - if (fw) ww = fw; - if (fh) wh = fh; - } - return stbwingraph_CreateWindow(1, func, NULL, NULL, ww, wh, fullscreen, 1, 0, 0); -} - -void stbwingraph_DestroyWindow(void *window) -{ - stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); - DestroyWindow(window); - free(z); - if (stbwingraph_primary_window == window) - stbwingraph_primary_window = NULL; -} - -void stbwingraph_ShowCursor(void *window, int visible) -{ - int hide; - stbwingraph__window *win; - if (!window) - window = stbwingraph_primary_window; - win = (stbwingraph__window *) GetWindowLong((HWND) window, GWL_USERDATA); - hide = !visible; - if (hide != win->hide_mouse) { - win->hide_mouse = hide; - if (!hide) - ShowCursor(TRUE); - else if (win->in_client) - ShowCursor(FALSE); - } -} - -float stbwingraph_GetTimestep(float minimum_time) -{ - float elapsedTime; - double thisTime; - static double lastTime = -1; - - if (lastTime == -1) - lastTime = timeGetTime() / 1000.0 - minimum_time; - - for(;;) { - thisTime = timeGetTime() / 1000.0; - elapsedTime = (float) (thisTime - lastTime); - if (elapsedTime >= minimum_time) { - lastTime = thisTime; - return elapsedTime; - } - #if 1 - Sleep(2); - #endif - } -} - -void stbwingraph_SetGLWindow(void *win) -{ - stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); - if (z) - wglMakeCurrent(z->dc, z->rc); -} - -void stbwingraph_MakeFonts(void *window, int font_base) -{ - wglUseFontBitmaps(GetDC(window ? window : stbwingraph_primary_window), 0, 256, font_base); -} - -// returns 1 if WM_QUIT, 0 if 'func' returned 0 -int stbwingraph_MainLoop(stbwingraph_update func, float mintime) -{ - int needs_drawing = FALSE; - MSG msg; - - int is_animating = TRUE; - if (mintime <= 0) mintime = 0.01f; - - for(;;) { - int n; - - is_animating = TRUE; - // wait for a message if: (a) we're animating and there's already a message - // or (b) we're not animating - if (!is_animating || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { - stbwingraph_force_update = FALSE; - if (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - return 1; // WM_QUIT - } - - // only force a draw for certain messages... - // if I don't do this, we peg at 50% for some reason... must - // be a bug somewhere, because we peg at 100% when rendering... - // very weird... looks like NVIDIA is pumping some messages - // through our pipeline? well, ok, I guess if we can get - // non-user-generated messages we have to do this - if (!stbwingraph_force_update) { - switch (msg.message) { - case WM_MOUSEMOVE: - case WM_NCMOUSEMOVE: - break; - case WM_CHAR: - case WM_KEYDOWN: - case WM_KEYUP: - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_TIMER: - case WM_SIZE: - case WM_ACTIVATE: - needs_drawing = TRUE; - break; - } - } else - needs_drawing = TRUE; - } - - // if another message, process that first - // @TODO: i don't think this is working, because I can't key ahead - // in the SVT demo app - if (PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE)) - continue; - - // and now call update - if (needs_drawing || is_animating) { - int real=1, in_client=1; - if (stbwingraph_primary_window) { - stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(stbwingraph_primary_window, GWL_USERDATA); - if (z && !z->active) { - real = 0; - } - if (z) - in_client = z->in_client; - } - - if (stbwingraph_primary_window) - stbwingraph_SetGLWindow(stbwingraph_primary_window); - n = func(stbwingraph_GetTimestep(mintime), real, in_client); - if (n == STBWINGRAPH_update_exit) - return 0; // update_quit - - is_animating = (n != STBWINGRAPH_update_pause); - - needs_drawing = FALSE; - } - } -} - -void stbwingraph_SwapBuffers(void *win) -{ - stbwingraph__window *z; - if (win == NULL) win = stbwingraph_primary_window; - z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); - if (z && z->dc) - SwapBuffers(z->dc); -} -#endif - -#ifdef STB_WINMAIN -void stbwingraph_main(void); - -char *stb_wingraph_commandline; - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - { - char buffer[1024]; - // add spaces to either side of the string - buffer[0] = ' '; - strcpy(buffer+1, lpCmdLine); - strcat(buffer, " "); - if (strstr(buffer, " -reset ")) { - ChangeDisplaySettings(NULL, 0); - exit(0); - } - if (strstr(buffer, " -window ") || strstr(buffer, " -windowed ")) - stbwingraph_request_windowed = TRUE; - else if (strstr(buffer, " -full ") || strstr(buffer, " -fullscreen ")) - stbwingraph_request_fullscreen = TRUE; - } - stb_wingraph_commandline = lpCmdLine; - - stbwingraph_DefineClass(hInstance, "appicon"); - stbwingraph_main(); - - return 0; -} -#endif - -#undef STB_EXTERN -#ifdef STB_WINGRAPH_DISABLE_DEFINE_AT_END -#undef STB_DEFINE -#endif - -#endif // INCLUDE_STB_WINGRAPH_H diff --git a/source/engine/thirdparty/stb/tests/pbm/basi0g16.pgm b/source/engine/thirdparty/stb/tests/pbm/basi0g16.pgm deleted file mode 100644 index 7241243..0000000 Binary files a/source/engine/thirdparty/stb/tests/pbm/basi0g16.pgm and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pbm/basi2c16.ppm b/source/engine/thirdparty/stb/tests/pbm/basi2c16.ppm deleted file mode 100644 index f2913bb..0000000 Binary files a/source/engine/thirdparty/stb/tests/pbm/basi2c16.ppm and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pbm/cdfn2c08.ppm b/source/engine/thirdparty/stb/tests/pbm/cdfn2c08.ppm deleted file mode 100644 index 1a9e0f0..0000000 Binary files a/source/engine/thirdparty/stb/tests/pbm/cdfn2c08.ppm and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pbm/cdun2c08.ppm b/source/engine/thirdparty/stb/tests/pbm/cdun2c08.ppm deleted file mode 100644 index 2d7202b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pbm/cdun2c08.ppm and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pbm/comment.pgm b/source/engine/thirdparty/stb/tests/pbm/comment.pgm deleted file mode 100644 index aa9dc71..0000000 Binary files a/source/engine/thirdparty/stb/tests/pbm/comment.pgm and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pbm/ctfn0g04.pgm b/source/engine/thirdparty/stb/tests/pbm/ctfn0g04.pgm deleted file mode 100644 index 284f870..0000000 Binary files a/source/engine/thirdparty/stb/tests/pbm/ctfn0g04.pgm and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pg_test/pg_test.c b/source/engine/thirdparty/stb/tests/pg_test/pg_test.c deleted file mode 100644 index c028d5f..0000000 --- a/source/engine/thirdparty/stb/tests/pg_test/pg_test.c +++ /dev/null @@ -1,124 +0,0 @@ -#define STB_DEFINE -#include "stb.h" -#define STB_PG_IMPLEMENTATION -#include "stb_pg.h" -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -static float *hf; -static int hf_width = 10001; -static int hf_height = 10001; - -static float get_height(float x, float y) -{ - float h00,h01,h10,h11,h0,h1; - int ix,iy; - if (x < 0) x = 0; - if (x > hf_width-1) x = (float) hf_width-1; - if (y < 0) y = 0; - if (y > hf_height-1) y = (float) hf_height-1; - ix = (int) x; x -= ix; - iy = (int) y; y -= iy; - h00 = hf[(iy+0)*hf_height+(ix+0)]; - h10 = hf[(iy+0)*hf_height+(ix+1)]; - h01 = hf[(iy+1)*hf_height+(ix+0)]; - h11 = hf[(iy+1)*hf_height+(ix+1)]; - h0 = stb_lerp(y, h00, h01); - h1 = stb_lerp(y, h10, h11); - return stb_lerp(x, h0, h1); -} - -void stbpg_tick(float dt) -{ - int i=0,j=0; - int step = 1; - - glUseProgram(0); - - glClearColor(0.6f,0.7f,1.0f,1.0f); - glClearDepth(1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); -#if 1 - glEnable(GL_CULL_FACE); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60.0, 1920/1080.0f, 0.02f, 8000.0f); - //glOrtho(-8,8,-6,6, -100, 100); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glRotatef(-90, 1,0,0); // z-up - - { - float x,y; - stbpg_get_mouselook(&x,&y); - glRotatef(-y, 1,0,0); - glRotatef(-x, 0,0,1); - } - - { - static float cam_x = 1000; - static float cam_y = 1000; - static float cam_z = 700; - float x=0,y=0; - stbpg_get_keymove(&x,&y); - cam_x += x*dt*5.0f; - cam_y += y*dt*5.0f; - glTranslatef(-cam_x, -cam_y, -cam_z); - if (cam_x >= 0 && cam_x < hf_width && cam_y >= 0 && cam_y < hf_height) - cam_z = get_height(cam_x, cam_y) + 1.65f; // average eye height in meters - } - - for (j=501; j+1 < 1500+0*hf_height; j += step) { - glBegin(GL_QUAD_STRIP); - for (i=501; i < 1500+0*hf_width; i += step) { - static int flip=0; - if (flip) - glColor3f(0.5,0.5,0.5); - else - glColor3f(0.4f,0.4f,0.4f); - flip = !flip; - glVertex3f((float) i, (float) j+step,hf[(j+step)*hf_width+i]); - glVertex3f((float) i, (float) j ,hf[ j *hf_width+i]); - } - glEnd(); - } - - glBegin(GL_LINES); - glColor3f(1,0,0); glVertex3f(10,0,0); glVertex3f(0,0,0); - glColor3f(0,1,0); glVertex3f(0,10,0); glVertex3f(0,0,0); - glColor3f(0,0,1); glVertex3f(0,0,10); glVertex3f(0,0,0); - glEnd(); -#endif -} - -void stbpg_main(int argc, char **argv) -{ - int i,j; - - #if 0 - int w,h,c; - unsigned short *data = stbi_load_16("c:/x/ned_1m/test2.png", &w, &h, &c, 1); - stb_filewrite("c:/x/ned_1m/x73_y428_10012_10012.bin", data, w*h*2); - #else - unsigned short *data = stb_file("c:/x/ned_1m/x73_y428_10012_10012.bin", NULL); - int w=10012, h = 10012; - #endif - - hf = malloc(hf_width * hf_height * 4); - for (j=0; j < hf_height; ++j) - for (i=0; i < hf_width; ++i) - hf[j*hf_width+i] = data[j*w+i] / 32.0f; - - stbpg_gl_compat_version(1,1); - stbpg_windowed("terrain_edit", 1920, 1080); - stbpg_run(); - - return; -} diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi0g16.png deleted file mode 100644 index a9f2816..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi2c16.png deleted file mode 100644 index cd7e50f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi4a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi4a16.png deleted file mode 100644 index 51192e7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi4a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi6a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi6a16.png deleted file mode 100644 index 4181533..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basi6a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn0g16.png deleted file mode 100644 index e7c82f7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn2c16.png deleted file mode 100644 index 50c1cb9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn4a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn4a16.png deleted file mode 100644 index 8243644..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn4a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn6a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn6a16.png deleted file mode 100644 index 984a995..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/basn6a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgai4a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgai4a16.png deleted file mode 100644 index 51192e7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgai4a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgan6a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgan6a16.png deleted file mode 100644 index 984a995..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgan6a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bggn4a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/bggn4a16.png deleted file mode 100644 index 13fd85b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bggn4a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgyn6a16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgyn6a16.png deleted file mode 100644 index ae3e9be..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/bgyn6a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi1n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi1n0g16.png deleted file mode 100644 index e7c82f7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi1n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi1n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi1n2c16.png deleted file mode 100644 index 50c1cb9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi1n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi2n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi2n0g16.png deleted file mode 100644 index 14d64c5..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi2n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi2n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi2n2c16.png deleted file mode 100644 index 4c2e3e3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi2n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi4n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi4n0g16.png deleted file mode 100644 index 69e73ed..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi4n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi4n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi4n2c16.png deleted file mode 100644 index 93691e3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi4n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi9n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi9n0g16.png deleted file mode 100644 index 9248413..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi9n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi9n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi9n2c16.png deleted file mode 100644 index f0512e4..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/oi9n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbbn2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbbn2c16.png deleted file mode 100644 index dd3168e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbbn2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbgn2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbgn2c16.png deleted file mode 100644 index 85cec39..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbgn2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbwn0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbwn0g16.png deleted file mode 100644 index 99bdeed..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/16bit/tbwn0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/PngSuite.LICENSE b/source/engine/thirdparty/stb/tests/pngsuite/PngSuite.LICENSE deleted file mode 100644 index 8d4d1d0..0000000 --- a/source/engine/thirdparty/stb/tests/pngsuite/PngSuite.LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -PngSuite --------- - -Permission to use, copy, modify and distribute these images for any -purpose and without fee is hereby granted. - - -(c) Willem van Schaik, 1996, 2011 - diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xc1n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xc1n0g08.png deleted file mode 100644 index 9404227..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xc1n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xc9n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xc9n2c08.png deleted file mode 100644 index b11c2a7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xc9n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xcrn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xcrn0g04.png deleted file mode 100644 index 48abba1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xcrn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xcsn0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xcsn0g01.png deleted file mode 100644 index 9863a26..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xcsn0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd0n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd0n2c08.png deleted file mode 100644 index 2f00161..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd0n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd3n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd3n2c08.png deleted file mode 100644 index 9e4a3ff..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd3n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd9n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd9n2c08.png deleted file mode 100644 index 2c3b91a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xd9n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xdtn0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xdtn0g01.png deleted file mode 100644 index 1a81abe..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xdtn0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xhdn0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xhdn0g08.png deleted file mode 100644 index fcb8737..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xhdn0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xlfn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xlfn0g04.png deleted file mode 100644 index d9ec53e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xlfn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs1n0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs1n0g01.png deleted file mode 100644 index 1817c51..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs1n0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs2n0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs2n0g01.png deleted file mode 100644 index b8147f2..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs2n0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs4n0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs4n0g01.png deleted file mode 100644 index 45237a1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs4n0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs7n0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs7n0g01.png deleted file mode 100644 index 3f307f1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/corrupt/xs7n0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi0g01.png deleted file mode 100644 index 33db08c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi0g02.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi0g02.png deleted file mode 100644 index 484f46d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi0g02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi3p02.png deleted file mode 100644 index 1699e9a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_basi3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_bgwn6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_bgwn6a08.png deleted file mode 100644 index 7d0ac50..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_bgwn6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_bgyn6a16.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_bgyn6a16.png deleted file mode 100644 index 9046336..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_bgyn6a16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_tbyn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_tbyn3p08.png deleted file mode 100644 index 3c224d0..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_tbyn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_z06n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_z06n2c08.png deleted file mode 100644 index de5dba3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/iphone/iphone_z06n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g01.png deleted file mode 100644 index 556fa72..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g02.png deleted file mode 100644 index ce09821..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g04.png deleted file mode 100644 index 3853273..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g08.png deleted file mode 100644 index faed8be..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi2c08.png deleted file mode 100644 index 2aab44d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p01.png deleted file mode 100644 index 00a7cea..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p02.png deleted file mode 100644 index bb16b44..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p04.png deleted file mode 100644 index b4e888e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p08.png deleted file mode 100644 index 50a6d1c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi4a08.png deleted file mode 100644 index 398132b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basi6a08.png deleted file mode 100644 index aecb32e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basi6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g01.png deleted file mode 100644 index 1d72242..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g02.png deleted file mode 100644 index 5083324..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g04.png deleted file mode 100644 index 0bf3687..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g08.png deleted file mode 100644 index 23c8237..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn2c08.png deleted file mode 100644 index db5ad15..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p01.png deleted file mode 100644 index b145c2b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p02.png deleted file mode 100644 index 8985b3d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p04.png deleted file mode 100644 index 0fbf9e8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p08.png deleted file mode 100644 index 0ddad07..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn4a08.png deleted file mode 100644 index 3e13052..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/basn6a08.png deleted file mode 100644 index e608738..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/basn6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgai4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/bgai4a08.png deleted file mode 100644 index 398132b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgai4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgan6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/bgan6a08.png deleted file mode 100644 index e608738..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgan6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgbn4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/bgbn4a08.png deleted file mode 100644 index 7cbefc3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgbn4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgwn6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/bgwn6a08.png deleted file mode 100644 index a67ff20..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/bgwn6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s01i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s01i3p01.png deleted file mode 100644 index 6c0fad1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s01i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s01n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s01n3p01.png deleted file mode 100644 index cb2c8c7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s01n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s02i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s02i3p01.png deleted file mode 100644 index 2defaed..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s02i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s02n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s02n3p01.png deleted file mode 100644 index 2b1b669..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s02n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s03i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s03i3p01.png deleted file mode 100644 index c23fdc4..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s03i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s03n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s03n3p01.png deleted file mode 100644 index 6d96ee4..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s03n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s04i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s04i3p01.png deleted file mode 100644 index 0e710c2..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s04i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s04n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s04n3p01.png deleted file mode 100644 index 956396c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s04n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s05i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s05i3p02.png deleted file mode 100644 index d14cbd3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s05i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s05n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s05n3p02.png deleted file mode 100644 index bf940f0..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s05n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s06i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s06i3p02.png deleted file mode 100644 index 456ada3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s06i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s06n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s06n3p02.png deleted file mode 100644 index 501064d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s06n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s07i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s07i3p02.png deleted file mode 100644 index 44b66ba..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s07i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s07n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s07n3p02.png deleted file mode 100644 index 6a58259..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s07n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s08i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s08i3p02.png deleted file mode 100644 index acf74f3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s08i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s08n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s08n3p02.png deleted file mode 100644 index b7094e1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s08n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s09i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s09i3p02.png deleted file mode 100644 index 0bfae8e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s09i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s09n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s09n3p02.png deleted file mode 100644 index 711ab82..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s09n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s32i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s32i3p04.png deleted file mode 100644 index 0841910..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s32i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s32n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s32n3p04.png deleted file mode 100644 index fa58e3e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s32n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s33i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s33i3p04.png deleted file mode 100644 index ab0dc14..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s33i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s33n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s33n3p04.png deleted file mode 100644 index 764f1a3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s33n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s34i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s34i3p04.png deleted file mode 100644 index bd99039..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s34i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s34n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s34n3p04.png deleted file mode 100644 index 9cbc68b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s34n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s35i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s35i3p04.png deleted file mode 100644 index e2a5e0a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s35i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s35n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s35n3p04.png deleted file mode 100644 index 90b892e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s35n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s36i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s36i3p04.png deleted file mode 100644 index eb61b6f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s36i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s36n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s36n3p04.png deleted file mode 100644 index b38d179..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s36n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s37i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s37i3p04.png deleted file mode 100644 index 6e2b1e9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s37i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s37n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s37n3p04.png deleted file mode 100644 index 4d3054d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s37n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s38i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s38i3p04.png deleted file mode 100644 index a0a8a14..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s38i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s38n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s38n3p04.png deleted file mode 100644 index 1233ed0..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s38n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s39i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s39i3p04.png deleted file mode 100644 index 04fee93..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s39i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s39n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s39n3p04.png deleted file mode 100644 index c750100..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s39n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s40i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s40i3p04.png deleted file mode 100644 index 68f358b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s40i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/s40n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/s40n3p04.png deleted file mode 100644 index 864b6b9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/s40n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbbn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tbbn0g04.png deleted file mode 100644 index 39a7050..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbbn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbbn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tbbn3p08.png deleted file mode 100644 index 0ede357..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbbn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbgn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tbgn3p08.png deleted file mode 100644 index 8cf2e6f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbgn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbrn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tbrn2c08.png deleted file mode 100644 index 5cca0d6..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbrn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbwn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tbwn3p08.png deleted file mode 100644 index eacab7a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbwn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbyn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tbyn3p08.png deleted file mode 100644 index 656db09..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tbyn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tm3n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tm3n3p02.png deleted file mode 100644 index fb3ef1d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tm3n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n0g08.png deleted file mode 100644 index 333465f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n2c08.png deleted file mode 100644 index fc6e42c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n3p08.png deleted file mode 100644 index 69a69e5..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp0n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp1n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/tp1n3p08.png deleted file mode 100644 index a6c9f35..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/tp1n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/z00n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/z00n2c08.png deleted file mode 100644 index 7669eb8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/z00n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/z03n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/z03n2c08.png deleted file mode 100644 index bfb10de..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/z03n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/z06n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/z06n2c08.png deleted file mode 100644 index b90ebc1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/z06n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary/z09n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary/z09n2c08.png deleted file mode 100644 index 5f191a7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary/z09n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g01.png deleted file mode 100644 index 96ed62d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g02.png deleted file mode 100644 index bb53098..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g04.png deleted file mode 100644 index 2efd487..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g08.png deleted file mode 100644 index 2395213..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi2c08.png deleted file mode 100644 index 64ef3f8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p01.png deleted file mode 100644 index a8599e9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p02.png deleted file mode 100644 index c911ea9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p04.png deleted file mode 100644 index 750ef69..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p08.png deleted file mode 100644 index 39272c3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi4a08.png deleted file mode 100644 index 1b7b3a5..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi6a08.png deleted file mode 100644 index c12484f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basi6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g01.png deleted file mode 100644 index 20f6404..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g02.png deleted file mode 100644 index c4fae00..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g04.png deleted file mode 100644 index 166e7db..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g08.png deleted file mode 100644 index 192c792..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn2c08.png deleted file mode 100644 index d774b80..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p01.png deleted file mode 100644 index 77c580b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p02.png deleted file mode 100644 index 8427124..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p04.png deleted file mode 100644 index f08c6e9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p08.png deleted file mode 100644 index 0fa8195..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn4a08.png deleted file mode 100644 index d4e0a72..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn6a08.png deleted file mode 100644 index 1f54e56..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/basn6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgai4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgai4a08.png deleted file mode 100644 index 23ec6ae..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgai4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgan6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgan6a08.png deleted file mode 100644 index 6cb76f2..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgan6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgbn4a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgbn4a08.png deleted file mode 100644 index 1086ccc..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgbn4a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgwn6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgwn6a08.png deleted file mode 100644 index 03a0a30..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/bgwn6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s01i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s01i3p01.png deleted file mode 100644 index 45f8c61..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s01i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s01n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s01n3p01.png deleted file mode 100644 index a79ac1b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s01n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s02i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s02i3p01.png deleted file mode 100644 index d84f406..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s02i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s02n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s02n3p01.png deleted file mode 100644 index 3b813c4..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s02n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s03i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s03i3p01.png deleted file mode 100644 index 51367f7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s03i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s03n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s03n3p01.png deleted file mode 100644 index 7c44b73..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s03n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s04i3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s04i3p01.png deleted file mode 100644 index ae326c1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s04i3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s04n3p01.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s04n3p01.png deleted file mode 100644 index 55c63df..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s04n3p01.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s05i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s05i3p02.png deleted file mode 100644 index fd41d1d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s05i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s05n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s05n3p02.png deleted file mode 100644 index d6ab572..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s05n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s06i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s06i3p02.png deleted file mode 100644 index 73a7b0c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s06i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s06n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s06n3p02.png deleted file mode 100644 index e85eac8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s06n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s07i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s07i3p02.png deleted file mode 100644 index 08f6180..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s07i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s07n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s07n3p02.png deleted file mode 100644 index 029bc29..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s07n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s08i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s08i3p02.png deleted file mode 100644 index 23d16c7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s08i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s08n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s08n3p02.png deleted file mode 100644 index 4a46016..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s08n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s09i3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s09i3p02.png deleted file mode 100644 index ea14f9b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s09i3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s09n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s09n3p02.png deleted file mode 100644 index 7a82253..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s09n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s32i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s32i3p04.png deleted file mode 100644 index db4bef7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s32i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s32n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s32n3p04.png deleted file mode 100644 index c250971..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s32n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s33i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s33i3p04.png deleted file mode 100644 index 0faaa74..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s33i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s33n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s33n3p04.png deleted file mode 100644 index 599171c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s33n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s34i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s34i3p04.png deleted file mode 100644 index ca0e5eb..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s34i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s34n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s34n3p04.png deleted file mode 100644 index b175f59..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s34n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s35i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s35i3p04.png deleted file mode 100644 index ccb1b8a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s35i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s35n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s35n3p04.png deleted file mode 100644 index 2c7219f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s35n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s36i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s36i3p04.png deleted file mode 100644 index d61491f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s36i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s36n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s36n3p04.png deleted file mode 100644 index 1f50479..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s36n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s37i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s37i3p04.png deleted file mode 100644 index 2906fa3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s37i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s37n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s37n3p04.png deleted file mode 100644 index 8931b85..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s37n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s38i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s38i3p04.png deleted file mode 100644 index becf5a1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s38i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s38n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s38n3p04.png deleted file mode 100644 index 43f8c98..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s38n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s39i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s39i3p04.png deleted file mode 100644 index b045ad5..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s39i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s39n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s39n3p04.png deleted file mode 100644 index d37d66d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s39n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s40i3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s40i3p04.png deleted file mode 100644 index dd2f7a1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s40i3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s40n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s40n3p04.png deleted file mode 100644 index 6f8596c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/s40n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbbn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbbn0g04.png deleted file mode 100644 index 8d9f7d5..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbbn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbbn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbbn3p08.png deleted file mode 100644 index 706e6c4..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbbn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbgn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbgn3p08.png deleted file mode 100644 index fa5cdbc..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbgn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbrn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbrn2c08.png deleted file mode 100644 index bbe748f..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbrn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbwn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbwn3p08.png deleted file mode 100644 index 9ecd404..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbwn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbyn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbyn3p08.png deleted file mode 100644 index 4fbdb36..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tbyn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tm3n3p02.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tm3n3p02.png deleted file mode 100644 index babdebe..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tm3n3p02.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n0g08.png deleted file mode 100644 index 96dd89c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n2c08.png deleted file mode 100644 index 364e97e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n3p08.png deleted file mode 100644 index e5a29d6..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp0n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp1n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp1n3p08.png deleted file mode 100644 index 9ecd404..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/tp1n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z00n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z00n2c08.png deleted file mode 100644 index ecaa0d8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z00n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z03n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z03n2c08.png deleted file mode 100644 index ecaa0d8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z03n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z06n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z06n2c08.png deleted file mode 100644 index ecaa0d8..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z06n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z09n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z09n2c08.png deleted file mode 100644 index d869f99..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/primary_check/z09n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/ref_results.csv b/source/engine/thirdparty/stb/tests/pngsuite/ref_results.csv deleted file mode 100644 index 74dc2e6..0000000 --- a/source/engine/thirdparty/stb/tests/pngsuite/ref_results.csv +++ /dev/null @@ -1,259 +0,0 @@ -filename,width,height,ncomp,error,hash -pngsuite/16bit/basi0g16.png,32,32,1,,0xfc8f2f99 -pngsuite/16bit/basi2c16.png,32,32,3,,0x65567ed5 -pngsuite/16bit/basi4a16.png,32,32,2,,0x198cf245 -pngsuite/16bit/basi6a16.png,32,32,4,,0x3016e9b5 -pngsuite/16bit/basn0g16.png,32,32,1,,0xfc8f2f99 -pngsuite/16bit/basn2c16.png,32,32,3,,0x65567ed5 -pngsuite/16bit/basn4a16.png,32,32,2,,0x198cf245 -pngsuite/16bit/basn6a16.png,32,32,4,,0x3016e9b5 -pngsuite/16bit/bgai4a16.png,32,32,2,,0x198cf245 -pngsuite/16bit/bgan6a16.png,32,32,4,,0x3016e9b5 -pngsuite/16bit/bggn4a16.png,32,32,2,,0x198cf245 -pngsuite/16bit/bgyn6a16.png,32,32,4,,0x3016e9b5 -pngsuite/16bit/oi1n0g16.png,32,32,1,,0xfc8f2f99 -pngsuite/16bit/oi1n2c16.png,32,32,3,,0x65567ed5 -pngsuite/16bit/oi2n0g16.png,32,32,1,,0xfc8f2f99 -pngsuite/16bit/oi2n2c16.png,32,32,3,,0x65567ed5 -pngsuite/16bit/oi4n0g16.png,32,32,1,,0xfc8f2f99 -pngsuite/16bit/oi4n2c16.png,32,32,3,,0x65567ed5 -pngsuite/16bit/oi9n0g16.png,32,32,1,,0xfc8f2f99 -pngsuite/16bit/oi9n2c16.png,32,32,3,,0x65567ed5 -pngsuite/16bit/tbbn2c16.png,32,32,4,,0xaa9bfe44 -pngsuite/16bit/tbgn2c16.png,32,32,4,,0xaa9bfe44 -pngsuite/16bit/tbwn0g16.png,32,32,2,,0x075e519a -pngsuite/corrupt/xc1n0g08.png,32,32,2,bad ctype,0x00000000 -pngsuite/corrupt/xc9n2c08.png,32,32,2,bad ctype,0x00000000 -pngsuite/corrupt/xcrn0g04.png,32,32,2,unknown image type,0x00000000 -pngsuite/corrupt/xcsn0g01.png,32,32,1,,0x43b9891f -pngsuite/corrupt/xd0n2c08.png,32,32,1,1/2/4/8/16-bit only,0x00000000 -pngsuite/corrupt/xd3n2c08.png,32,32,1,1/2/4/8/16-bit only,0x00000000 -pngsuite/corrupt/xd9n2c08.png,32,32,1,1/2/4/8/16-bit only,0x00000000 -pngsuite/corrupt/xdtn0g01.png,32,32,1,no IDAT,0x00000000 -pngsuite/corrupt/xhdn0g08.png,32,32,1,,0x414f1ca9 -pngsuite/corrupt/xlfn0g04.png,32,32,1,unknown image type,0x00000000 -pngsuite/corrupt/xs1n0g01.png,32,32,1,unknown image type,0x00000000 -pngsuite/corrupt/xs2n0g01.png,32,32,1,unknown image type,0x00000000 -pngsuite/corrupt/xs4n0g01.png,32,32,1,unknown image type,0x00000000 -pngsuite/corrupt/xs7n0g01.png,32,32,1,unknown image type,0x00000000 -pngsuite/iphone/iphone_basi0g01.png,32,32,4,,0x5fb33cfd -pngsuite/iphone/iphone_basi0g02.png,32,32,4,,0x5bbe95c5 -pngsuite/iphone/iphone_basi3p02.png,32,32,4,,0x50ba29c5 -pngsuite/iphone/iphone_bgwn6a08.png,32,32,4,,0x45d8548a -pngsuite/iphone/iphone_bgyn6a16.png,32,32,4,,0x4b2b7545 -pngsuite/iphone/iphone_tbyn3p08.png,32,32,4,,0x8ea9aaaf -pngsuite/iphone/iphone_z06n2c08.png,32,32,4,,0xb5dd034b -pngsuite/primary/basi0g01.png,32,32,1,,0x43b9891f -pngsuite/primary/basi0g02.png,32,32,1,,0xaf0bb3c5 -pngsuite/primary/basi0g04.png,32,32,1,,0x6fbaeb45 -pngsuite/primary/basi0g08.png,32,32,1,,0x414f1ca9 -pngsuite/primary/basi2c08.png,32,32,3,,0x522345c5 -pngsuite/primary/basi3p01.png,32,32,3,,0x9c5b75c5 -pngsuite/primary/basi3p02.png,32,32,3,,0x46f26ec5 -pngsuite/primary/basi3p04.png,32,32,3,,0x35b2e4a5 -pngsuite/primary/basi3p08.png,32,32,3,,0xfe066865 -pngsuite/primary/basi4a08.png,32,32,2,,0x77cbbfa5 -pngsuite/primary/basi6a08.png,32,32,4,,0xb472197d -pngsuite/primary/basn0g01.png,32,32,1,,0x43b9891f -pngsuite/primary/basn0g02.png,32,32,1,,0xaf0bb3c5 -pngsuite/primary/basn0g04.png,32,32,1,,0x6fbaeb45 -pngsuite/primary/basn0g08.png,32,32,1,,0x414f1ca9 -pngsuite/primary/basn2c08.png,32,32,3,,0x522345c5 -pngsuite/primary/basn3p01.png,32,32,3,,0x9c5b75c5 -pngsuite/primary/basn3p02.png,32,32,3,,0x46f26ec5 -pngsuite/primary/basn3p04.png,32,32,3,,0x35b2e4a5 -pngsuite/primary/basn3p08.png,32,32,3,,0xfe066865 -pngsuite/primary/basn4a08.png,32,32,2,,0x77cbbfa5 -pngsuite/primary/basn6a08.png,32,32,4,,0xb472197d -pngsuite/primary/bgai4a08.png,32,32,2,,0x77cbbfa5 -pngsuite/primary/bgan6a08.png,32,32,4,,0xb472197d -pngsuite/primary/bgbn4a08.png,32,32,2,,0x77cbbfa5 -pngsuite/primary/bgwn6a08.png,32,32,4,,0xb472197d -pngsuite/primary/s01i3p01.png,1,1,3,,0xafb003b6 -pngsuite/primary/s01n3p01.png,1,1,3,,0xafb003b6 -pngsuite/primary/s02i3p01.png,2,2,3,,0x96f3dd85 -pngsuite/primary/s02n3p01.png,2,2,3,,0x96f3dd85 -pngsuite/primary/s03i3p01.png,3,3,3,,0xb0cf1241 -pngsuite/primary/s03n3p01.png,3,3,3,,0xb0cf1241 -pngsuite/primary/s04i3p01.png,4,4,3,,0xbfcedd75 -pngsuite/primary/s04n3p01.png,4,4,3,,0xbfcedd75 -pngsuite/primary/s05i3p02.png,5,5,3,,0xc322cedd -pngsuite/primary/s05n3p02.png,5,5,3,,0xc322cedd -pngsuite/primary/s06i3p02.png,6,6,3,,0x46916799 -pngsuite/primary/s06n3p02.png,6,6,3,,0x46916799 -pngsuite/primary/s07i3p02.png,7,7,3,,0xfdabc297 -pngsuite/primary/s07n3p02.png,7,7,3,,0xfdabc297 -pngsuite/primary/s08i3p02.png,8,8,3,,0x8f036d09 -pngsuite/primary/s08n3p02.png,8,8,3,,0x8f036d09 -pngsuite/primary/s09i3p02.png,9,9,3,,0x16a46830 -pngsuite/primary/s09n3p02.png,9,9,3,,0x16a46830 -pngsuite/primary/s32i3p04.png,32,32,3,,0x4bd4fbd3 -pngsuite/primary/s32n3p04.png,32,32,3,,0x4bd4fbd3 -pngsuite/primary/s33i3p04.png,33,33,3,,0x51aa005e -pngsuite/primary/s33n3p04.png,33,33,3,,0x51aa005e -pngsuite/primary/s34i3p04.png,34,34,3,,0x84818775 -pngsuite/primary/s34n3p04.png,34,34,3,,0x84818775 -pngsuite/primary/s35i3p04.png,35,35,3,,0x6359ec75 -pngsuite/primary/s35n3p04.png,35,35,3,,0x6359ec75 -pngsuite/primary/s36i3p04.png,36,36,3,,0xe4878065 -pngsuite/primary/s36n3p04.png,36,36,3,,0xe4878065 -pngsuite/primary/s37i3p04.png,37,37,3,,0x3cefc423 -pngsuite/primary/s37n3p04.png,37,37,3,,0x3cefc423 -pngsuite/primary/s38i3p04.png,38,38,3,,0xffc55a2b -pngsuite/primary/s38n3p04.png,38,38,3,,0xffc55a2b -pngsuite/primary/s39i3p04.png,39,39,3,,0x0c790240 -pngsuite/primary/s39n3p04.png,39,39,3,,0x0c790240 -pngsuite/primary/s40i3p04.png,40,40,3,,0x951a316d -pngsuite/primary/s40n3p04.png,40,40,3,,0x951a316d -pngsuite/primary/tbbn0g04.png,32,32,2,,0x9c8410ea -pngsuite/primary/tbbn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary/tbgn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary/tbrn2c08.png,32,32,4,,0xaa9bfe44 -pngsuite/primary/tbwn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary/tbyn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary/tm3n3p02.png,32,32,4,,0xf59745c5 -pngsuite/primary/tp0n0g08.png,32,32,1,,0xbac0864c -pngsuite/primary/tp0n2c08.png,32,32,3,,0x82687c37 -pngsuite/primary/tp0n3p08.png,32,32,3,,0x61f54e37 -pngsuite/primary/tp1n3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary/z00n2c08.png,32,32,3,,0x65b4a72f -pngsuite/primary/z03n2c08.png,32,32,3,,0x65b4a72f -pngsuite/primary/z06n2c08.png,32,32,3,,0x65b4a72f -pngsuite/primary/z09n2c08.png,32,32,3,,0x65b4a72f -pngsuite/primary_check/basi0g01.png,32,32,4,,0x5fb33cfd -pngsuite/primary_check/basi0g02.png,32,32,4,,0x5bbe95c5 -pngsuite/primary_check/basi0g04.png,32,32,4,,0x3468b9c5 -pngsuite/primary_check/basi0g08.png,32,32,4,,0x262ef46d -pngsuite/primary_check/basi2c08.png,32,32,4,,0x1fc92bc5 -pngsuite/primary_check/basi3p01.png,32,32,4,,0x28a3e1c5 -pngsuite/primary_check/basi3p02.png,32,32,4,,0x803be5c5 -pngsuite/primary_check/basi3p04.png,32,32,4,,0xf3fc60e5 -pngsuite/primary_check/basi3p08.png,32,32,4,,0x30ef4f45 -pngsuite/primary_check/basi4a08.png,32,32,4,,0x23c8536d -pngsuite/primary_check/basi6a08.png,32,32,4,,0xb472197d -pngsuite/primary_check/basn0g01.png,32,32,4,,0x5fb33cfd -pngsuite/primary_check/basn0g02.png,32,32,4,,0x5bbe95c5 -pngsuite/primary_check/basn0g04.png,32,32,4,,0x3468b9c5 -pngsuite/primary_check/basn0g08.png,32,32,4,,0x262ef46d -pngsuite/primary_check/basn2c08.png,32,32,4,,0x1fc92bc5 -pngsuite/primary_check/basn3p01.png,32,32,4,,0x28a3e1c5 -pngsuite/primary_check/basn3p02.png,32,32,4,,0x803be5c5 -pngsuite/primary_check/basn3p04.png,32,32,4,,0xf3fc60e5 -pngsuite/primary_check/basn3p08.png,32,32,4,,0x30ef4f45 -pngsuite/primary_check/basn4a08.png,32,32,4,,0x23c8536d -pngsuite/primary_check/basn6a08.png,32,32,4,,0xb472197d -pngsuite/primary_check/bgai4a08.png,32,32,4,,0x23c8536d -pngsuite/primary_check/bgan6a08.png,32,32,4,,0xb472197d -pngsuite/primary_check/bgbn4a08.png,32,32,4,,0x23c8536d -pngsuite/primary_check/bgwn6a08.png,32,32,4,,0xb472197d -pngsuite/primary_check/s01i3p01.png,1,1,4,,0xdb152beb -pngsuite/primary_check/s01n3p01.png,1,1,4,,0xdb152beb -pngsuite/primary_check/s02i3p01.png,2,2,4,,0xa344a3a5 -pngsuite/primary_check/s02n3p01.png,2,2,4,,0xa344a3a5 -pngsuite/primary_check/s03i3p01.png,3,3,4,,0x594d3bfa -pngsuite/primary_check/s03n3p01.png,3,3,4,,0x594d3bfa -pngsuite/primary_check/s04i3p01.png,4,4,4,,0xd59d4605 -pngsuite/primary_check/s04n3p01.png,4,4,4,,0xd59d4605 -pngsuite/primary_check/s05i3p02.png,5,5,4,,0x41e58366 -pngsuite/primary_check/s05n3p02.png,5,5,4,,0x41e58366 -pngsuite/primary_check/s06i3p02.png,6,6,4,,0xcad1a885 -pngsuite/primary_check/s06n3p02.png,6,6,4,,0xcad1a885 -pngsuite/primary_check/s07i3p02.png,7,7,4,,0x09184108 -pngsuite/primary_check/s07n3p02.png,7,7,4,,0x09184108 -pngsuite/primary_check/s08i3p02.png,8,8,4,,0x4fd11cad -pngsuite/primary_check/s08n3p02.png,8,8,4,,0x4fd11cad -pngsuite/primary_check/s09i3p02.png,9,9,4,,0xc50dbecd -pngsuite/primary_check/s09n3p02.png,9,9,4,,0xc50dbecd -pngsuite/primary_check/s32i3p04.png,32,32,4,,0x95cbb1d3 -pngsuite/primary_check/s32n3p04.png,32,32,4,,0x95cbb1d3 -pngsuite/primary_check/s33i3p04.png,33,33,4,,0x6649fc5b -pngsuite/primary_check/s33n3p04.png,33,33,4,,0x6649fc5b -pngsuite/primary_check/s34i3p04.png,34,34,4,,0x35b98e15 -pngsuite/primary_check/s34n3p04.png,34,34,4,,0x35b98e15 -pngsuite/primary_check/s35i3p04.png,35,35,4,,0xc9ddf938 -pngsuite/primary_check/s35n3p04.png,35,35,4,,0xc9ddf938 -pngsuite/primary_check/s36i3p04.png,36,36,4,,0x7bb4e1cd -pngsuite/primary_check/s36n3p04.png,36,36,4,,0x7bb4e1cd -pngsuite/primary_check/s37i3p04.png,37,37,4,,0xee50001c -pngsuite/primary_check/s37n3p04.png,37,37,4,,0xee50001c -pngsuite/primary_check/s38i3p04.png,38,38,4,,0x51b76813 -pngsuite/primary_check/s38n3p04.png,38,38,4,,0x51b76813 -pngsuite/primary_check/s39i3p04.png,39,39,4,,0x42f23327 -pngsuite/primary_check/s39n3p04.png,39,39,4,,0x42f23327 -pngsuite/primary_check/s40i3p04.png,40,40,4,,0xf91b6a7d -pngsuite/primary_check/s40n3p04.png,40,40,4,,0xf91b6a7d -pngsuite/primary_check/tbbn0g04.png,32,32,4,,0x8a0117a4 -pngsuite/primary_check/tbbn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary_check/tbgn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary_check/tbrn2c08.png,32,32,4,,0xaa9bfe44 -pngsuite/primary_check/tbwn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary_check/tbyn3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary_check/tm3n3p02.png,32,32,4,,0xf59745c5 -pngsuite/primary_check/tp0n0g08.png,32,32,4,,0xd405ad2e -pngsuite/primary_check/tp0n2c08.png,32,32,4,,0x5a66ca09 -pngsuite/primary_check/tp0n3p08.png,32,32,4,,0x06e81adf -pngsuite/primary_check/tp1n3p08.png,32,32,4,,0x82bf9a57 -pngsuite/primary_check/z00n2c08.png,32,32,4,,0xaa698493 -pngsuite/primary_check/z03n2c08.png,32,32,4,,0xaa698493 -pngsuite/primary_check/z06n2c08.png,32,32,4,,0xaa698493 -pngsuite/primary_check/z09n2c08.png,32,32,4,,0xaa698493 -pngsuite/unused/ccwn2c08.png,32,32,3,,0xbb576418 -pngsuite/unused/ccwn3p08.png,32,32,3,,0x5c4df060 -pngsuite/unused/cdfn2c08.png,8,32,3,,0xe30ed48f -pngsuite/unused/cdhn2c08.png,32,8,3,,0x999321f5 -pngsuite/unused/cdsn2c08.png,8,8,3,,0x7f63fa01 -pngsuite/unused/cdun2c08.png,32,32,3,,0xbd325d71 -pngsuite/unused/ch1n3p04.png,32,32,3,,0x35b2e4a5 -pngsuite/unused/ch2n3p08.png,32,32,3,,0xfe066865 -pngsuite/unused/cm0n0g04.png,32,32,1,,0xe9f53e6c -pngsuite/unused/cm7n0g04.png,32,32,1,,0xe9f53e6c -pngsuite/unused/cm9n0g04.png,32,32,1,,0xe9f53e6c -pngsuite/unused/cs3n2c16.png,32,32,3,,0x7f0fa2c5 -pngsuite/unused/cs3n3p08.png,32,32,3,,0x5533bac5 -pngsuite/unused/cs5n2c08.png,32,32,3,,0x8a80f8c5 -pngsuite/unused/cs5n3p08.png,32,32,3,,0x8a80f8c5 -pngsuite/unused/cs8n2c08.png,32,32,3,,0x7f0fa2c5 -pngsuite/unused/cs8n3p08.png,32,32,3,,0x7f0fa2c5 -pngsuite/unused/ct0n0g04.png,32,32,1,,0xe9f53e6c -pngsuite/unused/ct1n0g04.png,32,32,1,,0xe9f53e6c -pngsuite/unused/cten0g04.png,32,32,1,,0x1c073b45 -pngsuite/unused/ctfn0g04.png,32,32,1,,0xfa9fd205 -pngsuite/unused/ctgn0g04.png,32,32,1,,0xf28c8085 -pngsuite/unused/cthn0g04.png,32,32,1,,0x7c039595 -pngsuite/unused/ctjn0g04.png,32,32,1,,0xc520f455 -pngsuite/unused/ctzn0g04.png,32,32,1,,0xe9f53e6c -pngsuite/unused/f00n0g08.png,32,32,1,,0x21db411b -pngsuite/unused/f00n2c08.png,32,32,3,,0x1f25ded0 -pngsuite/unused/f01n0g08.png,32,32,1,,0x7437b32a -pngsuite/unused/f01n2c08.png,32,32,3,,0x0d4507ae -pngsuite/unused/f02n0g08.png,32,32,1,,0x6b633c7c -pngsuite/unused/f02n2c08.png,32,32,3,,0x4b278986 -pngsuite/unused/f03n0g08.png,32,32,1,,0x2f31c08e -pngsuite/unused/f03n2c08.png,32,32,3,,0x843ecc7e -pngsuite/unused/f04n0g08.png,32,32,1,,0xfd3a0b73 -pngsuite/unused/f04n2c08.png,32,32,3,,0x557174bc -pngsuite/unused/f99n0g04.png,32,32,1,,0xb79aa6e1 -pngsuite/unused/g03n0g16.png,32,32,1,,0xecd13817 -pngsuite/unused/g03n2c08.png,32,32,3,,0x242407a8 -pngsuite/unused/g03n3p04.png,32,32,3,,0xe801ecc8 -pngsuite/unused/g04n0g16.png,32,32,1,,0xc11bc972 -pngsuite/unused/g04n2c08.png,32,32,3,,0xdf843cc4 -pngsuite/unused/g04n3p04.png,32,32,3,,0x60e41f3b -pngsuite/unused/g05n0g16.png,32,32,1,,0xbe6615a5 -pngsuite/unused/g05n2c08.png,32,32,3,,0x5c312116 -pngsuite/unused/g05n3p04.png,32,32,3,,0x2e0fbf86 -pngsuite/unused/g07n0g16.png,32,32,1,,0x2b54a398 -pngsuite/unused/g07n2c08.png,32,32,3,,0xf765fb10 -pngsuite/unused/g07n3p04.png,32,32,3,,0x9a8c3338 -pngsuite/unused/g10n0g16.png,32,32,1,,0xb08a92e1 -pngsuite/unused/g10n2c08.png,32,32,3,,0xa43f2291 -pngsuite/unused/g10n3p04.png,32,32,3,,0xb733194c -pngsuite/unused/g25n0g16.png,32,32,1,,0xa6b1f5dd -pngsuite/unused/g25n2c08.png,32,32,3,,0x767aee0c -pngsuite/unused/g25n3p04.png,32,32,3,,0x4cf349a8 -pngsuite/unused/pp0n2c16.png,32,32,3,,0x65567ed5 -pngsuite/unused/pp0n6a08.png,32,32,4,,0x3188c645 -pngsuite/unused/ps1n0g08.png,32,32,1,,0x414f1ca9 -pngsuite/unused/ps1n2c16.png,32,32,3,,0x65567ed5 -pngsuite/unused/ps2n0g08.png,32,32,1,,0x414f1ca9 -pngsuite/unused/ps2n2c16.png,32,32,3,,0x65567ed5 diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ccwn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ccwn2c08.png deleted file mode 100644 index 47c2481..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ccwn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ccwn3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ccwn3p08.png deleted file mode 100644 index 8bb2c10..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ccwn3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdfn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cdfn2c08.png deleted file mode 100644 index 559e526..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdfn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdhn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cdhn2c08.png deleted file mode 100644 index 3e07e8e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdhn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdsn2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cdsn2c08.png deleted file mode 100644 index 076c32c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdsn2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdun2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cdun2c08.png deleted file mode 100644 index 846033b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cdun2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ch1n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ch1n3p04.png deleted file mode 100644 index 17cd12d..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ch1n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ch2n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ch2n3p08.png deleted file mode 100644 index 25c1798..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ch2n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cm0n0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cm0n0g04.png deleted file mode 100644 index 9fba5db..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cm0n0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cm7n0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cm7n0g04.png deleted file mode 100644 index f7dc46e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cm7n0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cm9n0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cm9n0g04.png deleted file mode 100644 index dd70911..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cm9n0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs3n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cs3n2c16.png deleted file mode 100644 index bf5fd20..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs3n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs3n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cs3n3p08.png deleted file mode 100644 index f4a6623..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs3n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs5n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cs5n2c08.png deleted file mode 100644 index 40f947c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs5n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs5n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cs5n3p08.png deleted file mode 100644 index dfd6e6e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs5n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs8n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cs8n2c08.png deleted file mode 100644 index 8e01d32..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs8n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs8n3p08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cs8n3p08.png deleted file mode 100644 index a44066e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cs8n3p08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ct0n0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ct0n0g04.png deleted file mode 100644 index 40d1e06..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ct0n0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ct1n0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ct1n0g04.png deleted file mode 100644 index 3ba110a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ct1n0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cten0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cten0g04.png deleted file mode 100644 index a6a56fa..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cten0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctfn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ctfn0g04.png deleted file mode 100644 index 353873e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctfn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctgn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ctgn0g04.png deleted file mode 100644 index 453f2b0..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctgn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/cthn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/cthn0g04.png deleted file mode 100644 index 8fce253..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/cthn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctjn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ctjn0g04.png deleted file mode 100644 index a77b8d2..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctjn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctzn0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ctzn0g04.png deleted file mode 100644 index b4401c9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ctzn0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f00n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f00n0g08.png deleted file mode 100644 index 45a0075..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f00n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f00n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f00n2c08.png deleted file mode 100644 index d6a1fff..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f00n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f01n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f01n0g08.png deleted file mode 100644 index 4a1107b..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f01n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f01n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f01n2c08.png deleted file mode 100644 index 26fee95..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f01n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f02n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f02n0g08.png deleted file mode 100644 index bfe410c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f02n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f02n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f02n2c08.png deleted file mode 100644 index e590f12..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f02n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f03n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f03n0g08.png deleted file mode 100644 index ed01e29..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f03n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f03n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f03n2c08.png deleted file mode 100644 index 7581150..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f03n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f04n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f04n0g08.png deleted file mode 100644 index 663fdae..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f04n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f04n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f04n2c08.png deleted file mode 100644 index 3c8b511..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f04n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/f99n0g04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/f99n0g04.png deleted file mode 100644 index 0b521c1..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/f99n0g04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n0g16.png deleted file mode 100644 index 41083ca..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n2c08.png deleted file mode 100644 index a9354db..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n3p04.png deleted file mode 100644 index 60396c9..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g03n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n0g16.png deleted file mode 100644 index 32395b7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n2c08.png deleted file mode 100644 index a652b0c..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n3p04.png deleted file mode 100644 index 5661cc3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g04n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n0g16.png deleted file mode 100644 index 70b37f0..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n2c08.png deleted file mode 100644 index 932c136..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n3p04.png deleted file mode 100644 index 9619930..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g05n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n0g16.png deleted file mode 100644 index d6a47c2..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n2c08.png deleted file mode 100644 index 5973464..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n3p04.png deleted file mode 100644 index c73fb61..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g07n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n0g16.png deleted file mode 100644 index 85f2c95..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n2c08.png deleted file mode 100644 index b303997..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n3p04.png deleted file mode 100644 index 1b6a6be..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g10n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n0g16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n0g16.png deleted file mode 100644 index a9f6787..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n0g16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n2c08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n2c08.png deleted file mode 100644 index 03f505a..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n2c08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n3p04.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n3p04.png deleted file mode 100644 index 4f943c6..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/g25n3p04.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/pp0n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/pp0n2c16.png deleted file mode 100644 index 8f2aad7..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/pp0n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/pp0n6a08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/pp0n6a08.png deleted file mode 100644 index 4ed7a30..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/pp0n6a08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps1n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ps1n0g08.png deleted file mode 100644 index 99625fa..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps1n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps1n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ps1n2c16.png deleted file mode 100644 index 0c7a6b3..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps1n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps2n0g08.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ps2n0g08.png deleted file mode 100644 index 90b2979..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps2n0g08.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps2n2c16.png b/source/engine/thirdparty/stb/tests/pngsuite/unused/ps2n2c16.png deleted file mode 100644 index a4a181e..0000000 Binary files a/source/engine/thirdparty/stb/tests/pngsuite/unused/ps2n2c16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/prerelease/stb_lib.h b/source/engine/thirdparty/stb/tests/prerelease/stb_lib.h deleted file mode 100644 index 0a6eead..0000000 --- a/source/engine/thirdparty/stb/tests/prerelease/stb_lib.h +++ /dev/null @@ -1,3305 +0,0 @@ -/* stb_lib.h - v1.00 - http://nothings.org/stb - no warranty is offered or implied; use this code at your own risk - - ============================================================================ - You MUST - - #define STB_LIB_IMPLEMENTATION - - in EXACTLY _one_ C or C++ file that includes this header, BEFORE the - include, like this: - - #define STB_LIB_IMPLEMENTATION - #include "stblib_files.h" - - All other files should just #include "stblib_files.h" without the #define. - ============================================================================ - -LICENSE - - See end of file for license information. - -CREDITS - - Written by Sean Barrett. - - Fixes: - Philipp Wiesemann Robert Nix - r-lyeh blackpawn - github:Mojofreem Ryan Whitworth - Vincent Isambart Mike Sartain - Eugene Opalev Tim Sjostrand - github:infatum Dave Butler -*/ - -#ifndef STB_INCLUDE_STB_LIB_H - -#include - -#if defined(_WIN32) && !defined(__MINGW32__) - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif - #ifndef _CRT_NON_CONFORMING_SWPRINTFS - #define _CRT_NON_CONFORMING_SWPRINTFS - #endif - #if !defined(_MSC_VER) || _MSC_VER > 1700 - #include // _BitScanReverse - #endif -#endif - -#include // stdlib could have min/max -#include // need FILE -#include // stb_define_hash needs memcpy/memset -#include // stb_dirtree - -typedef unsigned char stb_uchar; -typedef unsigned char stb_uint8; -typedef unsigned int stb_uint; -typedef unsigned short stb_uint16; -typedef short stb_int16; -typedef signed char stb_int8; -#if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32) - typedef unsigned long stb_uint32; - typedef long stb_int32; -#else - typedef unsigned int stb_uint32; - typedef int stb_int32; -#endif -typedef char stb__testsize2_16[sizeof(stb_uint16)==2 ? 1 : -1]; -typedef char stb__testsize2_32[sizeof(stb_uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER - typedef unsigned __int64 stb_uint64; - typedef __int64 stb_int64; - #define STB_IMM_UINT64(literalui64) (literalui64##ui64) -#else - // ?? - typedef unsigned long long stb_uint64; - typedef long long stb_int64; - #define STB_IMM_UINT64(literalui64) (literalui64##ULL) -#endif -typedef char stb__testsize2_64[sizeof(stb_uint64)==8 ? 1 : -1]; - -#ifdef __cplusplus - #define STB_EXTERN extern "C" -#else - #define STB_EXTERN extern -#endif - -// check for well-known debug defines -#if defined(DEBUG) || defined(_DEBUG) || defined(DBG) - #ifndef NDEBUG - #define STB_DEBUG - #endif -#endif - -#ifdef STB_DEBUG - #include -#endif -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION - #include - #include - #include - #include - #include - #ifndef _WIN32 - #include - #else - #include // _mktemp - #include // _rmdir - #endif - #include // stat()/_stat() - #include // stat()/_stat() -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Miscellany -// - -#ifdef _WIN32 - #define stb_stricmp(a,b) stricmp(a,b) - #define stb_strnicmp(a,b,n) strnicmp(a,b,n) -#else - #define stb_stricmp(a,b) strcasecmp(a,b) - #define stb_strnicmp(a,b,n) strncasecmp(a,b,n) -#endif - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN void stb_fatal(char *fmt, ...); -STB_EXTERN void stb_swap(void *p, void *q, size_t sz); -STB_EXTERN double stb_linear_remap(double x, double x_min, double x_max, - double out_min, double out_max); - -#define stb_arrcount(x) (sizeof(x)/sizeof((x)[0])) -#define stb_lerp(t,a,b) ( (a) + (t) * (float) ((b)-(a)) ) -#define stb_unlerp(t,a,b) ( ((t) - (a)) / (float) ((b) - (a)) ) - -#endif - - -#ifdef STB_LIB_IMPLEMENTATION -void stb_fatal(char *s, ...) -{ - va_list a; - va_start(a,s); - fputs("Fatal error: ", stderr); - vfprintf(stderr, s, a); - va_end(a); - fputs("\n", stderr); - #ifdef STB_DEBUG - #ifdef _MSC_VER - #ifndef _WIN64 - __asm int 3; // trap to debugger! - #else - __debugbreak(); - #endif - #else - __builtin_trap(); - #endif - #endif - exit(1); -} - -typedef struct { char d[4]; } stb__4; -typedef struct { char d[8]; } stb__8; - -// optimize the small cases, though you shouldn't be calling this for those! -void stb_swap(void *p, void *q, size_t sz) -{ - char buffer[256]; - if (p == q) return; - if (sz == 4) { - stb__4 temp = * ( stb__4 *) p; - * (stb__4 *) p = * ( stb__4 *) q; - * (stb__4 *) q = temp; - return; - } else if (sz == 8) { - stb__8 temp = * ( stb__8 *) p; - * (stb__8 *) p = * ( stb__8 *) q; - * (stb__8 *) q = temp; - return; - } - - while (sz > sizeof(buffer)) { - stb_swap(p, q, sizeof(buffer)); - p = (char *) p + sizeof(buffer); - q = (char *) q + sizeof(buffer); - sz -= sizeof(buffer); - } - - memcpy(buffer, p , sz); - memcpy(p , q , sz); - memcpy(q , buffer, sz); -} - -#ifdef stb_linear_remap -#undef stb_linear_remap -#endif - -double stb_linear_remap(double x, double x_min, double x_max, - double out_min, double out_max) -{ - return stb_lerp(stb_unlerp(x,x_min,x_max),out_min,out_max); -} - -#define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d) -#endif // STB_LIB_IMPLEMENTATION - -#ifndef STB_INCLUDE_STB_LIB_H -// avoid unnecessary function call, but define function so its address can be taken -#ifndef stb_linear_remap -#define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d) -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// cross-platform snprintf because they keep changing that, -// and with old compilers without vararg macros we can't write -// a macro wrapper to fix it up - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...); -STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v); -STB_EXTERN char *stb_sprintf(const char *fmt, ...); -#endif - -#ifdef STB_LIB_IMPLEMENTATION - -int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v) -{ - int res; - #ifdef _WIN32 - // Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ? - res = _vsnprintf(s,n,fmt,v); - #else - res = vsnprintf(s,n,fmt,v); - #endif - if (n) s[n-1] = 0; - // Unix returns length output would require, Windows returns negative when truncated. - return (res >= (int) n || res < 0) ? -1 : res; -} - -int stb_snprintf(char *s, size_t n, const char *fmt, ...) -{ - int res; - va_list v; - va_start(v,fmt); - res = stb_vsnprintf(s, n, fmt, v); - va_end(v); - return res; -} - -char *stb_sprintf(const char *fmt, ...) -{ - static char buffer[1024]; - va_list v; - va_start(v,fmt); - stb_vsnprintf(buffer,1024,fmt,v); - va_end(v); - return buffer; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Windows UTF8 filename handling -// -// Windows stupidly treats 8-bit filenames as some dopey code page, -// rather than utf-8. If we want to use utf8 filenames, we have to -// convert them to WCHAR explicitly and call WCHAR versions of the -// file functions. So, ok, we do. - - -#ifndef STB_INCLUDE_STB_LIB_H -#ifdef _WIN32 - #define stb__fopen(x,y) _wfopen((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y)) - #define stb__windows(x,y) x -#else - #define stb__fopen(x,y) fopen(x,y) - #define stb__windows(x,y) y -#endif - - -typedef unsigned short stb__wchar; - -STB_EXTERN stb__wchar * stb_from_utf8(stb__wchar *buffer, char *str, int n); -STB_EXTERN char * stb_to_utf8 (char *buffer, stb__wchar *str, int n); - -STB_EXTERN stb__wchar *stb__from_utf8(char *str); -STB_EXTERN stb__wchar *stb__from_utf8_alt(char *str); -STB_EXTERN char *stb__to_utf8(stb__wchar *str); -#endif - -#ifdef STB_LIB_IMPLEMENTATION -stb__wchar * stb_from_utf8(stb__wchar *buffer, char *ostr, int n) -{ - unsigned char *str = (unsigned char *) ostr; - stb_uint32 c; - int i=0; - --n; - while (*str) { - if (i >= n) - return NULL; - if (!(*str & 0x80)) - buffer[i++] = *str++; - else if ((*str & 0xe0) == 0xc0) { - if (*str < 0xc2) return NULL; - c = (*str++ & 0x1f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = c + (*str++ & 0x3f); - } else if ((*str & 0xf0) == 0xe0) { - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; - if (*str == 0xed && str[1] > 0x9f) return NULL; // str[1] < 0x80 is checked below - c = (*str++ & 0x0f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - buffer[i++] = c + (*str++ & 0x3f); - } else if ((*str & 0xf8) == 0xf0) { - if (*str > 0xf4) return NULL; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; - if (*str == 0xf4 && str[1] > 0x8f) return NULL; // str[1] < 0x80 is checked below - c = (*str++ & 0x07) << 18; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 12; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f) << 6; - if ((*str & 0xc0) != 0x80) return NULL; - c += (*str++ & 0x3f); - // utf-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xFFFFF800) == 0xD800) return NULL; - if (c >= 0x10000) { - c -= 0x10000; - if (i + 2 > n) return NULL; - buffer[i++] = 0xD800 | (0x3ff & (c >> 10)); - buffer[i++] = 0xDC00 | (0x3ff & (c )); - } - } else - return NULL; - } - buffer[i] = 0; - return buffer; -} - -char * stb_to_utf8(char *buffer, stb__wchar *str, int n) -{ - int i=0; - --n; - while (*str) { - if (*str < 0x80) { - if (i+1 > n) return NULL; - buffer[i++] = (char) *str++; - } else if (*str < 0x800) { - if (i+2 > n) return NULL; - buffer[i++] = 0xc0 + (*str >> 6); - buffer[i++] = 0x80 + (*str & 0x3f); - str += 1; - } else if (*str >= 0xd800 && *str < 0xdc00) { - stb_uint32 c; - if (i+4 > n) return NULL; - c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; - buffer[i++] = 0xf0 + (c >> 18); - buffer[i++] = 0x80 + ((c >> 12) & 0x3f); - buffer[i++] = 0x80 + ((c >> 6) & 0x3f); - buffer[i++] = 0x80 + ((c ) & 0x3f); - str += 2; - } else if (*str >= 0xdc00 && *str < 0xe000) { - return NULL; - } else { - if (i+3 > n) return NULL; - buffer[i++] = 0xe0 + (*str >> 12); - buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); - buffer[i++] = 0x80 + ((*str ) & 0x3f); - str += 1; - } - } - buffer[i] = 0; - return buffer; -} - -stb__wchar *stb__from_utf8(char *str) -{ - static stb__wchar buffer[4096]; - return stb_from_utf8(buffer, str, 4096); -} - -stb__wchar *stb__from_utf8_alt(char *str) -{ - static stb__wchar buffer[4096]; - return stb_from_utf8(buffer, str, 4096); -} - -char *stb__to_utf8(stb__wchar *str) -{ - static char buffer[4096]; - return stb_to_utf8(buffer, str, 4096); -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// qsort Compare Routines -// NOT THREAD SAFE - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN int (*stb_intcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_qsort_strcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_qsort_stricmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_floatcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_ucharcmp(int offset))(const void *a, const void *b); -STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b); -#endif - -#ifdef STB_LIB_IMPLEMENTATION -static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset; -static int stb__floatcmpoffset, stb__doublecmpoffset, stb__charcmpoffset; - -int stb__intcmp(const void *a, const void *b) -{ - const int p = *(const int *) ((const char *) a + stb__intcmpoffset); - const int q = *(const int *) ((const char *) b + stb__intcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__ucharcmp(const void *a, const void *b) -{ - const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset); - const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__charcmp(const void *a, const void *b) -{ - const int p = *(const char *) ((const char *) a + stb__ucharcmpoffset); - const int q = *(const char *) ((const char *) b + stb__ucharcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__floatcmp(const void *a, const void *b) -{ - const float p = *(const float *) ((const char *) a + stb__floatcmpoffset); - const float q = *(const float *) ((const char *) b + stb__floatcmpoffset); - return p < q ? -1 : p > q; -} - -int stb__doublecmp(const void *a, const void *b) -{ - const double p = *(const double *) ((const char *) a + stb__doublecmpoffset); - const double q = *(const double *) ((const char *) b + stb__doublecmpoffset); - return p < q ? -1 : p > q; -} - -int stb__qsort_strcmp(const void *a, const void *b) -{ - const char *p = *(const char **) ((const char *) a + stb__strcmpoffset); - const char *q = *(const char **) ((const char *) b + stb__strcmpoffset); - return strcmp(p,q); -} - -int stb__qsort_stricmp(const void *a, const void *b) -{ - const char *p = *(const char **) ((const char *) a + stb__strcmpoffset); - const char *q = *(const char **) ((const char *) b + stb__strcmpoffset); - return stb_stricmp(p,q); -} - -int (*stb_intcmp(int offset))(const void *, const void *) -{ - stb__intcmpoffset = offset; - return &stb__intcmp; -} - -int (*stb_ucharcmp(int offset))(const void *, const void *) -{ - stb__ucharcmpoffset = offset; - return &stb__ucharcmp; -} - -int (*stb_charcmp(int offset))(const void *, const void *) -{ - stb__charcmpoffset = offset; - return &stb__ucharcmp; -} - -int (*stb_qsort_strcmp(int offset))(const void *, const void *) -{ - stb__strcmpoffset = offset; - return &stb__qsort_strcmp; -} - -int (*stb_qsort_stricmp(int offset))(const void *, const void *) -{ - stb__strcmpoffset = offset; - return &stb__qsort_stricmp; -} - -int (*stb_floatcmp(int offset))(const void *, const void *) -{ - stb__floatcmpoffset = offset; - return &stb__floatcmp; -} - -int (*stb_doublecmp(int offset))(const void *, const void *) -{ - stb__doublecmpoffset = offset; - return &stb__doublecmp; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// String Processing -// - -#ifndef STB_INCLUDE_STB_LIB_H -#define stb_prefixi(s,t) (0==stb_strnicmp((s),(t),strlen(t))) - -enum stb_splitpath_flag -{ - STB_PATH = 1, - STB_FILE = 2, - STB_EXT = 4, - STB_PATH_FILE = STB_PATH + STB_FILE, - STB_FILE_EXT = STB_FILE + STB_EXT, - STB_EXT_NO_PERIOD = 8, -}; - -STB_EXTERN char * stb_skipwhite(char *s); -STB_EXTERN char * stb_trimwhite(char *s); -STB_EXTERN char * stb_skipnewline(char *s); -STB_EXTERN char * stb_strncpy(char *s, char *t, int n); -STB_EXTERN char * stb_substr(char *t, int n); -STB_EXTERN char * stb_duplower(char *s); -STB_EXTERN void stb_tolower (char *s); -STB_EXTERN char * stb_strchr2 (char *s, char p1, char p2); -STB_EXTERN char * stb_strrchr2(char *s, char p1, char p2); -STB_EXTERN char * stb_strtok(char *output, char *src, char *delimit); -STB_EXTERN char * stb_strtok_keep(char *output, char *src, char *delimit); -STB_EXTERN char * stb_strtok_invert(char *output, char *src, char *allowed); -STB_EXTERN char * stb_dupreplace(char *s, char *find, char *replace); -STB_EXTERN void stb_replaceinplace(char *s, char *find, char *replace); -STB_EXTERN char * stb_splitpath(char *output, char *src, int flag); -STB_EXTERN char * stb_splitpathdup(char *src, int flag); -STB_EXTERN char * stb_replacedir(char *output, char *src, char *dir); -STB_EXTERN char * stb_replaceext(char *output, char *src, char *ext); -STB_EXTERN void stb_fixpath(char *path); -STB_EXTERN char * stb_shorten_path_readable(char *path, int max_len); -STB_EXTERN int stb_suffix (char *s, char *t); -STB_EXTERN int stb_suffixi(char *s, char *t); -STB_EXTERN int stb_prefix (char *s, char *t); -STB_EXTERN char * stb_strichr(char *s, char t); -STB_EXTERN char * stb_stristr(char *s, char *t); -STB_EXTERN int stb_prefix_count(char *s, char *t); -STB_EXTERN const char * stb_plural(int n); // "s" or "" -STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); - -STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out); -STB_EXTERN char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out); -STB_EXTERN char **stb_tokens_allowempty(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_stripwhite(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_withdelim(char *src, char *delimit, int *count); -STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count); -// with 'quoted', allow delimiters to appear inside quotation marks, and don't -// strip whitespace inside them (and we delete the quotation marks unless they -// appear back to back, in which case they're considered escaped) -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -#include - -size_t stb_strscpy(char *d, const char *s, size_t n) -{ - size_t len = strlen(s); - if (len >= n) { - if (n) d[0] = 0; - return 0; - } - strcpy(d,s); - return len + 1; -} - -const char *stb_plural(int n) -{ - return n == 1 ? "" : "s"; -} - -int stb_prefix(char *s, char *t) -{ - while (*t) - if (*s++ != *t++) - return 0; - return 1; -} - -int stb_prefix_count(char *s, char *t) -{ - int c=0; - while (*t) { - if (*s++ != *t++) - break; - ++c; - } - return c; -} - -int stb_suffix(char *s, char *t) -{ - size_t n = strlen(s); - size_t m = strlen(t); - if (m <= n) - return 0 == strcmp(s+n-m, t); - else - return 0; -} - -int stb_suffixi(char *s, char *t) -{ - size_t n = strlen(s); - size_t m = strlen(t); - if (m <= n) - return 0 == stb_stricmp(s+n-m, t); - else - return 0; -} - -// originally I was using this table so that I could create known sentinel -// values--e.g. change whitetable[0] to be true if I was scanning for whitespace, -// and false if I was scanning for nonwhite. I don't appear to be using that -// functionality anymore (I do for tokentable, though), so just replace it -// with isspace() -char *stb_skipwhite(char *s) -{ - while (isspace((unsigned char) *s)) ++s; - return s; -} - -char *stb_skipnewline(char *s) -{ - if (s[0] == '\r' || s[0] == '\n') { - if (s[0]+s[1] == '\r' + '\n') ++s; - ++s; - } - return s; -} - -char *stb_trimwhite(char *s) -{ - int i,n; - s = stb_skipwhite(s); - n = (int) strlen(s); - for (i=n-1; i >= 0; --i) - if (!isspace(s[i])) - break; - s[i+1] = 0; - return s; -} - -char *stb_strncpy(char *s, char *t, int n) -{ - strncpy(s,t,n); - s[n-1] = 0; - return s; -} - -char *stb_substr(char *t, int n) -{ - char *a; - int z = (int) strlen(t); - if (z < n) n = z; - a = (char *) malloc(n+1); - strncpy(a,t,n); - a[n] = 0; - return a; -} - -char *stb_duplower(char *s) -{ - char *p = strdup(s), *q = p; - while (*q) { - *q = tolower(*q); - ++q; - } - return p; -} - -void stb_tolower(char *s) -{ - while (*s) { - *s = tolower(*s); - ++s; - } -} - -char *stb_strchr2(char *s, char x, char y) -{ - for(; *s; ++s) - if (*s == x || *s == y) - return s; - return NULL; -} - -char *stb_strrchr2(char *s, char x, char y) -{ - char *r = NULL; - for(; *s; ++s) - if (*s == x || *s == y) - r = s; - return r; -} - -char *stb_strichr(char *s, char t) -{ - if (tolower(t) == toupper(t)) - return strchr(s,t); - return stb_strchr2(s, (char) tolower(t), (char) toupper(t)); -} - -char *stb_stristr(char *s, char *t) -{ - size_t n = strlen(t); - char *z; - if (n==0) return s; - while ((z = stb_strichr(s, *t)) != NULL) { - if (0==stb_strnicmp(z, t, n)) - return z; - s = z+1; - } - return NULL; -} - -static char *stb_strtok_raw(char *output, char *src, char *delimit, int keep, int invert) -{ - if (invert) { - while (*src && strchr(delimit, *src) != NULL) { - *output++ = *src++; - } - } else { - while (*src && strchr(delimit, *src) == NULL) { - *output++ = *src++; - } - } - *output = 0; - if (keep) - return src; - else - return *src ? src+1 : src; -} - -char *stb_strtok(char *output, char *src, char *delimit) -{ - return stb_strtok_raw(output, src, delimit, 0, 0); -} - -char *stb_strtok_keep(char *output, char *src, char *delimit) -{ - return stb_strtok_raw(output, src, delimit, 1, 0); -} - -char *stb_strtok_invert(char *output, char *src, char *delimit) -{ - return stb_strtok_raw(output, src, delimit, 1,1); -} - -static char **stb_tokens_raw(char *src_, char *delimit, int *count, - int stripwhite, int allow_empty, char *start, char *end) -{ - int nested = 0; - unsigned char *src = (unsigned char *) src_; - static char stb_tokentable[256]; // rely on static initializion to 0 - static char stable[256],etable[256]; - char *out; - char **result; - int num=0; - unsigned char *s; - - s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 1; - if (start) { - s = (unsigned char *) start; while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1; - } - stable[0] = 1; - - // two passes through: the first time, counting how many - s = (unsigned char *) src; - while (*s) { - // state: just found delimiter - // skip further delimiters - if (!allow_empty) { - stb_tokentable[0] = 0; - while (stb_tokentable[*s]) - ++s; - if (!*s) break; - } - ++num; - // skip further non-delimiters - stb_tokentable[0] = 1; - if (stripwhite == 2) { // quoted strings - while (!stb_tokentable[*s]) { - if (*s != '"') - ++s; - else { - ++s; - if (*s == '"') - ++s; // "" -> ", not start a string - else { - // begin a string - while (*s) { - if (s[0] == '"') { - if (s[1] == '"') s += 2; // "" -> " - else { ++s; break; } // terminating " - } else - ++s; - } - } - } - } - } else - while (nested || !stb_tokentable[*s]) { - if (stable[*s]) { - if (!*s) break; - if (end ? etable[*s] : nested) - --nested; - else - ++nested; - } - ++s; - } - if (allow_empty) { - if (*s) ++s; - } - } - // now num has the actual count... malloc our output structure - // need space for all the strings: strings won't be any longer than - // original input, since for every '\0' there's at least one delimiter - result = (char **) malloc(sizeof(*result) * (num+1) + (s-src+1)); - if (result == NULL) return result; - out = (char *) (result + (num+1)); - // second pass: copy out the data - s = (unsigned char *) src; - num = 0; - nested = 0; - while (*s) { - char *last_nonwhite; - // state: just found delimiter - // skip further delimiters - if (!allow_empty) { - stb_tokentable[0] = 0; - if (stripwhite) - while (stb_tokentable[*s] || isspace(*s)) - ++s; - else - while (stb_tokentable[*s]) - ++s; - } else if (stripwhite) { - while (isspace(*s)) ++s; - } - if (!*s) break; - // we're past any leading delimiters and whitespace - result[num] = out; - ++num; - // copy non-delimiters - stb_tokentable[0] = 1; - last_nonwhite = out-1; - if (stripwhite == 2) { - while (!stb_tokentable[*s]) { - if (*s != '"') { - if (!isspace(*s)) last_nonwhite = out; - *out++ = *s++; - } else { - ++s; - if (*s == '"') { - if (!isspace(*s)) last_nonwhite = out; - *out++ = *s++; // "" -> ", not start string - } else { - // begin a quoted string - while (*s) { - if (s[0] == '"') { - if (s[1] == '"') { *out++ = *s; s += 2; } - else { ++s; break; } // terminating " - } else - *out++ = *s++; - } - last_nonwhite = out-1; // all in quotes counts as non-white - } - } - } - } else { - while (nested || !stb_tokentable[*s]) { - if (!isspace(*s)) last_nonwhite = out; - if (stable[*s]) { - if (!*s) break; - if (end ? etable[*s] : nested) - --nested; - else - ++nested; - } - *out++ = *s++; - } - } - - if (stripwhite) // rewind to last non-whitespace char - out = last_nonwhite+1; - *out++ = '\0'; - - if (*s) ++s; // skip delimiter - } - s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 0; - if (start) { - s = (unsigned char *) start; while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1; - s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1; - } - if (count != NULL) *count = num; - result[num] = 0; - return result; -} - -char **stb_tokens(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,0,0,0,0); -} - -char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out) -{ - return stb_tokens_raw(src,delimit,count,0,0,nest_in,nest_out); -} - -char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out) -{ - return stb_tokens_raw(src,delimit,count,0,1,nest_in,nest_out); -} - -char **stb_tokens_allowempty(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,0,1,0,0); -} - -char **stb_tokens_stripwhite(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,1,1,0,0); -} - -char **stb_tokens_quoted(char *src, char *delimit, int *count) -{ - return stb_tokens_raw(src,delimit,count,2,1,0,0); -} - -char *stb_dupreplace(char *src, char *find, char *replace) -{ - size_t len_find = strlen(find); - size_t len_replace = strlen(replace); - int count = 0; - - char *s,*p,*q; - - s = strstr(src, find); - if (s == NULL) return strdup(src); - do { - ++count; - s = strstr(s + len_find, find); - } while (s != NULL); - - p = (char *) malloc(strlen(src) + count * (len_replace - len_find) + 1); - if (p == NULL) return p; - q = p; - s = src; - for (;;) { - char *t = strstr(s, find); - if (t == NULL) { - strcpy(q,s); - assert(strlen(p) == strlen(src) + count*(len_replace-len_find)); - return p; - } - memcpy(q, s, t-s); - q += t-s; - memcpy(q, replace, len_replace); - q += len_replace; - s = t + len_find; - } -} - -void stb_replaceinplace(char *src, char *find, char *replace) -{ - size_t len_find = strlen(find); - size_t len_replace = strlen(replace); - int delta; - - char *s,*p,*q; - - delta = len_replace - len_find; - assert(delta <= 0); - if (delta > 0) return; - - p = strstr(src, find); - if (p == NULL) return; - - s = q = p; - while (*s) { - memcpy(q, replace, len_replace); - p += len_find; - q += len_replace; - s = strstr(p, find); - if (s == NULL) s = p + strlen(p); - memmove(q, p, s-p); - q += s-p; - p = s; - } - *q = 0; -} - -void stb_fixpath(char *path) -{ - for(; *path; ++path) - if (*path == '\\') - *path = '/'; -} - -void stb__add_section(char *buffer, char *data, int curlen, int newlen) -{ - if (newlen < curlen) { - int z1 = newlen >> 1, z2 = newlen-z1; - memcpy(buffer, data, z1-1); - buffer[z1-1] = '.'; - buffer[z1-0] = '.'; - memcpy(buffer+z1+1, data+curlen-z2+1, z2-1); - } else - memcpy(buffer, data, curlen); -} - -char * stb_shorten_path_readable(char *path, int len) -{ - static char buffer[1024]; - int n = strlen(path),n1,n2,r1,r2; - char *s; - if (n <= len) return path; - if (len > 1024) return path; - s = stb_strrchr2(path, '/', '\\'); - if (s) { - n1 = s - path + 1; - n2 = n - n1; - ++s; - } else { - n1 = 0; - n2 = n; - s = path; - } - // now we need to reduce r1 and r2 so that they fit in len - if (n1 < len>>1) { - r1 = n1; - r2 = len - r1; - } else if (n2 < len >> 1) { - r2 = n2; - r1 = len - r2; - } else { - r1 = n1 * len / n; - r2 = n2 * len / n; - if (r1 < len>>2) r1 = len>>2, r2 = len-r1; - if (r2 < len>>2) r2 = len>>2, r1 = len-r2; - } - assert(r1 <= n1 && r2 <= n2); - if (n1) - stb__add_section(buffer, path, n1, r1); - stb__add_section(buffer+r1, s, n2, r2); - buffer[len] = 0; - return buffer; -} - -static char *stb__splitpath_raw(char *buffer, char *path, int flag) -{ - int len=0,x,y, n = (int) strlen(path), f1,f2; - char *s = stb_strrchr2(path, '/', '\\'); - char *t = strrchr(path, '.'); - if (s && t && t < s) t = NULL; - if (s) ++s; - - if (flag == STB_EXT_NO_PERIOD) - flag |= STB_EXT; - - if (!(flag & (STB_PATH | STB_FILE | STB_EXT))) return NULL; - - f1 = s == NULL ? 0 : s-path; // start of filename - f2 = t == NULL ? n : t-path; // just past end of filename - - if (flag & STB_PATH) { - x = 0; if (f1 == 0 && flag == STB_PATH) len=2; - } else if (flag & STB_FILE) { - x = f1; - } else { - x = f2; - if (flag & STB_EXT_NO_PERIOD) - if (buffer[x] == '.') - ++x; - } - - if (flag & STB_EXT) - y = n; - else if (flag & STB_FILE) - y = f2; - else - y = f1; - - if (buffer == NULL) { - buffer = (char *) malloc(y-x + len + 1); - if (!buffer) return NULL; - } - - if (len) { strcpy(buffer, "./"); return buffer; } - strncpy(buffer, path+x, y-x); - buffer[y-x] = 0; - return buffer; -} - -char *stb_splitpath(char *output, char *src, int flag) -{ - return stb__splitpath_raw(output, src, flag); -} - -char *stb_splitpathdup(char *src, int flag) -{ - return stb__splitpath_raw(NULL, src, flag); -} - -char *stb_replacedir(char *output, char *src, char *dir) -{ - char buffer[4096]; - stb_splitpath(buffer, src, STB_FILE | STB_EXT); - if (dir) - sprintf(output, "%s/%s", dir, buffer); - else - strcpy(output, buffer); - return output; -} - -char *stb_replaceext(char *output, char *src, char *ext) -{ - char buffer[4096]; - stb_splitpath(buffer, src, STB_PATH | STB_FILE); - if (ext) - sprintf(output, "%s.%s", buffer, ext[0] == '.' ? ext+1 : ext); - else - strcpy(output, buffer); - return output; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// stb_arr -// -// An stb_arr is directly useable as a pointer (use the actual type in your -// definition), but when it resizes, it returns a new pointer and you can't -// use the old one, so you have to be careful to copy-in-out as necessary. -// -// Use a NULL pointer as a 0-length array. -// -// float *my_array = NULL, *temp; -// -// // add elements on the end one at a time -// stb_arr_push(my_array, 0.0f); -// stb_arr_push(my_array, 1.0f); -// stb_arr_push(my_array, 2.0f); -// -// assert(my_array[1] == 2.0f); -// -// // add an uninitialized element at the end, then assign it -// *stb_arr_add(my_array) = 3.0f; -// -// // add three uninitialized elements at the end -// temp = stb_arr_addn(my_array,3); -// temp[0] = 4.0f; -// temp[1] = 5.0f; -// temp[2] = 6.0f; -// -// assert(my_array[5] == 5.0f); -// -// // remove the last one -// stb_arr_pop(my_array); -// -// assert(stb_arr_len(my_array) == 6); - - -#ifndef STB_INCLUDE_STB_LIB_H - -// simple functions written on top of other functions -#define stb_arr_empty(a) ( stb_arr_len(a) == 0 ) -#define stb_arr_add(a) ( stb_arr_addn((a),1) ) -#define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) ) - -typedef struct -{ - int len, limit; - unsigned int signature; - unsigned int padding; // make it a multiple of 16 so preserve alignment mod 16 -} stb__arr; - -#define stb_arr_signature 0x51bada7b // ends with 0123 in decimal - -// access the header block stored before the data -#define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1) -#define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1) - -#ifdef STB_DEBUG -#define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature) -#define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature) -#else -#define stb_arr_check(a) ((void) 0) -#define stb_arr_check2(a) ((void) 0) -#endif - -// ARRAY LENGTH - -// get the array length; special case if pointer is NULL -#define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0) -#define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0) -#define stb_arr_lastn(a) (stb_arr_len(a)-1) - -// check whether a given index is valid -- tests 0 <= i < stb_arr_len(a) -#define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0) - -// change the array length so is is exactly N entries long, creating -// uninitialized entries as needed -#define stb_arr_setlen(a,n) \ - (stb__arr_setlen((void **) &(a), sizeof(a[0]), (n))) - -// change the array length so that N is a valid index (that is, so -// it is at least N entries long), creating uninitialized entries as needed -#define stb_arr_makevalid(a,n) \ - (stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a)) - -// remove the last element of the array, returning it -#define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len]) - -// access the last element in the array -#define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1]) - -// is iterator at end of list? -#define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)]) - -// (internal) change the allocated length of the array -#define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n)) - -// add N new uninitialized elements to the end of the array -#define stb_arr__addn(a,n) /*lint --e(826)*/ \ - ((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \ - ? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \ - : ((stb_arr__grow(a,n), 0))) - -// add N new uninitialized elements to the end of the array, and return -// a pointer to the first new one -#define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n)) - -// add N new uninitialized elements starting at index 'i' -#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n)) - -// insert an element at i -#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v)) - -// delete N elements from the middle starting at index 'i' -#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n)) - -// delete the i'th element -#define stb_arr_delete(a,i) stb_arr_deleten(a,i,1) - -// delete the i'th element, swapping down from the end -#define stb_arr_fastdelete(a,i) \ - (stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a)) - - -// ARRAY STORAGE - -// get the array maximum storage; special case if NULL -#define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0) -#define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0) - -// set the maxlength of the array to n in anticipation of further growth -#define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n)) - -// make sure maxlength is large enough for at least N new allocations -#define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \ - ? stb_arr_setsize((a), (n)) : 0) - -// make a copy of a given array (copies contents via 'memcpy'!) -#define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0])) - -// compute the storage needed to store all the elements of the array -#define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0])) - -#define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v)) - -// IMPLEMENTATION - -STB_EXTERN void stb_arr_free_(void **p); -STB_EXTERN void *stb__arr_copy_(void *p, int elem_size); -STB_EXTERN void stb__arr_setsize_(void **p, int size, int limit); -STB_EXTERN void stb__arr_setlen_(void **p, int size, int newlen); -STB_EXTERN void stb__arr_addlen_(void **p, int size, int addlen); -STB_EXTERN void stb__arr_deleten_(void **p, int size, int loc, int n); -STB_EXTERN void stb__arr_insertn_(void **p, int size, int loc, int n); - -#define stb_arr_free(p) stb_arr_free_((void **) &(p)) - -#ifndef STBLIB_MALLOC_WRAPPER // @Todo - #define stb__arr_setsize stb__arr_setsize_ - #define stb__arr_setlen stb__arr_setlen_ - #define stb__arr_addlen stb__arr_addlen_ - #define stb__arr_deleten stb__arr_deleten_ - #define stb__arr_insertn stb__arr_insertn_ - #define stb__arr_copy stb__arr_copy_ -#else - #define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__) - #define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__) - #define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__) - #define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__) - #define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__) - #define stb__arr_copy(p,s) stb__arr_copy_(p,s,__FILE__,__LINE__) -#endif -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -void stb_arr_malloc(void **target, void *context) -{ - stb__arr *q = (stb__arr *) malloc(sizeof(*q)); - q->len = q->limit = 0; - q->signature = stb_arr_signature; - *target = (void *) (q+1); -} - -static void * stb__arr_malloc(int size) -{ - return malloc(size); -} - -void * stb__arr_copy_(void *p, int elem_size) -{ - stb__arr *q; - if (p == NULL) return p; - q = (stb__arr *) malloc(sizeof(*q) + elem_size * stb_arrhead2(p)->limit); - stb_arr_check2(p); - memcpy(q, stb_arrhead2(p), sizeof(*q) + elem_size * stb_arrhead2(p)->len); - return q+1; -} - -void stb_arr_free_(void **pp) -{ - void *p = *pp; - stb_arr_check2(p); - if (p) { - stb__arr *q = stb_arrhead2(p); - free(q); - } - *pp = NULL; -} - -static void stb__arrsize_(void **pp, int size, int limit, int len) -{ - void *p = *pp; - stb__arr *a; - stb_arr_check2(p); - if (p == NULL) { - if (len == 0 && size == 0) return; - a = (stb__arr *) stb__arr_malloc(sizeof(*a) + size*limit); - a->limit = limit; - a->len = len; - a->signature = stb_arr_signature; - } else { - a = stb_arrhead2(p); - a->len = len; - if (a->limit < limit) { - void *p; - if (a->limit >= 4 && limit < a->limit * 2) - limit = a->limit * 2; - p = realloc(a, sizeof(*a) + limit*size); - if (p) { - a = (stb__arr *) p; - a->limit = limit; - } else { - // throw an error! - } - } - } - a->len = a->len < a->limit ? a->len : a->limit; - *pp = a+1; -} - -void stb__arr_setsize_(void **pp, int size, int limit) -{ - void *p = *pp; - stb_arr_check2(p); - stb__arrsize_(pp, size, limit, stb_arr_len2(p)); -} - -void stb__arr_setlen_(void **pp, int size, int newlen) -{ - void *p = *pp; - stb_arr_check2(p); - if (stb_arrcurmax2(p) < newlen || p == NULL) { - stb__arrsize_(pp, size, newlen, newlen); - } else { - stb_arrhead2(p)->len = newlen; - } -} - -void stb__arr_addlen_(void **p, int size, int addlen) -{ - stb__arr_setlen_(p, size, stb_arr_len2(*p) + addlen); -} - -void stb__arr_insertn_(void **pp, int size, int i, int n) -{ - void *p = *pp; - if (n) { - int z; - - if (p == NULL) { - stb__arr_addlen_(pp, size, n); - return; - } - - z = stb_arr_len2(p); - stb__arr_addlen_(&p, size, n); - memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i)); - } - *pp = p; -} - -void stb__arr_deleten_(void **pp, int size, int i, int n) -{ - void *p = *pp; - if (n) { - memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n))); - stb_arrhead2(p)->len -= n; - } - *pp = p; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Hashing -// -// typical use for this is to make a power-of-two hash table. -// -// let N = size of table (2^n) -// let H = stb_hash(str) -// let S = stb_rehash(H) | 1 -// -// then hash probe sequence P(i) for i=0..N-1 -// P(i) = (H + S*i) & (N-1) -// -// the idea is that H has 32 bits of hash information, but the -// table has only, say, 2^20 entries so only uses 20 of the bits. -// then by rehashing the original H we get 2^12 different probe -// sequences for a given initial probe location. (So it's optimal -// for 64K tables and its optimality decreases past that.) -// -// ok, so I've added something that generates _two separate_ -// 32-bit hashes simultaneously which should scale better to -// very large tables. - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN unsigned int stb_hash(char *str); -STB_EXTERN unsigned int stb_hashptr(void *p); -STB_EXTERN unsigned int stb_hashlen(char *str, int len); -STB_EXTERN unsigned int stb_rehash_improved(unsigned int v); -STB_EXTERN unsigned int stb_hash_fast(void *p, int len); -STB_EXTERN unsigned int stb_hash2(char *str, unsigned int *hash2_ptr); -STB_EXTERN unsigned int stb_hash_number(unsigned int hash); - -#define stb_rehash(x) ((x) + ((x) >> 6) + ((x) >> 19)) -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -unsigned int stb_hash(char *str) -{ - unsigned int hash = 0; - while (*str) - hash = (hash << 7) + (hash >> 25) + *str++; - return hash + (hash >> 16); -} - -unsigned int stb_hashlen(char *str, int len) -{ - unsigned int hash = 0; - while (len-- > 0 && *str) - hash = (hash << 7) + (hash >> 25) + *str++; - return hash + (hash >> 16); -} - -unsigned int stb_hashptr(void *p) -{ - unsigned int x = (unsigned int)(size_t) p; - - // typically lacking in low bits and high bits - x = stb_rehash(x); - x += x << 16; - - // pearson's shuffle - x ^= x << 3; - x += x >> 5; - x ^= x << 2; - x += x >> 15; - x ^= x << 10; - return stb_rehash(x); -} - -unsigned int stb_rehash_improved(unsigned int v) -{ - return stb_hashptr((void *)(size_t) v); -} - -unsigned int stb_hash2(char *str, unsigned int *hash2_ptr) -{ - unsigned int hash1 = 0x3141592c; - unsigned int hash2 = 0x77f044ed; - while (*str) { - hash1 = (hash1 << 7) + (hash1 >> 25) + *str; - hash2 = (hash2 << 11) + (hash2 >> 21) + *str; - ++str; - } - *hash2_ptr = hash2 + (hash1 >> 16); - return hash1 + (hash2 >> 16); -} - -// Paul Hsieh hash -#define stb__get16_slow(p) ((p)[0] + ((p)[1] << 8)) -#if defined(_MSC_VER) - #define stb__get16(p) (*((unsigned short *) (p))) -#else - #define stb__get16(p) stb__get16_slow(p) -#endif - -unsigned int stb_hash_fast(void *p, int len) -{ - unsigned char *q = (unsigned char *) p; - unsigned int hash = len; - - if (len <= 0 || q == NULL) return 0; - - /* Main loop */ - if (((int)(size_t) q & 1) == 0) { - for (;len > 3; len -= 4) { - unsigned int val; - hash += stb__get16(q); - val = (stb__get16(q+2) << 11); - hash = (hash << 16) ^ hash ^ val; - q += 4; - hash += hash >> 11; - } - } else { - for (;len > 3; len -= 4) { - unsigned int val; - hash += stb__get16_slow(q); - val = (stb__get16_slow(q+2) << 11); - hash = (hash << 16) ^ hash ^ val; - q += 4; - hash += hash >> 11; - } - } - - /* Handle end cases */ - switch (len) { - case 3: hash += stb__get16_slow(q); - hash ^= hash << 16; - hash ^= q[2] << 18; - hash += hash >> 11; - break; - case 2: hash += stb__get16_slow(q); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += q[0]; - hash ^= hash << 10; - hash += hash >> 1; - break; - case 0: break; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -unsigned int stb_hash_number(unsigned int hash) -{ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Instantiated data structures -// -// This is an attempt to implement a templated data structure. -// -// Hash table: call stb_define_hash(TYPE,N,KEY,K1,K2,HASH,VALUE) -// TYPE -- will define a structure type containing the hash table -// N -- the name, will prefix functions named: -// N create -// N destroy -// N get -// N set, N add, N update, -// N remove -// KEY -- the type of the key. 'x == y' must be valid -// K1,K2 -- keys never used by the app, used as flags in the hashtable -// HASH -- a piece of code ending with 'return' that hashes key 'k' -// VALUE -- the type of the value. 'x = y' must be valid -// -// Note that stb_define_hash_base can be used to define more sophisticated -// hash tables, e.g. those that make copies of the key or use special -// comparisons (e.g. strcmp). - -#define STB_(prefix,name) stb__##prefix##name -#define STB__(prefix,name) prefix##name -#define STB__use(x) x -#define STB__skip(x) - -#define stb_declare_hash(PREFIX,TYPE,N,KEY,VALUE) \ - typedef struct stb__st_##TYPE TYPE;\ - PREFIX int STB__(N, init)(TYPE *h, int count);\ - PREFIX int STB__(N, memory_usage)(TYPE *h);\ - PREFIX TYPE * STB__(N, create)(void);\ - PREFIX TYPE * STB__(N, copy)(TYPE *h);\ - PREFIX void STB__(N, destroy)(TYPE *h);\ - PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v);\ - PREFIX VALUE STB__(N,get)(TYPE *a, KEY k);\ - PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v);\ - PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v);\ - PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v);\ - PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v); - -#define STB_nocopy(x) (x) -#define STB_nodelete(x) 0 -#define STB_nofields -#define STB_nonullvalue(x) -#define STB_nullvalue(x) x -#define STB_safecompare(x) x -#define STB_nosafe(x) -#define STB_noprefix - -#ifdef __GNUC__ -#define STB__nogcc(x) -#else -#define STB__nogcc(x) x -#endif - -#define stb_define_hash_base(PREFIX,TYPE,FIELDS,N,NC,LOAD_FACTOR, \ - KEY,EMPTY,DEL,COPY,DISPOSE,SAFE, \ - VCOMPARE,CCOMPARE,HASH, \ - VALUE,HASVNULL,VNULL) \ - \ -typedef struct \ -{ \ - KEY k; \ - VALUE v; \ -} STB_(N,_hashpair); \ - \ -STB__nogcc( typedef struct stb__st_##TYPE TYPE; ) \ -struct stb__st_##TYPE { \ - FIELDS \ - STB_(N,_hashpair) *table; \ - unsigned int mask; \ - int count, limit; \ - int deleted; \ - \ - int delete_threshhold; \ - int grow_threshhold; \ - int shrink_threshhold; \ - unsigned char alloced, has_empty, has_del; \ - VALUE ev; VALUE dv; \ -}; \ - \ -static unsigned int STB_(N, hash)(KEY k) \ -{ \ - HASH \ -} \ - \ -PREFIX int STB__(N, init)(TYPE *h, int count) \ -{ \ - int i; \ - if (count < 4) count = 4; \ - h->limit = count; \ - h->count = 0; \ - h->mask = count-1; \ - h->deleted = 0; \ - h->grow_threshhold = (int) (count * LOAD_FACTOR); \ - h->has_empty = h->has_del = 0; \ - h->alloced = 0; \ - if (count <= 64) \ - h->shrink_threshhold = 0; \ - else \ - h->shrink_threshhold = (int) (count * (LOAD_FACTOR/2.25)); \ - h->delete_threshhold = (int) (count * (1-LOAD_FACTOR)/2); \ - h->table = (STB_(N,_hashpair)*) malloc(sizeof(h->table[0]) * count); \ - if (h->table == NULL) return 0; \ - /* ideally this gets turned into a memset32 automatically */ \ - for (i=0; i < count; ++i) \ - h->table[i].k = EMPTY; \ - return 1; \ -} \ - \ -PREFIX int STB__(N, memory_usage)(TYPE *h) \ -{ \ - return sizeof(*h) + h->limit * sizeof(h->table[0]); \ -} \ - \ -PREFIX TYPE * STB__(N, create)(void) \ -{ \ - TYPE *h = (TYPE *) malloc(sizeof(*h)); \ - if (h) { \ - if (STB__(N, init)(h, 16)) \ - h->alloced = 1; \ - else { free(h); h=NULL; } \ - } \ - return h; \ -} \ - \ -PREFIX void STB__(N, destroy)(TYPE *a) \ -{ \ - int i; \ - for (i=0; i < a->limit; ++i) \ - if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k, DEL)) \ - DISPOSE(a->table[i].k); \ - free(a->table); \ - if (a->alloced) \ - free(a); \ -} \ - \ -static void STB_(N, rehash)(TYPE *a, int count); \ - \ -PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask, s; \ - if (CCOMPARE(k,EMPTY)){ if (a->has_empty) *v = a->ev; return a->has_empty;}\ - if (CCOMPARE(k,DEL)) { if (a->has_del ) *v = a->dv; return a->has_del; }\ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ - if (VCOMPARE(a->table[n].k,k)) { *v = a->table[n].v; return 1; } \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ - if (VCOMPARE(a->table[n].k,k)) \ - { *v = a->table[n].v; return 1; } \ - } \ -} \ - \ -HASVNULL( \ - PREFIX VALUE STB__(N,get)(TYPE *a, KEY k) \ - { \ - VALUE v; \ - if (STB__(N,get_flag)(a,k,&v)) return v; \ - else return VNULL; \ - } \ -) \ - \ -PREFIX int STB__(N,getkey)(TYPE *a, KEY k, KEY *kout) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask, s; \ - if (CCOMPARE(k,EMPTY)||CCOMPARE(k,DEL)) return 0; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ - if (VCOMPARE(a->table[n].k,k)) { *kout = a->table[n].k; return 1; } \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ - if (VCOMPARE(a->table[n].k,k)) \ - { *kout = a->table[n].k; return 1; } \ - } \ -} \ - \ -static int STB_(N,addset)(TYPE *a, KEY k, VALUE v, \ - int allow_new, int allow_old, int copy) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask; \ - int b = -1; \ - if (CCOMPARE(k,EMPTY)) { \ - if (a->has_empty ? allow_old : allow_new) { \ - n=a->has_empty; a->ev = v; a->has_empty = 1; return !n; \ - } else return 0; \ - } \ - if (CCOMPARE(k,DEL)) { \ - if (a->has_del ? allow_old : allow_new) { \ - n=a->has_del; a->dv = v; a->has_del = 1; return !n; \ - } else return 0; \ - } \ - if (!CCOMPARE(a->table[n].k, EMPTY)) { \ - unsigned int s; \ - if (CCOMPARE(a->table[n].k, DEL)) \ - b = n; \ - else if (VCOMPARE(a->table[n].k,k)) { \ - if (allow_old) \ - a->table[n].v = v; \ - return !allow_new; \ - } \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k, EMPTY)) break; \ - if (CCOMPARE(a->table[n].k, DEL)) { \ - if (b < 0) b = n; \ - } else if (VCOMPARE(a->table[n].k,k)) { \ - if (allow_old) \ - a->table[n].v = v; \ - return !allow_new; \ - } \ - } \ - } \ - if (!allow_new) return 0; \ - if (b < 0) b = n; else --a->deleted; \ - a->table[b].k = copy ? COPY(k) : k; \ - a->table[b].v = v; \ - ++a->count; \ - if (a->count > a->grow_threshhold) \ - STB_(N,rehash)(a, a->limit*2); \ - return 1; \ -} \ - \ -PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,1,1);}\ -PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,0,1);}\ -PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v){return STB_(N,addset)(a,k,v,0,1,1);}\ - \ -PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v) \ -{ \ - unsigned int h = STB_(N, hash)(k); \ - unsigned int n = h & a->mask, s; \ - if (CCOMPARE(k,EMPTY)) { if (a->has_empty) { if(v)*v = a->ev; a->has_empty=0; return 1; } return 0; } \ - if (CCOMPARE(k,DEL)) { if (a->has_del ) { if(v)*v = a->dv; a->has_del =0; return 1; } return 0; } \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - if (SAFE(CCOMPARE(a->table[n].k,DEL) || ) !VCOMPARE(a->table[n].k,k)) { \ - s = stb_rehash(h) | 1; \ - for(;;) { \ - n = (n + s) & a->mask; \ - if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ - SAFE(if (CCOMPARE(a->table[n].k, DEL)) continue;) \ - if (VCOMPARE(a->table[n].k,k)) break; \ - } \ - } \ - DISPOSE(a->table[n].k); \ - a->table[n].k = DEL; \ - --a->count; \ - ++a->deleted; \ - if (v != NULL) \ - *v = a->table[n].v; \ - if (a->count < a->shrink_threshhold) \ - STB_(N, rehash)(a, a->limit >> 1); \ - else if (a->deleted > a->delete_threshhold) \ - STB_(N, rehash)(a, a->limit); \ - return 1; \ -} \ - \ -PREFIX TYPE * STB__(NC, copy)(TYPE *a) \ -{ \ - int i; \ - TYPE *h = (TYPE *) malloc(sizeof(*h)); \ - if (!h) return NULL; \ - if (!STB__(N, init)(h, a->limit)) { free(h); return NULL; } \ - h->count = a->count; \ - h->deleted = a->deleted; \ - h->alloced = 1; \ - h->ev = a->ev; h->dv = a->dv; \ - h->has_empty = a->has_empty; h->has_del = a->has_del; \ - memcpy(h->table, a->table, h->limit * sizeof(h->table[0])); \ - for (i=0; i < a->limit; ++i) \ - if (!CCOMPARE(h->table[i].k,EMPTY) && !CCOMPARE(h->table[i].k,DEL)) \ - h->table[i].k = COPY(h->table[i].k); \ - return h; \ -} \ - \ -static void STB_(N, rehash)(TYPE *a, int count) \ -{ \ - int i; \ - TYPE b; \ - STB__(N, init)(&b, count); \ - for (i=0; i < a->limit; ++i) \ - if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k,DEL)) \ - STB_(N,addset)(&b, a->table[i].k, a->table[i].v,1,1,0); \ - free(a->table); \ - a->table = b.table; \ - a->mask = b.mask; \ - a->count = b.count; \ - a->limit = b.limit; \ - a->deleted = b.deleted; \ - a->delete_threshhold = b.delete_threshhold; \ - a->grow_threshhold = b.grow_threshhold; \ - a->shrink_threshhold = b.shrink_threshhold; \ -} - -#define STB_equal(a,b) ((a) == (b)) - -#define stb_define_hash(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE) \ - stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ - KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ - STB_equal,STB_equal,HASH, \ - VALUE,STB_nonullvalue,0) - -#define stb_define_hash_vnull(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE,VNULL) \ - stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ - KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ - STB_equal,STB_equal,HASH, \ - VALUE,STB_nullvalue,VNULL) - -////////////////////////////////////////////////////////////////////////////// -// -// stb_ptrmap -// -// An stb_ptrmap data structure is an O(1) hash table between pointers. One -// application is to let you store "extra" data associated with pointers, -// which is why it was originally called stb_extra. - -#ifndef STB_INCLUDE_STB_LIB_H -stb_declare_hash(STB_EXTERN, stb_ptrmap, stb_ptrmap_, void *, void *) -stb_declare_hash(STB_EXTERN, stb_idict, stb_idict_, stb_int32, stb_int32) - -STB_EXTERN void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *)); -STB_EXTERN stb_ptrmap *stb_ptrmap_new(void); - -STB_EXTERN stb_idict * stb_idict_new_size(unsigned int size); -STB_EXTERN void stb_idict_remove_all(stb_idict *e); -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION - -#define STB_EMPTY ((void *) 2) -#define STB_EDEL ((void *) 6) - -stb_define_hash_base(STB_noprefix,stb_ptrmap, STB_nofields, stb_ptrmap_,stb_ptrmap_,0.85f, - void *,STB_EMPTY,STB_EDEL,STB_nocopy,STB_nodelete,STB_nosafe, - STB_equal,STB_equal,return stb_hashptr(k);, - void *,STB_nullvalue,NULL) - -stb_ptrmap *stb_ptrmap_new(void) -{ - return stb_ptrmap_create(); -} - -void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *)) -{ - int i; - if (free_func) - for (i=0; i < e->limit; ++i) - if (e->table[i].k != STB_EMPTY && e->table[i].k != STB_EDEL) { - if (free_func == free) - free(e->table[i].v); // allow STB_MALLOC_WRAPPER to operate - else - free_func(e->table[i].v); - } - stb_ptrmap_destroy(e); -} - -// extra fields needed for stua_dict -#define STB_IEMPTY ((int) 1) -#define STB_IDEL ((int) 3) -stb_define_hash_base(STB_noprefix, stb_idict, STB_nofields, stb_idict_,stb_idict_,0.85f, - stb_int32,STB_IEMPTY,STB_IDEL,STB_nocopy,STB_nodelete,STB_nosafe, - STB_equal,STB_equal, - return stb_rehash_improved(k);,stb_int32,STB_nonullvalue,0) - -stb_idict * stb_idict_new_size(unsigned int size) -{ - stb_idict *e = (stb_idict *) malloc(sizeof(*e)); - if (e) { - // round up to power of 2 - while ((size & (size-1)) != 0) // while more than 1 bit is set - size += (size & ~(size-1)); // add the lowest set bit - stb_idict_init(e, size); - e->alloced = 1; - } - return e; -} - -void stb_idict_remove_all(stb_idict *e) -{ - int n; - for (n=0; n < e->limit; ++n) - e->table[n].k = STB_IEMPTY; - e->has_empty = e->has_del = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// SDICT: Hash Table for Strings (symbol table) -// -// if "use_arena=1", then strings will be copied -// into blocks and never freed until the sdict is freed; -// otherwise they're malloc()ed and free()d on the fly. -// (specify use_arena=1 if you never stb_sdict_remove) - -#ifndef STB_INCLUDE_STB_LIB_H -stb_declare_hash(STB_EXTERN, stb_sdict, stb_sdict_, char *, void *) - -STB_EXTERN stb_sdict * stb_sdict_new(void); -STB_EXTERN stb_sdict * stb_sdict_copy(stb_sdict*); -STB_EXTERN void stb_sdict_delete(stb_sdict *); -STB_EXTERN void * stb_sdict_change(stb_sdict *, char *str, void *p); -STB_EXTERN int stb_sdict_count(stb_sdict *d); - -STB_EXTERN int stb_sdict_internal_limit(stb_sdict *d); -STB_EXTERN char * stb_sdict_internal_key(stb_sdict *d, int n); -STB_EXTERN void * stb_sdict_internal_value(stb_sdict *d, int n); - -#define stb_sdict_for(d,i,q,z) \ - for(i=0; i < stb_sdict_internal_limit(d) ? (q=stb_sdict_internal_key(d,i),z=stb_sdict_internal_value(d,i),1) : 0; ++i) \ - if (q==NULL||q==(void *) 1);else // reversed makes macro friendly -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION - -// if in same translation unit, for speed, don't call accessors -#undef stb_sdict_for -#define stb_sdict_for(d,i,q,z) \ - for(i=0; i < (d)->limit ? (q=(d)->table[i].k,z=(d)->table[i].v,1) : 0; ++i) \ - if (q==NULL||q==(void *) 1);else // reversed makes macro friendly - -//#define STB_DEL ((void *) 1) -#define STB_SDEL ((char *) 1) - -stb_define_hash_base(STB_noprefix, stb_sdict, STB_nofields, stb_sdict_,stb_sdictinternal_, 0.85f, - char *, NULL, STB_SDEL, strdup, free, - STB_safecompare, !strcmp, STB_equal, return stb_hash(k);, - void *, STB_nullvalue, NULL) - -int stb_sdict_count(stb_sdict *a) -{ - return a->count; -} - -int stb_sdict_internal_limit(stb_sdict *a) -{ - return a->limit; -} -char* stb_sdict_internal_key(stb_sdict *a, int n) -{ - return a->table[n].k; -} -void* stb_sdict_internal_value(stb_sdict *a, int n) -{ - return a->table[n].v; -} - -stb_sdict * stb_sdict_new(void) -{ - stb_sdict *d = stb_sdict_create(); - if (d == NULL) return NULL; - return d; -} - -stb_sdict* stb_sdict_copy(stb_sdict *old) -{ - return stb_sdictinternal_copy(old); -} - -void stb_sdict_delete(stb_sdict *d) -{ - stb_sdict_destroy(d); -} - -void * stb_sdict_change(stb_sdict *d, char *str, void *p) -{ - void *q = stb_sdict_get(d, str); - stb_sdict_set(d, str, p); - return q; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// File Processing -// - -#ifndef STB_INCLUDE_STB_LIB_H -#ifdef _MSC_VER - #define stb_rename(x,y) _wrename((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y)) - #define stb_mktemp _mktemp -#else - #define stb_mktemp mktemp - #define stb_rename rename -#endif - -#define stb_filec (char *) stb_file -#define stb_fileu (unsigned char *) stb_file -STB_EXTERN void * stb_file(char *filename, size_t *length); -STB_EXTERN size_t stb_filelen(FILE *f); -STB_EXTERN int stb_filewrite(char *filename, void *data, size_t length); -STB_EXTERN int stb_filewritestr(char *filename, char *data); -STB_EXTERN char ** stb_stringfile(char *filename, int *len); -STB_EXTERN char * stb_fgets(char *buffer, int buflen, FILE *f); -STB_EXTERN char * stb_fgets_malloc(FILE *f); -STB_EXTERN int stb_fexists(char *filename); -STB_EXTERN int stb_fcmp(char *s1, char *s2); -STB_EXTERN int stb_feq(char *s1, char *s2); -STB_EXTERN time_t stb_ftimestamp(char *filename); -STB_EXTERN int stb_fullpath(char *abs, int abs_size, char *rel); - -STB_EXTERN int stb_copyfile(char *src, char *dest); -STB_EXTERN int stb_fread(void *data, size_t len, size_t count, void *f); -STB_EXTERN int stb_fwrite(void *data, size_t len, size_t count, void *f); -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -#if defined(_MSC_VER) || defined(__MINGW32__) - #define stb__stat _stat -#else - #define stb__stat stat -#endif - -int stb_fexists(char *filename) -{ - struct stb__stat buf; - return stb__windows( - _wstat((const wchar_t *)stb__from_utf8(filename), &buf), - stat(filename,&buf) - ) == 0; -} - -time_t stb_ftimestamp(char *filename) -{ - struct stb__stat buf; - if (stb__windows( - _wstat((const wchar_t *)stb__from_utf8(filename), &buf), - stat(filename,&buf) - ) == 0) - { - return buf.st_mtime; - } else { - return 0; - } -} - -size_t stb_filelen(FILE *f) -{ - size_t len, pos; - pos = ftell(f); - fseek(f, 0, SEEK_END); - len = ftell(f); - fseek(f, pos, SEEK_SET); - return len; -} - -void *stb_file(char *filename, size_t *length) -{ - FILE *f = stb__fopen(filename, "rb"); - char *buffer; - size_t len, len2; - if (!f) return NULL; - len = stb_filelen(f); - buffer = (char *) malloc(len+2); // nul + extra - len2 = fread(buffer, 1, len, f); - if (len2 == len) { - if (length) *length = len; - buffer[len] = 0; - } else { - free(buffer); - buffer = NULL; - } - fclose(f); - return buffer; -} - -int stb_filewrite(char *filename, void *data, size_t length) -{ - FILE *f = stb__fopen(filename, "wb"); - if (f) { - unsigned char *data_ptr = (unsigned char *) data; - size_t remaining = length; - while (remaining > 0) { - size_t len2 = remaining > 65536 ? 65536 : remaining; - size_t len3 = fwrite(data_ptr, 1, len2, f); - if (len2 != len3) { - fprintf(stderr, "Failed while writing %s\n", filename); - break; - } - remaining -= len2; - data_ptr += len2; - } - fclose(f); - } - return f != NULL; -} - -int stb_filewritestr(char *filename, char *data) -{ - return stb_filewrite(filename, data, strlen(data)); -} - -char ** stb_stringfile(char *filename, int *plen) -{ - FILE *f = stb__fopen(filename, "rb"); - char *buffer, **list=NULL, *s; - size_t len, count, i; - - if (!f) return NULL; - len = stb_filelen(f); - buffer = (char *) malloc(len+1); - len = fread(buffer, 1, len, f); - buffer[len] = 0; - fclose(f); - - // two passes through: first time count lines, second time set them - for (i=0; i < 2; ++i) { - s = buffer; - if (i == 1) - list[0] = s; - count = 1; - while (*s) { - if (*s == '\n' || *s == '\r') { - // detect if both cr & lf are together - int crlf = (s[0] + s[1]) == ('\n' + '\r'); - if (i == 1) *s = 0; - if (crlf) ++s; - if (s[1]) { // it's not over yet - if (i == 1) list[count] = s+1; - ++count; - } - } - ++s; - } - if (i == 0) { - list = (char **) malloc(sizeof(*list) * (count+1) + len+1); - if (!list) return NULL; - list[count] = 0; - // recopy the file so there's just a single allocation to free - memcpy(&list[count+1], buffer, len+1); - free(buffer); - buffer = (char *) &list[count+1]; - if (plen) *plen = count; - } - } - return list; -} - -char * stb_fgets(char *buffer, int buflen, FILE *f) -{ - char *p; - buffer[0] = 0; - p = fgets(buffer, buflen, f); - if (p) { - int n = strlen(p)-1; - if (n >= 0) - if (p[n] == '\n') - p[n] = 0; - } - return p; -} - -char * stb_fgets_malloc(FILE *f) -{ - // avoid reallocing for small strings - char quick_buffer[800]; - quick_buffer[sizeof(quick_buffer)-2] = 0; - if (!fgets(quick_buffer, sizeof(quick_buffer), f)) - return NULL; - - if (quick_buffer[sizeof(quick_buffer)-2] == 0) { - int n = strlen(quick_buffer); - if (n > 0 && quick_buffer[n-1] == '\n') - quick_buffer[n-1] = 0; - return strdup(quick_buffer); - } else { - char *p; - char *a = strdup(quick_buffer); - int len = sizeof(quick_buffer)-1; - - while (!feof(f)) { - if (a[len-1] == '\n') break; - a = (char *) realloc(a, len*2); - p = &a[len]; - p[len-2] = 0; - if (!fgets(p, len, f)) - break; - if (p[len-2] == 0) { - len += strlen(p); - break; - } - len = len + (len-1); - } - if (a[len-1] == '\n') - a[len-1] = 0; - return a; - } -} - -int stb_fullpath(char *abs, int abs_size, char *rel) -{ - #ifdef _MSC_VER - return _fullpath(abs, rel, abs_size) != NULL; - #else - if (rel[0] == '/' || rel[0] == '~') { - if ((int) strlen(rel) >= abs_size) - return 0; - strcpy(abs,rel); - return 1; - } else { - int n; - getcwd(abs, abs_size); - n = strlen(abs); - if (n+(int) strlen(rel)+2 <= abs_size) { - abs[n] = '/'; - strcpy(abs+n+1, rel); - return 1; - } else { - return 0; - } - } - #endif -} - -static int stb_fcmp_core(FILE *f, FILE *g) -{ - char buf1[1024],buf2[1024]; - int n1,n2, res=0; - - while (1) { - n1 = fread(buf1, 1, sizeof(buf1), f); - n2 = fread(buf2, 1, sizeof(buf2), g); - res = memcmp(buf1,buf2,n1 < n2 ? n1 : n2); - if (res) - break; - if (n1 != n2) { - res = n1 < n2 ? -1 : 1; - break; - } - if (n1 == 0) - break; - } - - fclose(f); - fclose(g); - return res; -} - -int stb_fcmp(char *s1, char *s2) -{ - FILE *f = stb__fopen(s1, "rb"); - FILE *g = stb__fopen(s2, "rb"); - - if (f == NULL || g == NULL) { - if (f) fclose(f); - if (g) { - fclose(g); - return 1; - } - return f != NULL; - } - - return stb_fcmp_core(f,g); -} - -int stb_feq(char *s1, char *s2) -{ - FILE *f = stb__fopen(s1, "rb"); - FILE *g = stb__fopen(s2, "rb"); - - if (f == NULL || g == NULL) { - if (f) fclose(f); - if (g) fclose(g); - return f == g; - } - - // feq is faster because it shortcuts if they're different length - if (stb_filelen(f) != stb_filelen(g)) { - fclose(f); - fclose(g); - return 0; - } - - return !stb_fcmp_core(f,g); -} - -int stb_copyfile(char *src, char *dest) -{ - char raw_buffer[1024]; - char *buffer; - int buf_size = 65536; - - FILE *f, *g; - - // if file already exists at destination, do nothing - if (stb_feq(src, dest)) return 1; - - // open file - f = stb__fopen(src, "rb"); - if (f == NULL) return 0; - - // open file for writing - g = stb__fopen(dest, "wb"); - if (g == NULL) { - fclose(f); - return 0; - } - - buffer = (char *) malloc(buf_size); - if (buffer == NULL) { - buffer = raw_buffer; - buf_size = sizeof(raw_buffer); - } - - while (!feof(f)) { - int n = fread(buffer, 1, buf_size, f); - if (n != 0) - fwrite(buffer, 1, n, g); - } - - fclose(f); - if (buffer != raw_buffer) - free(buffer); - - fclose(g); - return 1; -} - -#define stb_fgetc(f) ((unsigned char) fgetc(f)) - -#if 0 -// strip the trailing '/' or '\\' from a directory so we can refer to it -// as a file for _stat() -char *stb_strip_final_slash(char *t) -{ - if (t[0]) { - char *z = t + strlen(t) - 1; - // *z is the last character - if (*z == '\\' || *z == '/') - if (z != t+2 || t[1] != ':') // but don't strip it if it's e.g. "c:/" - *z = 0; - if (*z == '\\') - *z = '/'; // canonicalize to make sure it matches db - } - return t; -} - -char *stb_strip_final_slash_regardless(char *t) -{ - if (t[0]) { - char *z = t + strlen(t) - 1; - // *z is the last character - if (*z == '\\' || *z == '/') - *z = 0; - if (*z == '\\') - *z = '/'; // canonicalize to make sure it matches db - } - return t; -} -#endif -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Portable directory reading -// - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN char **stb_readdir_files (char *dir); -STB_EXTERN char **stb_readdir_files_mask(char *dir, char *wild); -STB_EXTERN char **stb_readdir_subdirs(char *dir); -STB_EXTERN char **stb_readdir_subdirs_mask(char *dir, char *wild); -STB_EXTERN void stb_readdir_free (char **files); -STB_EXTERN char **stb_readdir_recursive(char *dir, char *filespec); -STB_EXTERN void stb_delete_directory_recursive(char *dir); - -// forward declare for implementation -STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); -#endif // STB_INCLUDE_STB_LIB_H - - -#ifdef STB_LIB_IMPLEMENTATION - -#ifdef _MSC_VER -#include -#else -#include -#include -#endif - -void stb_readdir_free(char **files) -{ - char **f2 = files; - int i; - for (i=0; i < stb_arr_len(f2); ++i) - free(f2[i]); - stb_arr_free(f2); -} - -static int isdotdirname(char *name) -{ - if (name[0] == '.') - return (name[1] == '.') ? !name[2] : !name[1]; - return 0; -} - -static char **readdir_raw(char *dir, int return_subdirs, char *mask) -{ - char **results = NULL; - char buffer[4096], with_slash[4096]; - size_t n; - - #ifdef _MSC_VER - stb__wchar *ws; - struct _wfinddata_t data; - #ifdef _WIN64 - const intptr_t none = -1; - intptr_t z; - #else - const long none = -1; - long z; - #endif - #else // !_MSC_VER - const DIR *none = NULL; - DIR *z; - #endif - - n = stb_strscpy(buffer,dir,sizeof(buffer)); - if (!n || n >= sizeof(buffer)) - return NULL; - stb_fixpath(buffer); - n--; - - if (n > 0 && (buffer[n-1] != '/')) { - buffer[n++] = '/'; - } - buffer[n] = 0; - if (!stb_strscpy(with_slash,buffer,sizeof(with_slash))) - return NULL; - - #ifdef _MSC_VER - if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n)) - return NULL; - ws = stb__from_utf8(buffer); - z = _wfindfirst((const wchar_t *)ws, &data); - #else - z = opendir(dir); - #endif - - if (z != none) { - int nonempty = 1; - #ifndef _MSC_VER - struct dirent *data = readdir(z); - nonempty = (data != NULL); - #endif - - if (nonempty) { - - do { - int is_subdir; - #ifdef _MSC_VER - char *name = stb__to_utf8((stb__wchar *)data.name); - if (name == NULL) { - fprintf(stderr, "%s to convert '%S' to %s!\n", "Unable", data.name, "utf8"); - continue; - } - is_subdir = !!(data.attrib & _A_SUBDIR); - #else - char *name = data->d_name; - if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n)) - break; - // Could follow DT_LNK, but would need to check for recursive links. - is_subdir = !!(data->d_type & DT_DIR); - #endif - - if (is_subdir == return_subdirs) { - if (!is_subdir || !isdotdirname(name)) { - if (!mask || stb_wildmatchi(mask, name)) { - char buffer[4096],*p=buffer; - if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 ) - break; - if (buffer[0] == '.' && buffer[1] == '/') - p = buffer+2; - stb_arr_push(results, strdup(p)); - } - } - } - } - #ifdef _MSC_VER - while (0 == _wfindnext(z, &data)); - #else - while ((data = readdir(z)) != NULL); - #endif - } - #ifdef _MSC_VER - _findclose(z); - #else - closedir(z); - #endif - } - return results; -} - -char **stb_readdir_files (char *dir) { return readdir_raw(dir, 0, NULL); } -char **stb_readdir_subdirs(char *dir) { return readdir_raw(dir, 1, NULL); } -char **stb_readdir_files_mask(char *dir, char *wild) { return readdir_raw(dir, 0, wild); } -char **stb_readdir_subdirs_mask(char *dir, char *wild) { return readdir_raw(dir, 1, wild); } - -int stb__rec_max=0x7fffffff; -static char **stb_readdir_rec(char **sofar, char *dir, char *filespec) -{ - char **files; - char ** dirs; - char **p; - - if (stb_arr_len(sofar) >= stb__rec_max) return sofar; - - files = stb_readdir_files_mask(dir, filespec); - stb_arr_for(p, files) { - stb_arr_push(sofar, strdup(*p)); - if (stb_arr_len(sofar) >= stb__rec_max) break; - } - stb_readdir_free(files); - if (stb_arr_len(sofar) >= stb__rec_max) return sofar; - - dirs = stb_readdir_subdirs(dir); - stb_arr_for(p, dirs) - sofar = stb_readdir_rec(sofar, *p, filespec); - stb_readdir_free(dirs); - return sofar; -} - -char **stb_readdir_recursive(char *dir, char *filespec) -{ - return stb_readdir_rec(NULL, dir, filespec); -} - -void stb_delete_directory_recursive(char *dir) -{ - char **list = stb_readdir_subdirs(dir); - int i; - for (i=0; i < stb_arr_len(list); ++i) - stb_delete_directory_recursive(list[i]); - stb_arr_free(list); - list = stb_readdir_files(dir); - for (i=0; i < stb_arr_len(list); ++i) - if (!remove(list[i])) { - // on windows, try again after making it writeable; don't ALWAYS - // do this first since that would be slow in the normal case - #ifdef _MSC_VER - _chmod(list[i], _S_IWRITE); - remove(list[i]); - #endif - } - stb_arr_free(list); - stb__windows(_rmdir,rmdir)(dir); -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Checksums: CRC-32, ADLER32, SHA-1 -// -// CRC-32 and ADLER32 allow streaming blocks -// SHA-1 requires either a complete buffer, max size 2^32 - 73 -// or it can checksum directly from a file, max 2^61 - -#ifndef STB_INCLUDE_STB_LIB_H -#define STB_ADLER32_SEED 1 -#define STB_CRC32_SEED 0 // note that we logical NOT this in the code - -STB_EXTERN stb_uint stb_adler32 (stb_uint adler32, stb_uchar *buffer, stb_uint buflen); -STB_EXTERN stb_uint stb_crc32_block(stb_uint crc32 , stb_uchar *buffer, stb_uint buflen); -STB_EXTERN stb_uint stb_crc32 ( stb_uchar *buffer, stb_uint buflen); - -STB_EXTERN void stb_sha1( unsigned char output[20], stb_uchar *buffer, unsigned int len); -STB_EXTERN int stb_sha1_file(unsigned char output[20], char *file); -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -stb_uint stb_crc32_block(stb_uint crc, unsigned char *buffer, stb_uint len) -{ - static stb_uint crc_table[256]; - stb_uint i,j,s; - crc = ~crc; - - if (crc_table[1] == 0) - for(i=0; i < 256; i++) { - for (s=i, j=0; j < 8; ++j) - s = (s >> 1) ^ (s & 1 ? 0xedb88320 : 0); - crc_table[i] = s; - } - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; -} - -stb_uint stb_crc32(unsigned char *buffer, stb_uint len) -{ - return stb_crc32_block(0, buffer, len); -} - -stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen) -{ - const unsigned long ADLER_MOD = 65521; - unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; - unsigned long blocklen, i; - - blocklen = buflen % 5552; - while (buflen) { - for (i=0; i + 7 < blocklen; i += 8) { - s1 += buffer[0], s2 += s1; - s1 += buffer[1], s2 += s1; - s1 += buffer[2], s2 += s1; - s1 += buffer[3], s2 += s1; - s1 += buffer[4], s2 += s1; - s1 += buffer[5], s2 += s1; - s1 += buffer[6], s2 += s1; - s1 += buffer[7], s2 += s1; - - buffer += 8; - } - - for (; i < blocklen; ++i) - s1 += *buffer++, s2 += s1; - - s1 %= ADLER_MOD, s2 %= ADLER_MOD; - buflen -= blocklen; - blocklen = 5552; - } - return (s2 << 16) + s1; -} - -#define stb__big32(c) (((c)[0]<<24) + (c)[1]*65536 + (c)[2]*256 + (c)[3]) -static void stb__sha1(stb_uchar *chunk, stb_uint h[5]) -{ - int i; - stb_uint a,b,c,d,e; - stb_uint w[80]; - - for (i=0; i < 16; ++i) - w[i] = stb__big32(&chunk[i*4]); - for (i=16; i < 80; ++i) { - stb_uint t; - t = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; - w[i] = (t + t) | (t >> 31); - } - - a = h[0]; - b = h[1]; - c = h[2]; - d = h[3]; - e = h[4]; - - #define STB__SHA1(k,f) \ - { \ - stb_uint temp = (a << 5) + (a >> 27) + (f) + e + (k) + w[i]; \ - e = d; \ - d = c; \ - c = (b << 30) + (b >> 2); \ - b = a; \ - a = temp; \ - } - - i=0; - for (; i < 20; ++i) STB__SHA1(0x5a827999, d ^ (b & (c ^ d)) ); - for (; i < 40; ++i) STB__SHA1(0x6ed9eba1, b ^ c ^ d ); - for (; i < 60; ++i) STB__SHA1(0x8f1bbcdc, (b & c) + (d & (b ^ c)) ); - for (; i < 80; ++i) STB__SHA1(0xca62c1d6, b ^ c ^ d ); - - #undef STB__SHA1 - - h[0] += a; - h[1] += b; - h[2] += c; - h[3] += d; - h[4] += e; -} - -void stb_sha1(stb_uchar output[20], stb_uchar *buffer, stb_uint len) -{ - unsigned char final_block[128]; - stb_uint end_start, final_len, j; - int i; - - stb_uint h[5]; - - h[0] = 0x67452301; - h[1] = 0xefcdab89; - h[2] = 0x98badcfe; - h[3] = 0x10325476; - h[4] = 0xc3d2e1f0; - - // we need to write padding to the last one or two - // blocks, so build those first into 'final_block' - - // we have to write one special byte, plus the 8-byte length - - // compute the block where the data runs out - end_start = len & ~63; - - // compute the earliest we can encode the length - if (((len+9) & ~63) == end_start) { - // it all fits in one block, so fill a second-to-last block - end_start -= 64; - } - - final_len = end_start + 128; - - // now we need to copy the data in - assert(end_start + 128 >= len+9); - assert(end_start < len || len < 64-9); - - j = 0; - if (end_start > len) - j = (stb_uint) - (int) end_start; - - for (; end_start + j < len; ++j) - final_block[j] = buffer[end_start + j]; - final_block[j++] = 0x80; - while (j < 128-5) // 5 byte length, so write 4 extra padding bytes - final_block[j++] = 0; - // big-endian size - final_block[j++] = len >> 29; - final_block[j++] = len >> 21; - final_block[j++] = len >> 13; - final_block[j++] = len >> 5; - final_block[j++] = len << 3; - assert(j == 128 && end_start + j == final_len); - - for (j=0; j < final_len; j += 64) { // 512-bit chunks - if (j+64 >= end_start+64) - stb__sha1(&final_block[j - end_start], h); - else - stb__sha1(&buffer[j], h); - } - - for (i=0; i < 5; ++i) { - output[i*4 + 0] = h[i] >> 24; - output[i*4 + 1] = h[i] >> 16; - output[i*4 + 2] = h[i] >> 8; - output[i*4 + 3] = h[i] >> 0; - } -} - -int stb_sha1_file(stb_uchar output[20], char *file) -{ - int i; - stb_uint64 length=0; - unsigned char buffer[128]; - - FILE *f = stb__fopen(file, "rb"); - stb_uint h[5]; - - if (f == NULL) return 0; // file not found - - h[0] = 0x67452301; - h[1] = 0xefcdab89; - h[2] = 0x98badcfe; - h[3] = 0x10325476; - h[4] = 0xc3d2e1f0; - - for(;;) { - int n = fread(buffer, 1, 64, f); - if (n == 64) { - stb__sha1(buffer, h); - length += n; - } else { - int block = 64; - - length += n; - - buffer[n++] = 0x80; - - // if there isn't enough room for the length, double the block - if (n + 8 > 64) - block = 128; - - // pad to end - memset(buffer+n, 0, block-8-n); - - i = block - 8; - buffer[i++] = (stb_uchar) (length >> 53); - buffer[i++] = (stb_uchar) (length >> 45); - buffer[i++] = (stb_uchar) (length >> 37); - buffer[i++] = (stb_uchar) (length >> 29); - buffer[i++] = (stb_uchar) (length >> 21); - buffer[i++] = (stb_uchar) (length >> 13); - buffer[i++] = (stb_uchar) (length >> 5); - buffer[i++] = (stb_uchar) (length << 3); - assert(i == block); - stb__sha1(buffer, h); - if (block == 128) - stb__sha1(buffer+64, h); - else - assert(block == 64); - break; - } - } - fclose(f); - - for (i=0; i < 5; ++i) { - output[i*4 + 0] = h[i] >> 24; - output[i*4 + 1] = h[i] >> 16; - output[i*4 + 2] = h[i] >> 8; - output[i*4 + 3] = h[i] >> 0; - } - - return 1; -} -#endif // STB_LIB_IMPLEMENTATION - -////////////////////////////////////////////////////////////////////////////// -// -// Random Numbers via Meresenne Twister or LCG -// - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN unsigned long stb_srandLCG(unsigned long seed); -STB_EXTERN unsigned long stb_randLCG(void); -STB_EXTERN double stb_frandLCG(void); - -STB_EXTERN void stb_srand(unsigned long seed); -STB_EXTERN unsigned long stb_rand(void); -STB_EXTERN double stb_frand(void); -STB_EXTERN void stb_shuffle(void *p, size_t n, size_t sz, - unsigned long seed); -STB_EXTERN void stb_reverse(void *p, size_t n, size_t sz); - -STB_EXTERN unsigned long stb_randLCG_explicit(unsigned long seed); -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -unsigned long stb_randLCG_explicit(unsigned long seed) -{ - return seed * 2147001325 + 715136305; -} - -static unsigned long stb__rand_seed=0; - -unsigned long stb_srandLCG(unsigned long seed) -{ - unsigned long previous = stb__rand_seed; - stb__rand_seed = seed; - return previous; -} - -unsigned long stb_randLCG(void) -{ - stb__rand_seed = stb__rand_seed * 2147001325 + 715136305; // BCPL generator - // shuffle non-random bits to the middle, and xor to decorrelate with seed - return 0x31415926 ^ ((stb__rand_seed >> 16) + (stb__rand_seed << 16)); -} - -double stb_frandLCG(void) -{ - return stb_randLCG() / ((double) (1 << 16) * (1 << 16)); -} - -void stb_shuffle(void *p, size_t n, size_t sz, unsigned long seed) -{ - char *a; - unsigned long old_seed; - int i; - if (seed) - old_seed = stb_srandLCG(seed); - a = (char *) p + (n-1) * sz; - - for (i=n; i > 1; --i) { - int j = stb_randLCG() % i; - stb_swap(a, (char *) p + j * sz, sz); - a -= sz; - } - if (seed) - stb_srandLCG(old_seed); -} - -void stb_reverse(void *p, size_t n, size_t sz) -{ - int i,j = n-1; - for (i=0; i < j; ++i,--j) { - stb_swap((char *) p + i * sz, (char *) p + j * sz, sz); - } -} - -// public domain Mersenne Twister by Michael Brundage -#define STB__MT_LEN 624 - -int stb__mt_index = STB__MT_LEN*sizeof(unsigned long)+1; -unsigned long stb__mt_buffer[STB__MT_LEN]; - -void stb_srand(unsigned long seed) -{ - int i; - unsigned long old = stb_srandLCG(seed); - for (i = 0; i < STB__MT_LEN; i++) - stb__mt_buffer[i] = stb_randLCG(); - stb_srandLCG(old); - stb__mt_index = STB__MT_LEN*sizeof(unsigned long); -} - -#define STB__MT_IA 397 -#define STB__MT_IB (STB__MT_LEN - STB__MT_IA) -#define STB__UPPER_MASK 0x80000000 -#define STB__LOWER_MASK 0x7FFFFFFF -#define STB__MATRIX_A 0x9908B0DF -#define STB__TWIST(b,i,j) ((b)[i] & STB__UPPER_MASK) | ((b)[j] & STB__LOWER_MASK) -#define STB__MAGIC(s) (((s)&1)*STB__MATRIX_A) - -unsigned long stb_rand() -{ - unsigned long * b = stb__mt_buffer; - int idx = stb__mt_index; - unsigned long s,r; - int i; - - if (idx >= STB__MT_LEN*sizeof(unsigned long)) { - if (idx > STB__MT_LEN*sizeof(unsigned long)) - stb_srand(0); - idx = 0; - i = 0; - for (; i < STB__MT_IB; i++) { - s = STB__TWIST(b, i, i+1); - b[i] = b[i + STB__MT_IA] ^ (s >> 1) ^ STB__MAGIC(s); - } - for (; i < STB__MT_LEN-1; i++) { - s = STB__TWIST(b, i, i+1); - b[i] = b[i - STB__MT_IB] ^ (s >> 1) ^ STB__MAGIC(s); - } - - s = STB__TWIST(b, STB__MT_LEN-1, 0); - b[STB__MT_LEN-1] = b[STB__MT_IA-1] ^ (s >> 1) ^ STB__MAGIC(s); - } - stb__mt_index = idx + sizeof(unsigned long); - - r = *(unsigned long *)((unsigned char *)b + idx); - - r ^= (r >> 11); - r ^= (r << 7) & 0x9D2C5680; - r ^= (r << 15) & 0xEFC60000; - r ^= (r >> 18); - - return r; -} - -double stb_frand(void) -{ - return stb_rand() / ((double) (1 << 16) * (1 << 16)); -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// wildcards and regexping -// - -#ifndef STB_INCLUDE_STB_LIB_H -STB_EXTERN int stb_wildmatch (char *expr, char *candidate); -STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); -STB_EXTERN int stb_wildfind (char *expr, char *candidate); -STB_EXTERN int stb_wildfindi (char *expr, char *candidate); -#endif // STB_INCLUDE_STB_LIB_H - -#ifdef STB_LIB_IMPLEMENTATION -static int stb__match_qstring(char *candidate, char *qstring, int qlen, int insensitive) -{ - int i; - if (insensitive) { - for (i=0; i < qlen; ++i) - if (qstring[i] == '?') { - if (!candidate[i]) return 0; - } else - if (tolower(qstring[i]) != tolower(candidate[i])) - return 0; - } else { - for (i=0; i < qlen; ++i) - if (qstring[i] == '?') { - if (!candidate[i]) return 0; - } else - if (qstring[i] != candidate[i]) - return 0; - } - return 1; -} - -static int stb__find_qstring(char *candidate, char *qstring, int qlen, int insensitive) -{ - char c; - - int offset=0; - while (*qstring == '?') { - ++qstring; - --qlen; - ++candidate; - if (qlen == 0) return 0; - if (*candidate == 0) return -1; - } - - c = *qstring++; - --qlen; - if (insensitive) c = tolower(c); - - while (candidate[offset]) { - if (c == (insensitive ? tolower(candidate[offset]) : candidate[offset])) - if (stb__match_qstring(candidate+offset+1, qstring, qlen, insensitive)) - return offset; - ++offset; - } - - return -1; -} - -int stb__wildmatch_raw2(char *expr, char *candidate, int search, int insensitive) -{ - int where=0; - int start = -1; - - if (!search) { - // parse to first '*' - if (*expr != '*') - start = 0; - while (*expr != '*') { - if (!*expr) - return *candidate == 0 ? 0 : -1; - if (*expr == '?') { - if (!*candidate) return -1; - } else { - if (insensitive) { - if (tolower(*candidate) != tolower(*expr)) - return -1; - } else - if (*candidate != *expr) - return -1; - } - ++candidate, ++expr, ++where; - } - } else { - // 0-length search string - if (!*expr) - return 0; - } - - assert(search || *expr == '*'); - if (!search) - ++expr; - - // implicit '*' at this point - - while (*expr) { - int o=0; - // combine redundant * characters - while (expr[0] == '*') ++expr; - - // ok, at this point, expr[-1] == '*', - // and expr[0] != '*' - - if (!expr[0]) return start >= 0 ? start : 0; - - // now find next '*' - o = 0; - while (expr[o] != '*') { - if (expr[o] == 0) - break; - ++o; - } - // if no '*', scan to end, then match at end - if (expr[o] == 0 && !search) { - int z; - for (z=0; z < o; ++z) - if (candidate[z] == 0) - return -1; - while (candidate[z]) - ++z; - // ok, now check if they match - if (stb__match_qstring(candidate+z-o, expr, o, insensitive)) - return start >= 0 ? start : 0; - return -1; - } else { - // if yes '*', then do stb__find_qmatch on the intervening chars - int n = stb__find_qstring(candidate, expr, o, insensitive); - if (n < 0) - return -1; - if (start < 0) - start = where + n; - expr += o; - candidate += n+o; - } - - if (*expr == 0) { - assert(search); - return start; - } - - assert(*expr == '*'); - ++expr; - } - - return start >= 0 ? start : 0; -} - -int stb__wildmatch_raw(char *expr, char *candidate, int search, int insensitive) -{ - char buffer[256]; - // handle multiple search strings - char *s = strchr(expr, ';'); - char *last = expr; - while (s) { - int z; - // need to allow for non-writeable strings... assume they're small - if (s - last < 256) { - stb_strncpy(buffer, last, s-last+1); - z = stb__wildmatch_raw2(buffer, candidate, search, insensitive); - } else { - *s = 0; - z = stb__wildmatch_raw2(last, candidate, search, insensitive); - *s = ';'; - } - if (z >= 0) return z; - last = s+1; - s = strchr(last, ';'); - } - return stb__wildmatch_raw2(last, candidate, search, insensitive); -} - -int stb_wildmatch(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 0,0) >= 0; -} - -int stb_wildmatchi(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 0,1) >= 0; -} - -int stb_wildfind(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 1,0); -} - -int stb_wildfindi(char *expr, char *candidate) -{ - return stb__wildmatch_raw(expr, candidate, 1,1); -} - -#undef STB_LIB_IMPLEMENTATION -#endif // STB_LIB_IMPLEMENTATION - -#ifndef STB_INCLUDE_STB_LIB_H -#define STB_INCLUDE_STB_LIB_H -#undef STB_EXTERN -#endif - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -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 OR COPYRIGHT HOLDERS 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. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -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. ------------------------------------------------------------------------------- -*/ diff --git a/source/engine/thirdparty/stb/tests/resample_test.cpp b/source/engine/thirdparty/stb/tests/resample_test.cpp deleted file mode 100644 index 6595e37..0000000 --- a/source/engine/thirdparty/stb/tests/resample_test.cpp +++ /dev/null @@ -1,1127 +0,0 @@ -#define _CRT_SECURE_NO_WARNINGS -#include -#include - -#if defined(_WIN32) && _MSC_VER > 1200 -#define STBIR_ASSERT(x) \ - if (!(x)) { \ - __debugbreak(); \ - } else -#else -#include -#define STBIR_ASSERT(x) assert(x) -#endif - -#define STBIR_MALLOC stbir_malloc -#define STBIR_FREE stbir_free - -class stbir_context { -public: - stbir_context() - { - size = 1000000; - memory = malloc(size); - } - - ~stbir_context() - { - free(memory); - } - - size_t size; - void* memory; -} g_context; - -void* stbir_malloc(size_t size, void* context) -{ - if (!context) - return malloc(size); - - stbir_context* real_context = (stbir_context*)context; - if (size > real_context->size) - return 0; - - return real_context->memory; -} - -void stbir_free(void* memory, void* context) -{ - if (!context) - free(memory); -} - -//#include -void stbir_progress(float p) -{ - //printf("%f\n", p); - STBIR_ASSERT(p >= 0 && p <= 1); -} - -#ifdef __clang__ -#define STBIRDEF static inline -#endif - -#define STBIR_PROGRESS_REPORT stbir_progress -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#define STB_IMAGE_RESIZE_STATIC -#include "stb_image_resize2.h" - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#ifdef _WIN32 -#include -#include -#define mkdir(a, b) _mkdir(a) -#else -#include -#endif - -#define MT_SIZE 624 -static size_t g_aiMT[MT_SIZE]; -static size_t g_iMTI = 0; - -// Mersenne Twister implementation from Wikipedia. -// Avoiding use of the system rand() to be sure that our tests generate the same test data on any system. -void mtsrand(size_t iSeed) -{ - g_aiMT[0] = iSeed; - for (size_t i = 1; i < MT_SIZE; i++) - { - size_t inner1 = g_aiMT[i - 1]; - size_t inner2 = (g_aiMT[i - 1] >> 30); - size_t inner = inner1 ^ inner2; - g_aiMT[i] = (0x6c078965 * inner) + i; - } - - g_iMTI = 0; -} - -size_t mtrand() -{ - if (g_iMTI == 0) - { - for (size_t i = 0; i < MT_SIZE; i++) - { - size_t y = (0x80000000 & (g_aiMT[i])) + (0x7fffffff & (g_aiMT[(i + 1) % MT_SIZE])); - g_aiMT[i] = g_aiMT[(i + 397) % MT_SIZE] ^ (y >> 1); - if ((y % 2) == 1) - g_aiMT[i] = g_aiMT[i] ^ 0x9908b0df; - } - } - - size_t y = g_aiMT[g_iMTI]; - y = y ^ (y >> 11); - y = y ^ ((y << 7) & (0x9d2c5680)); - y = y ^ ((y << 15) & (0xefc60000)); - y = y ^ (y >> 18); - - g_iMTI = (g_iMTI + 1) % MT_SIZE; - - return y; -} - - -inline float mtfrand() -{ - const int ninenine = 999999; - return (float)(mtrand() % ninenine)/ninenine; -} - -void resizer(int argc, char **argv) -{ - unsigned char* input_pixels; - unsigned char* output_pixels; - int w, h; - int n; - int out_w, out_h; - input_pixels = stbi_load(argv[1], &w, &h, &n, 0); - out_w = w*3; - out_h = h*3; - output_pixels = (unsigned char*) malloc(out_w*out_h*n); - //stbir_resize_uint8_srgb(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, n, -1,0); - stbir_resize_uint8_linear(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, (stbir_pixel_layout) n); - stbi_write_png("output.png", out_w, out_h, n, output_pixels, 0); - exit(0); -} - -void performance(int argc, char **argv) -{ - unsigned char* input_pixels; - unsigned char* output_pixels; - int w, h, count; - int n, i; - int out_w, out_h, srgb=1; - input_pixels = stbi_load(argv[1], &w, &h, &n, 0); - #if 0 - out_w = w/4; out_h = h/4; count=100; // 1 - #elif 0 - out_w = w*2; out_h = h/4; count=20; // 2 // note this is structured pessimily, would be much faster to downsample vertically first - #elif 0 - out_w = w/4; out_h = h*2; count=50; // 3 - #elif 0 - out_w = w*3; out_h = h*3; count=2; srgb=0; // 4 - #else - out_w = w*3; out_h = h*3; count=2; // 5 // this is dominated by linear->sRGB conversion - #endif - - output_pixels = (unsigned char*) malloc(out_w*out_h*n); - for (i=0; i < count; ++i) - if (srgb) - stbir_resize_uint8_srgb(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, (stbir_pixel_layout) n); - else - stbir_resize_uint8_linear(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, (stbir_pixel_layout) n); - exit(0); -} - -void test_suite(int argc, char **argv); - -int main(int argc, char** argv) -{ - //resizer(argc, argv); - //performance(argc, argv); - - test_suite(argc, argv); - return 0; -} - -#if 0 -void resize_image(const char* filename, float width_percent, float height_percent, stbir_filter filter, stbir_edge edge, stbir_colorspace colorspace, const char* output_filename) -{ - int w, h, n; - - unsigned char* input_data = stbi_load(filename, &w, &h, &n, 0); - if (!input_data) - { - printf("Input image could not be loaded\n"); - return; - } - - int out_w = (int)(w * width_percent); - int out_h = (int)(h * height_percent); - - unsigned char* output_data = (unsigned char*)malloc(out_w * out_h * n); - - stbir_resize(input_data, w, h, 0, output_data, out_w, out_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, edge, edge, filter, filter, colorspace, &g_context); - - stbi_image_free(input_data); - - stbi_write_png(output_filename, out_w, out_h, n, output_data, 0); - - free(output_data); -} - -template -void convert_image(const F* input, T* output, int length) -{ - double f = (pow(2.0, 8.0 * sizeof(T)) - 1) / (pow(2.0, 8.0 * sizeof(F)) - 1); - for (int i = 0; i < length; i++) - output[i] = (T)(((double)input[i]) * f); -} - -template -void test_format(const char* file, float width_percent, float height_percent, stbir_datatype type, stbir_colorspace colorspace) -{ - int w, h, n; - unsigned char* input_data = stbi_load(file, &w, &h, &n, 0); - - if (input_data == NULL) - return; - - - int new_w = (int)(w * width_percent); - int new_h = (int)(h * height_percent); - - T* T_data = (T*)malloc(w * h * n * sizeof(T)); - memset(T_data, 0, w*h*n*sizeof(T)); - convert_image(input_data, T_data, w * h * n); - - T* output_data = (T*)malloc(new_w * new_h * n * sizeof(T)); - - stbir_resize(T_data, w, h, 0, output_data, new_w, new_h, 0, type, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, colorspace, &g_context); - - free(T_data); - stbi_image_free(input_data); - - unsigned char* char_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(char)); - convert_image(output_data, char_data, new_w * new_h * n); - - char output[200]; - sprintf(output, "test-output/type-%d-%d-%d-%d-%s", type, colorspace, new_w, new_h, file); - stbi_write_png(output, new_w, new_h, n, char_data, 0); - - free(char_data); - free(output_data); -} - -void convert_image_float(const unsigned char* input, float* output, int length) -{ - for (int i = 0; i < length; i++) - output[i] = ((float)input[i])/255; -} - -void convert_image_float(const float* input, unsigned char* output, int length) -{ - for (int i = 0; i < length; i++) - output[i] = (unsigned char)(stbir__saturate(input[i]) * 255); -} - -void test_float(const char* file, float width_percent, float height_percent, stbir_datatype type, stbir_colorspace colorspace) -{ - int w, h, n; - unsigned char* input_data = stbi_load(file, &w, &h, &n, 0); - - if (input_data == NULL) - return; - - int new_w = (int)(w * width_percent); - int new_h = (int)(h * height_percent); - - float* T_data = (float*)malloc(w * h * n * sizeof(float)); - convert_image_float(input_data, T_data, w * h * n); - - float* output_data = (float*)malloc(new_w * new_h * n * sizeof(float)); - - stbir_resize_float_generic(T_data, w, h, 0, output_data, new_w, new_h, 0, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, colorspace, &g_context); - - free(T_data); - stbi_image_free(input_data); - - unsigned char* char_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(char)); - convert_image_float(output_data, char_data, new_w * new_h * n); - - char output[200]; - sprintf(output, "test-output/type-%d-%d-%d-%d-%s", type, colorspace, new_w, new_h, file); - stbi_write_png(output, new_w, new_h, n, char_data, 0); - - free(char_data); - free(output_data); -} - -void test_channels(const char* file, float width_percent, float height_percent, int channels) -{ - int w, h, n; - unsigned char* input_data = stbi_load(file, &w, &h, &n, 0); - - if (input_data == NULL) - return; - - int new_w = (int)(w * width_percent); - int new_h = (int)(h * height_percent); - - unsigned char* channels_data = (unsigned char*)malloc(w * h * channels * sizeof(unsigned char)); - - for (int i = 0; i < w * h; i++) - { - int input_position = i * n; - int output_position = i * channels; - - for (int c = 0; c < channels; c++) - channels_data[output_position + c] = input_data[input_position + stbir__min(c, n)]; - } - - unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * channels * sizeof(unsigned char)); - - stbir_resize_uint8_srgb(channels_data, w, h, 0, output_data, new_w, new_h, 0, channels, STBIR_ALPHA_CHANNEL_NONE, 0); - - free(channels_data); - stbi_image_free(input_data); - - char output[200]; - sprintf(output, "test-output/channels-%d-%d-%d-%s", channels, new_w, new_h, file); - stbi_write_png(output, new_w, new_h, channels, output_data, 0); - - free(output_data); -} - -void test_subpixel(const char* file, float width_percent, float height_percent, float s1, float t1) -{ - int w, h, n; - unsigned char* input_data = stbi_load(file, &w, &h, &n, 0); - - if (input_data == NULL) - return; - - s1 = ((float)w - 1 + s1)/w; - t1 = ((float)h - 1 + t1)/h; - - int new_w = (int)(w * width_percent); - int new_h = (int)(h * height_percent); - - unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char)); - - stbir_resize_region(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 0, 0, s1, t1); - - stbi_image_free(input_data); - - char output[200]; - sprintf(output, "test-output/subpixel-%d-%d-%f-%f-%s", new_w, new_h, s1, t1, file); - stbi_write_png(output, new_w, new_h, n, output_data, 0); - - free(output_data); -} - -void test_subpixel_region(const char* file, float width_percent, float height_percent, float s0, float t0, float s1, float t1) -{ - int w, h, n; - unsigned char* input_data = stbi_load(file, &w, &h, &n, 0); - - if (input_data == NULL) - return; - - int new_w = (int)(w * width_percent); - int new_h = (int)(h * height_percent); - - unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char)); - - stbir_resize_region(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, s0, t0, s1, t1); - - stbi_image_free(input_data); - - char output[200]; - sprintf(output, "test-output/subpixel-region-%d-%d-%f-%f-%f-%f-%s", new_w, new_h, s0, t0, s1, t1, file); - stbi_write_png(output, new_w, new_h, n, output_data, 0); - - free(output_data); -} - -void test_subpixel_command(const char* file, float width_percent, float height_percent, float x_scale, float y_scale, float x_offset, float y_offset) -{ - int w, h, n; - unsigned char* input_data = stbi_load(file, &w, &h, &n, 0); - - if (input_data == NULL) - return; - - int new_w = (int)(w * width_percent); - int new_h = (int)(h * height_percent); - - unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char)); - - stbir_resize_subpixel(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, x_scale, y_scale, x_offset, y_offset); - - stbi_image_free(input_data); - - char output[200]; - sprintf(output, "test-output/subpixel-command-%d-%d-%f-%f-%f-%f-%s", new_w, new_h, x_scale, y_scale, x_offset, y_offset, file); - stbi_write_png(output, new_w, new_h, n, output_data, 0); - - free(output_data); -} - -unsigned int* pixel(unsigned int* buffer, int x, int y, int c, int w, int n) -{ - return &buffer[y*w*n + x*n + c]; -} - -void test_premul() -{ - unsigned int input[2 * 2 * 4]; - unsigned int output[1 * 1 * 4]; - unsigned int output2[2 * 2 * 4]; - - memset(input, 0, sizeof(input)); - - // First a test to make sure premul is working properly. - - // Top left - solid red - *pixel(input, 0, 0, 0, 2, 4) = 255; - *pixel(input, 0, 0, 3, 2, 4) = 255; - - // Bottom left - solid red - *pixel(input, 0, 1, 0, 2, 4) = 255; - *pixel(input, 0, 1, 3, 2, 4) = 255; - - // Top right - transparent green - *pixel(input, 1, 0, 1, 2, 4) = 255; - *pixel(input, 1, 0, 3, 2, 4) = 25; - - // Bottom right - transparent green - *pixel(input, 1, 1, 1, 2, 4) = 255; - *pixel(input, 1, 1, 3, 2, 4) = 25; - - stbir_resize(input, 2, 2, 0, output, 1, 1, 0, STBIR_TYPE_UINT32, 4, 3, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, &g_context); - - float r = (float)255 / 4294967296; - float g = (float)255 / 4294967296; - float ra = (float)255 / 4294967296; - float ga = (float)25 / 4294967296; - float a = (ra + ga) / 2; - - STBIR_ASSERT(output[0] == (unsigned int)(r * ra / 2 / a * 4294967296 + 0.5f)); // 232 - STBIR_ASSERT(output[1] == (unsigned int)(g * ga / 2 / a * 4294967296 + 0.5f)); // 23 - STBIR_ASSERT(output[2] == 0); - STBIR_ASSERT(output[3] == (unsigned int)(a * 4294967296 + 0.5f)); // 140 - - // Now a test to make sure it doesn't clobber existing values. - - // Top right - completely transparent green - *pixel(input, 1, 0, 1, 2, 4) = 255; - *pixel(input, 1, 0, 3, 2, 4) = 0; - - // Bottom right - completely transparent green - *pixel(input, 1, 1, 1, 2, 4) = 255; - *pixel(input, 1, 1, 3, 2, 4) = 0; - - stbir_resize(input, 2, 2, 0, output2, 2, 2, 0, STBIR_TYPE_UINT32, 4, 3, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, &g_context); - - STBIR_ASSERT(*pixel(output2, 0, 0, 0, 2, 4) == 255); - STBIR_ASSERT(*pixel(output2, 0, 0, 1, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 0, 0, 2, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 0, 0, 3, 2, 4) == 255); - - STBIR_ASSERT(*pixel(output2, 0, 1, 0, 2, 4) == 255); - STBIR_ASSERT(*pixel(output2, 0, 1, 1, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 0, 1, 2, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 0, 1, 3, 2, 4) == 255); - - STBIR_ASSERT(*pixel(output2, 1, 0, 0, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 1, 0, 1, 2, 4) == 255); - STBIR_ASSERT(*pixel(output2, 1, 0, 2, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 1, 0, 3, 2, 4) == 0); - - STBIR_ASSERT(*pixel(output2, 1, 1, 0, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 1, 1, 1, 2, 4) == 255); - STBIR_ASSERT(*pixel(output2, 1, 1, 2, 2, 4) == 0); - STBIR_ASSERT(*pixel(output2, 1, 1, 3, 2, 4) == 0); -} - -// test that splitting a pow-2 image into tiles produces identical results -void test_subpixel_1() -{ - unsigned char image[8 * 8]; - - mtsrand(0); - - for (int i = 0; i < sizeof(image); i++) - image[i] = mtrand() & 255; - - unsigned char output_data[16 * 16]; - - stbir_resize_region(image, 8, 8, 0, output_data, 16, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 0, 0, 1, 1); - - unsigned char output_left[8 * 16]; - unsigned char output_right[8 * 16]; - - stbir_resize_region(image, 8, 8, 0, output_left, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 0, 0, 0.5f, 1); - stbir_resize_region(image, 8, 8, 0, output_right, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 0.5f, 0, 1, 1); - - for (int x = 0; x < 8; x++) - { - for (int y = 0; y < 16; y++) - { - STBIR_ASSERT(output_data[y * 16 + x] == output_left[y * 8 + x]); - STBIR_ASSERT(output_data[y * 16 + x + 8] == output_right[y * 8 + x]); - } - } - - stbir_resize_subpixel(image, 8, 8, 0, output_left, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 0, 0); - stbir_resize_subpixel(image, 8, 8, 0, output_right, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 8, 0); - - {for (int x = 0; x < 8; x++) - { - for (int y = 0; y < 16; y++) - { - STBIR_ASSERT(output_data[y * 16 + x] == output_left[y * 8 + x]); - STBIR_ASSERT(output_data[y * 16 + x + 8] == output_right[y * 8 + x]); - } - }} -} - -// test that replicating an image and using a subtile of it produces same results as wraparound -void test_subpixel_2() -{ - unsigned char image[8 * 8]; - - mtsrand(0); - - for (int i = 0; i < sizeof(image); i++) - image[i] = mtrand() & 255; - - unsigned char large_image[32 * 32]; - - for (int x = 0; x < 8; x++) - { - for (int y = 0; y < 8; y++) - { - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - large_image[j*4*8*8 + i*8 + y*4*8 + x] = image[y*8 + x]; - } - } - } - - unsigned char output_data_1[16 * 16]; - unsigned char output_data_2[16 * 16]; - - stbir_resize(image, 8, 8, 0, output_data_1, 16, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_WRAP, STBIR_EDGE_WRAP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context); - stbir_resize_region(large_image, 32, 32, 0, output_data_2, 16, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_WRAP, STBIR_EDGE_WRAP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 0.25f, 0.25f, 0.5f, 0.5f); - - {for (int x = 0; x < 16; x++) - { - for (int y = 0; y < 16; y++) - STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]); - }} - - stbir_resize_subpixel(large_image, 32, 32, 0, output_data_2, 16, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_WRAP, STBIR_EDGE_WRAP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 16, 16); - - {for (int x = 0; x < 16; x++) - { - for (int y = 0; y < 16; y++) - STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]); - }} -} - -// test that 0,0,1,1 subpixel produces same result as no-rect -void test_subpixel_3() -{ - unsigned char image[8 * 8]; - - mtsrand(0); - - for (int i = 0; i < sizeof(image); i++) - image[i] = mtrand() & 255; - - unsigned char output_data_1[32 * 32]; - unsigned char output_data_2[32 * 32]; - - stbir_resize_region(image, 8, 8, 0, output_data_1, 32, 32, 0, STBIR_TYPE_UINT8, 1, 0, STBIR_ALPHA_CHANNEL_NONE, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_LINEAR, NULL, 0, 0, 1, 1); - stbir_resize_uint8(image, 8, 8, 0, output_data_2, 32, 32, 0, 1); - - for (int x = 0; x < 32; x++) - { - for (int y = 0; y < 32; y++) - STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]); - } - - stbir_resize_subpixel(image, 8, 8, 0, output_data_1, 32, 32, 0, STBIR_TYPE_UINT8, 1, 0, STBIR_ALPHA_CHANNEL_NONE, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_LINEAR, NULL, 4, 4, 0, 0); - - {for (int x = 0; x < 32; x++) - { - for (int y = 0; y < 32; y++) - STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]); - }} -} - -// test that 1:1 resample using s,t=0,0,1,1 with bilinear produces original image -void test_subpixel_4() -{ - unsigned char image[8 * 8]; - - mtsrand(0); - - for (int i = 0; i < sizeof(image); i++) - image[i] = mtrand() & 255; - - unsigned char output[8 * 8]; - - stbir_resize_region(image, 8, 8, 0, output, 8, 8, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, &g_context, 0, 0, 1, 1); - STBIR_ASSERT(memcmp(image, output, 8 * 8) == 0); - - stbir_resize_subpixel(image, 8, 8, 0, output, 8, 8, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, &g_context, 1, 1, 0, 0); - STBIR_ASSERT(memcmp(image, output, 8 * 8) == 0); -} - -static unsigned int image88_int[8][8]; -static unsigned char image88 [8][8]; -static unsigned char output88[8][8]; -static unsigned char output44[4][4]; -static unsigned char output22[2][2]; -static unsigned char output11[1][1]; - -void resample_88(stbir_filter filter) -{ - stbir_resize_uint8_generic(image88[0],8,8,0, output88[0],8,8,0, 1,-1,0, STBIR_EDGE_CLAMP, filter, STBIR_COLORSPACE_LINEAR, NULL); - stbir_resize_uint8_generic(image88[0],8,8,0, output44[0],4,4,0, 1,-1,0, STBIR_EDGE_CLAMP, filter, STBIR_COLORSPACE_LINEAR, NULL); - stbir_resize_uint8_generic(image88[0],8,8,0, output22[0],2,2,0, 1,-1,0, STBIR_EDGE_CLAMP, filter, STBIR_COLORSPACE_LINEAR, NULL); - stbir_resize_uint8_generic(image88[0],8,8,0, output11[0],1,1,0, 1,-1,0, STBIR_EDGE_CLAMP, filter, STBIR_COLORSPACE_LINEAR, NULL); -} - -void verify_box(void) -{ - int i,j,t; - - resample_88(STBIR_FILTER_BOX); - - for (i=0; i < sizeof(image88); ++i) - STBIR_ASSERT(image88[0][i] == output88[0][i]); - - t = 0; - for (j=0; j < 4; ++j) - for (i=0; i < 4; ++i) { - int n = image88[j*2+0][i*2+0] - + image88[j*2+0][i*2+1] - + image88[j*2+1][i*2+0] - + image88[j*2+1][i*2+1]; - STBIR_ASSERT(output44[j][i] == ((n+2)>>2) || output44[j][i] == ((n+1)>>2)); // can't guarantee exact rounding due to numerical precision - t += n; - } - STBIR_ASSERT(output11[0][0] == ((t+32)>>6) || output11[0][0] == ((t+31)>>6)); // can't guarantee exact rounding due to numerical precision -} - -void verify_filter_normalized(stbir_filter filter, int output_size, unsigned int value) -{ - int i, j; - unsigned int output[64]; - - stbir_resize(image88_int[0], 8, 8, 0, output, output_size, output_size, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, filter, filter, STBIR_COLORSPACE_LINEAR, NULL); - - for (j = 0; j < output_size; ++j) - for (i = 0; i < output_size; ++i) - STBIR_ASSERT(value == output[j*output_size + i]); -} - -float round2(float f) -{ - return (float) floor(f+0.5f); // round() isn't C standard pre-C99 -} - -void test_filters(void) -{ - int i,j; - - mtsrand(0); - - for (i=0; i < sizeof(image88); ++i) - image88[0][i] = mtrand() & 255; - verify_box(); - - for (i=0; i < sizeof(image88); ++i) - image88[0][i] = 0; - image88[4][4] = 255; - verify_box(); - - for (j=0; j < 8; ++j) - for (i=0; i < 8; ++i) - image88[j][i] = (j^i)&1 ? 255 : 0; - verify_box(); - - for (j=0; j < 8; ++j) - for (i=0; i < 8; ++i) - image88[j][i] = i&2 ? 255 : 0; - verify_box(); - - int value = 64; - - for (j = 0; j < 8; ++j) - for (i = 0; i < 8; ++i) - image88_int[j][i] = value; - - verify_filter_normalized(STBIR_FILTER_BOX, 8, value); - verify_filter_normalized(STBIR_FILTER_TRIANGLE, 8, value); - verify_filter_normalized(STBIR_FILTER_CUBICBSPLINE, 8, value); - verify_filter_normalized(STBIR_FILTER_CATMULLROM, 8, value); - verify_filter_normalized(STBIR_FILTER_MITCHELL, 8, value); - - verify_filter_normalized(STBIR_FILTER_BOX, 4, value); - verify_filter_normalized(STBIR_FILTER_TRIANGLE, 4, value); - verify_filter_normalized(STBIR_FILTER_CUBICBSPLINE, 4, value); - verify_filter_normalized(STBIR_FILTER_CATMULLROM, 4, value); - verify_filter_normalized(STBIR_FILTER_MITCHELL, 4, value); - - verify_filter_normalized(STBIR_FILTER_BOX, 2, value); - verify_filter_normalized(STBIR_FILTER_TRIANGLE, 2, value); - verify_filter_normalized(STBIR_FILTER_CUBICBSPLINE, 2, value); - verify_filter_normalized(STBIR_FILTER_CATMULLROM, 2, value); - verify_filter_normalized(STBIR_FILTER_MITCHELL, 2, value); - - verify_filter_normalized(STBIR_FILTER_BOX, 1, value); - verify_filter_normalized(STBIR_FILTER_TRIANGLE, 1, value); - verify_filter_normalized(STBIR_FILTER_CUBICBSPLINE, 1, value); - verify_filter_normalized(STBIR_FILTER_CATMULLROM, 1, value); - verify_filter_normalized(STBIR_FILTER_MITCHELL, 1, value); - - { - // This test is designed to produce coefficients that are very badly denormalized. - unsigned int v = 556; - - unsigned int input[100 * 100]; - unsigned int output[11 * 11]; - - for (j = 0; j < 100 * 100; ++j) - input[j] = v; - - stbir_resize(input, 100, 100, 0, output, 11, 11, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, NULL); - - for (j = 0; j < 11 * 11; ++j) - STBIR_ASSERT(v == output[j]); - } - - { - // Now test the trapezoid filter for downsampling. - unsigned int input[3 * 1]; - unsigned int output[2 * 1]; - - input[0] = 0; - input[1] = 255; - input[2] = 127; - - stbir_resize(input, 3, 1, 0, output, 2, 1, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL); - - STBIR_ASSERT(output[0] == (unsigned int)round2((float)(input[0] * 2 + input[1]) / 3)); - STBIR_ASSERT(output[1] == (unsigned int)round2((float)(input[2] * 2 + input[1]) / 3)); - - stbir_resize(input, 1, 3, 0, output, 1, 2, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL); - - STBIR_ASSERT(output[0] == (unsigned int)round2((float)(input[0] * 2 + input[1]) / 3)); - STBIR_ASSERT(output[1] == (unsigned int)round2((float)(input[2] * 2 + input[1]) / 3)); - } - - { - // Now test the trapezoid filter for upsampling. - unsigned int input[2 * 1]; - unsigned int output[3 * 1]; - - input[0] = 0; - input[1] = 255; - - stbir_resize(input, 2, 1, 0, output, 3, 1, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL); - - STBIR_ASSERT(output[0] == input[0]); - STBIR_ASSERT(output[1] == (input[0] + input[1]) / 2); - STBIR_ASSERT(output[2] == input[1]); - - stbir_resize(input, 1, 2, 0, output, 1, 3, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL); - - STBIR_ASSERT(output[0] == input[0]); - STBIR_ASSERT(output[1] == (input[0] + input[1]) / 2); - STBIR_ASSERT(output[2] == input[1]); - } - - // checkerboard - { - unsigned char input[64][64]; - unsigned char output[16][16]; - int i,j; - for (j=0; j < 64; ++j) - for (i=0; i < 64; ++i) - input[j][i] = (i^j)&1 ? 255 : 0; - stbir_resize_uint8_generic(input[0], 64, 64, 0, output[0],16,16,0, 1,-1,0,STBIR_EDGE_WRAP,STBIR_FILTER_DEFAULT,STBIR_COLORSPACE_LINEAR,0); - for (j=0; j < 16; ++j) - for (i=0; i < 16; ++i) - STBIR_ASSERT(output[j][i] == 128); - stbir_resize_uint8_srgb_edgemode(input[0], 64, 64, 0, output[0],16,16,0, 1,-1,0,STBIR_EDGE_WRAP); - for (j=0; j < 16; ++j) - for (i=0; i < 16; ++i) - STBIR_ASSERT(output[j][i] == 188); - - - } - - { - // Test trapezoid box filter - unsigned char input[2 * 1]; - unsigned char output[127 * 1]; - - input[0] = 0; - input[1] = 255; - - stbir_resize(input, 2, 1, 0, output, 127, 1, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL); - STBIR_ASSERT(output[0] == 0); - STBIR_ASSERT(output[127 / 2 - 1] == 0); - STBIR_ASSERT(output[127 / 2] == 128); - STBIR_ASSERT(output[127 / 2 + 1] == 255); - STBIR_ASSERT(output[126] == 255); - stbi_write_png("test-output/trapezoid-upsample-horizontal.png", 127, 1, 1, output, 0); - - stbir_resize(input, 1, 2, 0, output, 1, 127, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL); - STBIR_ASSERT(output[0] == 0); - STBIR_ASSERT(output[127 / 2 - 1] == 0); - STBIR_ASSERT(output[127 / 2] == 128); - STBIR_ASSERT(output[127 / 2 + 1] == 255); - STBIR_ASSERT(output[126] == 255); - stbi_write_png("test-output/trapezoid-upsample-vertical.png", 1, 127, 1, output, 0); - } -} - -#define UMAX32 4294967295U - -static void write32(const char *filename, stbir_uint32 *output, int w, int h) -{ - stbir_uint8 *data = (stbir_uint8*) malloc(w*h*3); - for (int i=0; i < w*h*3; ++i) - data[i] = output[i]>>24; - stbi_write_png(filename, w, h, 3, data, 0); - free(data); -} - -static void test_32(void) -{ - int w=100,h=120,x,y, out_w,out_h; - stbir_uint32 *input = (stbir_uint32*) malloc(4 * 3 * w * h); - stbir_uint32 *output = (stbir_uint32*) malloc(4 * 3 * 3*w * 3*h); - for (y=0; y < h; ++y) { - for (x=0; x < w; ++x) { - input[y*3*w + x*3 + 0] = x * ( UMAX32/w ); - input[y*3*w + x*3 + 1] = y * ( UMAX32/h ); - input[y*3*w + x*3 + 2] = UMAX32/2; - } - } - out_w = w*33/16; - out_h = h*33/16; - stbir_resize(input,w,h,0,output,out_w,out_h,0,STBIR_TYPE_UINT32,3,-1,0,STBIR_EDGE_CLAMP,STBIR_EDGE_CLAMP,STBIR_FILTER_DEFAULT,STBIR_FILTER_DEFAULT,STBIR_COLORSPACE_LINEAR,NULL); - write32("test-output/seantest_1.png", output,out_w,out_h); - - out_w = w*16/33; - out_h = h*16/33; - stbir_resize(input,w,h,0,output,out_w,out_h,0,STBIR_TYPE_UINT32,3,-1,0,STBIR_EDGE_CLAMP,STBIR_EDGE_CLAMP,STBIR_FILTER_DEFAULT,STBIR_FILTER_DEFAULT,STBIR_COLORSPACE_LINEAR,NULL); - write32("test-output/seantest_2.png", output,out_w,out_h); -} - - -void test_suite(int argc, char **argv) -{ - int i; - const char *barbara; - - mkdir("test-output", 777); - - if (argc > 1) - barbara = argv[1]; - else - barbara = "barbara.png"; - - // check what cases we need normalization for -#if 1 - { - float x, y; - for (x = -1; x < 1; x += 0.05f) { - float sums[5] = { 0 }; - float o; - for (o = -5; o <= 5; ++o) { - sums[0] += stbir__filter_mitchell(x + o, 1); - sums[1] += stbir__filter_catmullrom(x + o, 1); - sums[2] += stbir__filter_cubic(x + o, 1); - sums[3] += stbir__filter_triangle(x + o, 1); - sums[4] += stbir__filter_trapezoid(x + o, 0.5f); - } - for (i = 0; i < 5; ++i) - STBIR_ASSERT(sums[i] >= 1.0 - 0.001 && sums[i] <= 1.0 + 0.001); - } - -#if 1 - for (y = 0.11f; y < 1; y += 0.01f) { // Step - for (x = -1; x < 1; x += 0.05f) { // Phase - float sums[5] = { 0 }; - float o; - for (o = -5; o <= 5; o += y) { - sums[0] += y * stbir__filter_mitchell(x + o, 1); - sums[1] += y * stbir__filter_catmullrom(x + o, 1); - sums[2] += y * stbir__filter_cubic(x + o, 1); - sums[4] += y * stbir__filter_trapezoid(x + o, 0.5f); - sums[3] += y * stbir__filter_triangle(x + o, 1); - } - for (i = 0; i < 3; ++i) - STBIR_ASSERT(sums[i] >= 1.0 - 0.0170 && sums[i] <= 1.0 + 0.0170); - } - } -#endif - } -#endif - -#if 0 // linear_to_srgb_uchar table - for (i=0; i < 256; ++i) { - float f = stbir__srgb_to_linear((i-0.5f)/255.0f); - printf("%9d, ", (int) ((f) * (1<<28))); - if ((i & 7) == 7) - printf("\n"); - } -#endif - - // old tests that hacky fix worked on - test that - // every uint8 maps to itself - for (i = 0; i < 256; i++) { - float f = stbir__srgb_to_linear(float(i) / 255); - int n = stbir__linear_to_srgb_uchar(f); - STBIR_ASSERT(n == i); - } - - // new tests that hacky fix failed for - test that - // values adjacent to uint8 round to nearest uint8 - for (i = 0; i < 256; i++) { - for (float y = -0.42f; y <= 0.42f; y += 0.01f) { - float f = stbir__srgb_to_linear((i+y) / 255.0f); - int n = stbir__linear_to_srgb_uchar(f); - STBIR_ASSERT(n == i); - } - } - - test_filters(); - - test_subpixel_1(); - test_subpixel_2(); - test_subpixel_3(); - test_subpixel_4(); - - test_premul(); - - test_32(); - - // Some tests to make sure errors don't pop up with strange filter/dimension combinations. - stbir_resize(image88, 8, 8, 0, output88, 4, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context); - stbir_resize(image88, 8, 8, 0, output88, 4, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_BOX, STBIR_COLORSPACE_SRGB, &g_context); - stbir_resize(image88, 8, 8, 0, output88, 16, 4, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context); - stbir_resize(image88, 8, 8, 0, output88, 16, 4, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_BOX, STBIR_COLORSPACE_SRGB, &g_context); - - int barbara_width, barbara_height, barbara_channels; - stbi_image_free(stbi_load(barbara, &barbara_width, &barbara_height, &barbara_channels, 0)); - - int res = 10; - // Downscaling - {for (int i = 0; i <= res; i++) - { - float t = (float)i/res; - float scale = 0.5; - float out_scale = 2.0f/3; - float x_shift = (barbara_width*out_scale - barbara_width*scale) * t; - float y_shift = (barbara_height*out_scale - barbara_height*scale) * t; - - test_subpixel_command(barbara, scale, scale, out_scale, out_scale, x_shift, y_shift); - }} - - // Upscaling - {for (int i = 0; i <= res; i++) - { - float t = (float)i/res; - float scale = 2; - float out_scale = 3; - float x_shift = (barbara_width*out_scale - barbara_width*scale) * t; - float y_shift = (barbara_height*out_scale - barbara_height*scale) * t; - - test_subpixel_command(barbara, scale, scale, out_scale, out_scale, x_shift, y_shift); - }} - - // Downscaling - {for (int i = 0; i <= res; i++) - { - float t = (float)i/res / 2; - test_subpixel_region(barbara, 0.25f, 0.25f, t, t, t+0.5f, t+0.5f); - }} - - // No scaling - {for (int i = 0; i <= res; i++) - { - float t = (float)i/res / 2; - test_subpixel_region(barbara, 0.5f, 0.5f, t, t, t+0.5f, t+0.5f); - }} - - // Upscaling - {for (int i = 0; i <= res; i++) - { - float t = (float)i/res / 2; - test_subpixel_region(barbara, 1, 1, t, t, t+0.5f, t+0.5f); - }} - - {for (i = 0; i < 10; i++) - test_subpixel(barbara, 0.5f, 0.5f, (float)i / 10, 1); - } - - {for (i = 0; i < 10; i++) - test_subpixel(barbara, 0.5f, 0.5f, 1, (float)i / 10); - } - - {for (i = 0; i < 10; i++) - test_subpixel(barbara, 2, 2, (float)i / 10, 1); - } - - {for (i = 0; i < 10; i++) - test_subpixel(barbara, 2, 2, 1, (float)i / 10); - } - - // Channels test - test_channels(barbara, 0.5f, 0.5f, 1); - test_channels(barbara, 0.5f, 0.5f, 2); - test_channels(barbara, 0.5f, 0.5f, 3); - test_channels(barbara, 0.5f, 0.5f, 4); - - test_channels(barbara, 2, 2, 1); - test_channels(barbara, 2, 2, 2); - test_channels(barbara, 2, 2, 3); - test_channels(barbara, 2, 2, 4); - - // filter tests - resize_image(barbara, 2, 2, STBIR_FILTER_BOX , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-upsample-nearest.png"); - resize_image(barbara, 2, 2, STBIR_FILTER_TRIANGLE , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-upsample-bilinear.png"); - resize_image(barbara, 2, 2, STBIR_FILTER_CUBICBSPLINE, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-upsample-bicubic.png"); - resize_image(barbara, 2, 2, STBIR_FILTER_CATMULLROM , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-upsample-catmullrom.png"); - resize_image(barbara, 2, 2, STBIR_FILTER_MITCHELL , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-upsample-mitchell.png"); - - resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_BOX , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-nearest.png"); - resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_TRIANGLE , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-bilinear.png"); - resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_CUBICBSPLINE, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-bicubic.png"); - resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_CATMULLROM , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-catmullrom.png"); - resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_MITCHELL , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-mitchell.png"); - - {for (i = 10; i < 100; i++) - { - char outname[200]; - sprintf(outname, "test-output/barbara-width-%d.jpg", i); - resize_image(barbara, (float)i / 100, 1, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname); - }} - - {for (i = 110; i < 500; i += 10) - { - char outname[200]; - sprintf(outname, "test-output/barbara-width-%d.jpg", i); - resize_image(barbara, (float)i / 100, 1, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname); - }} - - {for (i = 10; i < 100; i++) - { - char outname[200]; - sprintf(outname, "test-output/barbara-height-%d.jpg", i); - resize_image(barbara, 1, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname); - }} - - {for (i = 110; i < 500; i += 10) - { - char outname[200]; - sprintf(outname, "test-output/barbara-height-%d.jpg", i); - resize_image(barbara, 1, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname); - }} - - {for (i = 50; i < 200; i += 10) - { - char outname[200]; - sprintf(outname, "test-output/barbara-width-height-%d.jpg", i); - resize_image(barbara, 100 / (float)i, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname); - }} - - test_format(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB); - test_format(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR); - test_format(barbara, 2.0, 0.5, STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB); - test_format(barbara, 2.0, 0.5, STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR); - - test_format(barbara, 0.5, 2.0, STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB); - test_format(barbara, 0.5, 2.0, STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR); - test_format(barbara, 2.0, 0.5, STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB); - test_format(barbara, 2.0, 0.5, STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR); - - test_float(barbara, 0.5, 2.0, STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB); - test_float(barbara, 0.5, 2.0, STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR); - test_float(barbara, 2.0, 0.5, STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB); - test_float(barbara, 2.0, 0.5, STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR); - - // Edge behavior tests - resize_image("hgradient.png", 2, 2, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR, "test-output/hgradient-clamp.png"); - resize_image("hgradient.png", 2, 2, STBIR_FILTER_CATMULLROM, STBIR_EDGE_WRAP, STBIR_COLORSPACE_LINEAR, "test-output/hgradient-wrap.png"); - - resize_image("vgradient.png", 2, 2, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR, "test-output/vgradient-clamp.png"); - resize_image("vgradient.png", 2, 2, STBIR_FILTER_CATMULLROM, STBIR_EDGE_WRAP, STBIR_COLORSPACE_LINEAR, "test-output/vgradient-wrap.png"); - - resize_image("1px-border.png", 2, 2, STBIR_FILTER_CATMULLROM, STBIR_EDGE_REFLECT, STBIR_COLORSPACE_LINEAR, "test-output/1px-border-reflect.png"); - resize_image("1px-border.png", 2, 2, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR, "test-output/1px-border-clamp.png"); - - // sRGB tests - resize_image("gamma_colors.jpg", .5f, .5f, STBIR_FILTER_CATMULLROM, STBIR_EDGE_REFLECT, STBIR_COLORSPACE_SRGB, "test-output/gamma_colors.jpg"); - resize_image("gamma_2.2.jpg", .5f, .5f, STBIR_FILTER_CATMULLROM, STBIR_EDGE_REFLECT, STBIR_COLORSPACE_SRGB, "test-output/gamma_2.2.jpg"); - resize_image("gamma_dalai_lama_gray.jpg", .5f, .5f, STBIR_FILTER_CATMULLROM, STBIR_EDGE_REFLECT, STBIR_COLORSPACE_SRGB, "test-output/gamma_dalai_lama_gray.jpg"); -} -#endif -void test_suite(int argc, char **argv) -{ -} diff --git a/source/engine/thirdparty/stb/tests/resample_test_c.c b/source/engine/thirdparty/stb/tests/resample_test_c.c deleted file mode 100644 index e7e3531..0000000 --- a/source/engine/thirdparty/stb/tests/resample_test_c.c +++ /dev/null @@ -1,8 +0,0 @@ -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#define STB_IMAGE_RESIZE_STATIC -#include "stb_image_resize.h" - -// Just to make sure it will build properly with a c compiler - -int main() { -} diff --git a/source/engine/thirdparty/stb/tests/resize.dsp b/source/engine/thirdparty/stb/tests/resize.dsp deleted file mode 100644 index cfb9608..0000000 --- a/source/engine/thirdparty/stb/tests/resize.dsp +++ /dev/null @@ -1,94 +0,0 @@ -# Microsoft Developer Studio Project File - Name="resize" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=resize - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "resize.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "resize.mak" CFG="resize - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "resize - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "resize - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "resize - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /W3 /GX /Z7 /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 - -!ELSEIF "$(CFG)" == "resize - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "resize - Win32 Release" -# Name "resize - Win32 Debug" -# Begin Source File - -SOURCE=.\resample_test.cpp -# End Source File -# Begin Source File - -SOURCE=..\stb_image_resize2.h -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/sdf/sdf_test.c b/source/engine/thirdparty/stb/tests/sdf/sdf_test.c deleted file mode 100644 index d5b0ca0..0000000 --- a/source/engine/thirdparty/stb/tests/sdf/sdf_test.c +++ /dev/null @@ -1,152 +0,0 @@ -#define STB_DEFINE -#include "stb.h" - -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -// used both to compute SDF and in 'shader' -float sdf_size = 32.0; // the larger this is, the better large font sizes look -float pixel_dist_scale = 64.0; // trades off precision w/ ability to handle *smaller* sizes -int onedge_value = 128; -int padding = 3; // not used in shader - -typedef struct -{ - float advance; - signed char xoff; - signed char yoff; - unsigned char w,h; - unsigned char *data; -} fontchar; - -fontchar fdata[128]; - -#define BITMAP_W 1200 -#define BITMAP_H 800 -unsigned char bitmap[BITMAP_H][BITMAP_W][3]; - -char *sample = "This is goofy text, size %d!"; -char *small_sample = "This is goofy text, size %d! Really needs in-shader supersampling to look good."; - -void blend_pixel(int x, int y, int color, float alpha) -{ - int i; - for (i=0; i < 3; ++i) - bitmap[y][x][i] = (unsigned char) (stb_lerp(alpha, bitmap[y][x][i], color)+0.5); // round -} - -void draw_char(float px, float py, char c, float relative_scale) -{ - int x,y; - fontchar *fc = &fdata[c]; - float fx0 = px + fc->xoff*relative_scale; - float fy0 = py + fc->yoff*relative_scale; - float fx1 = fx0 + fc->w*relative_scale; - float fy1 = fy0 + fc->h*relative_scale; - int ix0 = (int) floor(fx0); - int iy0 = (int) floor(fy0); - int ix1 = (int) ceil(fx1); - int iy1 = (int) ceil(fy1); - // clamp to viewport - if (ix0 < 0) ix0 = 0; - if (iy0 < 0) iy0 = 0; - if (ix1 > BITMAP_W) ix1 = BITMAP_W; - if (iy1 > BITMAP_H) iy1 = BITMAP_H; - - for (y=iy0; y < iy1; ++y) { - for (x=ix0; x < ix1; ++x) { - float sdf_dist, pix_dist; - float bmx = stb_linear_remap(x, fx0, fx1, 0, fc->w); - float bmy = stb_linear_remap(y, fy0, fy1, 0, fc->h); - int v00,v01,v10,v11; - float v0,v1,v; - int sx0 = (int) bmx; - int sx1 = sx0+1; - int sy0 = (int) bmy; - int sy1 = sy0+1; - // compute lerp weights - bmx = bmx - sx0; - bmy = bmy - sy0; - // clamp to edge - sx0 = stb_clamp(sx0, 0, fc->w-1); - sx1 = stb_clamp(sx1, 0, fc->w-1); - sy0 = stb_clamp(sy0, 0, fc->h-1); - sy1 = stb_clamp(sy1, 0, fc->h-1); - // bilinear texture sample - v00 = fc->data[sy0*fc->w+sx0]; - v01 = fc->data[sy0*fc->w+sx1]; - v10 = fc->data[sy1*fc->w+sx0]; - v11 = fc->data[sy1*fc->w+sx1]; - v0 = stb_lerp(bmx,v00,v01); - v1 = stb_lerp(bmx,v10,v11); - v = stb_lerp(bmy,v0 ,v1 ); - #if 0 - // non-anti-aliased - if (v > onedge_value) - blend_pixel(x,y,0,1.0); - #else - // Following math can be greatly simplified - - // convert distance in SDF value to distance in SDF bitmap - sdf_dist = stb_linear_remap(v, onedge_value, onedge_value+pixel_dist_scale, 0, 1); - // convert distance in SDF bitmap to distance in output bitmap - pix_dist = sdf_dist * relative_scale; - // anti-alias by mapping 1/2 pixel around contour from 0..1 alpha - v = stb_linear_remap(pix_dist, -0.5f, 0.5f, 0, 1); - if (v > 1) v = 1; - if (v > 0) - blend_pixel(x,y,0,v); - #endif - } - } -} - - -void print_text(float x, float y, char *text, float scale) -{ - int i; - for (i=0; text[i]; ++i) { - if (fdata[text[i]].data) - draw_char(x,y,text[i],scale); - x += fdata[text[i]].advance * scale; - } -} - -int main(int argc, char **argv) -{ - int ch; - float scale, ypos; - stbtt_fontinfo font; - void *data = stb_file("c:/windows/fonts/times.ttf", NULL); - stbtt_InitFont(&font, data, 0); - - scale = stbtt_ScaleForPixelHeight(&font, sdf_size); - - for (ch=32; ch < 127; ++ch) { - fontchar fc; - int xoff,yoff,w,h, advance; - fc.data = stbtt_GetCodepointSDF(&font, scale, ch, padding, onedge_value, pixel_dist_scale, &w, &h, &xoff, &yoff); - fc.xoff = xoff; - fc.yoff = yoff; - fc.w = w; - fc.h = h; - stbtt_GetCodepointHMetrics(&font, ch, &advance, NULL); - fc.advance = advance * scale; - fdata[ch] = fc; - } - - ypos = 60; - memset(bitmap, 255, sizeof(bitmap)); - print_text(400, ypos+30, stb_sprintf("sdf bitmap height %d", (int) sdf_size), 30/sdf_size); - ypos += 80; - for (scale = 8.0; scale < 120.0; scale *= 1.33f) { - print_text(80, ypos+scale, stb_sprintf(scale == 8.0 ? small_sample : sample, (int) scale), scale / sdf_size); - ypos += scale*1.05f + 20; - } - - stbi_write_png("sdf_test.png", BITMAP_W, BITMAP_H, 3, bitmap, 0); - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/sdf/sdf_test_arial_16.png b/source/engine/thirdparty/stb/tests/sdf/sdf_test_arial_16.png deleted file mode 100644 index 3d2bc1e..0000000 Binary files a/source/engine/thirdparty/stb/tests/sdf/sdf_test_arial_16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/sdf/sdf_test_times_16.png b/source/engine/thirdparty/stb/tests/sdf/sdf_test_times_16.png deleted file mode 100644 index c76e7b9..0000000 Binary files a/source/engine/thirdparty/stb/tests/sdf/sdf_test_times_16.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/sdf/sdf_test_times_50.png b/source/engine/thirdparty/stb/tests/sdf/sdf_test_times_50.png deleted file mode 100644 index bf4974f..0000000 Binary files a/source/engine/thirdparty/stb/tests/sdf/sdf_test_times_50.png and /dev/null differ diff --git a/source/engine/thirdparty/stb/tests/stb.c b/source/engine/thirdparty/stb/tests/stb.c deleted file mode 100644 index ee6941f..0000000 --- a/source/engine/thirdparty/stb/tests/stb.c +++ /dev/null @@ -1,3330 +0,0 @@ -/* - * Unit tests for "stb.h" - */ - -#define _CRT_SECURE_NO_WARNINGS -//#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -//#define STB_FASTMALLOC -#ifdef _DEBUG -#define STB_MALLOC_WRAPPER_DEBUG -#endif -#ifndef _M_AMD64 -#define STB_NPTR -#endif -#define STB_DEFINE -#include "stb.h" - -//#include "stb_file.h" -//#include "stb_pixel32.h" - -//#define DEBUG_BLOCK -#ifdef DEBUG_BLOCK -#include -#endif - -#ifdef STB_FASTMALLOC -#error "can't use FASTMALLOC with threads" -#endif - -int count; -void c(int truth, char *error) -{ - if (!truth) { - fprintf(stderr, "Test failed: %s\n", error); - ++count; - } -} - - -#if 0 -void show(void) -{ - #ifdef _WIN32 - SYSTEM_INFO x; - GetSystemInfo(&x); - printf("%d\n", x.dwPageSize); - #endif -} -#endif - -void test_classes(void) -{ - unsigned char size_base[32], size_shift[32]; - int class_to_pages[256]; - int class_to_size[256], cl; - int lg, size, wasted_pages; - int kAlignShift = 3; - int kAlignment = 1 << kAlignShift; - int kMaxSize = 8 * 4096; - int kPageShift = 12; - int kPageSize = (1 << kPageShift); - int next_class = 1; - int alignshift = kAlignShift; - int last_lg = -1; - - for (lg = 0; lg < kAlignShift; lg++) { - size_base[lg] = 1; - size_shift[lg] = kAlignShift; - } - - for (size = kAlignment; size <= kMaxSize; size += (1 << alignshift)) { - int lg = stb_log2_floor(size); - if (lg > last_lg) { - // Increase alignment every so often. - // - // Since we double the alignment every time size doubles and - // size >= 128, this means that space wasted due to alignment is - // at most 16/128 i.e., 12.5%. Plus we cap the alignment at 256 - // bytes, so the space wasted as a percentage starts falling for - // sizes > 2K. - if ((lg >= 7) && (alignshift < 8)) { - alignshift++; - } - size_base[lg] = next_class - ((size-1) >> alignshift); - size_shift[lg] = alignshift; - } - - class_to_size[next_class] = size; - last_lg = lg; - - next_class++; - } - - // Initialize the number of pages we should allocate to split into - // small objects for a given class. - wasted_pages = 0; - for (cl = 1; cl < next_class; cl++) { - // Allocate enough pages so leftover is less than 1/8 of total. - // This bounds wasted space to at most 12.5%. - size_t psize = kPageSize; - const size_t s = class_to_size[cl]; - while ((psize % s) > (psize >> 3)) { - psize += kPageSize; - } - class_to_pages[cl] = (int) (psize >> kPageShift); - wasted_pages += (int) psize; - } - - printf("TCMalloc can waste as much as %d memory on one-shot allocations\n", wasted_pages); - - - return; -} - -#ifdef STB_STUA -void test_script(void) -{ - stua_run_script( - "var g = (2+3)*5 + 3*(2+1) + ((7)); \n" - "func sprint(x) _print(x) _print(' ') x end;\n" - "func foo(y) var q = func(x) sprint(x) end; q end;\n " - "var z=foo(5); z(77);\n" - "func counter(z) func(x) z=z+1 end end\n" - "var q=counter(0), p=counter(5);\n" - "sprint(q()) sprint(p()) sprint(q()) sprint(p()) sprint(q()) sprint(p())\n" - "var x=2222;\n" - "if 1 == 2 then 3333 else 4444 end; => x; sprint(x);\n" - "var x1 = sprint(1.5e3); \n" - "var x2 = sprint(.5); \n" - "var x3 = sprint(1.); \n" - "var x4 = sprint(1.e3); \n" - "var x5 = sprint(1e3); \n" - "var x6 = sprint(0.5e3); \n" - "var x7 = sprint(.5e3); \n" - " func sum(x,y) x+y end \n" - " func sumfunc(a) sum+{x=a} end \n" - " var q = sumfunc(3) \n" - " var p = sumfunc(20) \n" - " var d = sprint(q(5)) - sprint(q(8)) \n" - " var e = sprint(p(5)) - sprint(p(8)) \n" - " func test3(x) \n" - " sprint(x) \n" - " x = x+3 \n" - " sprint(x) \n" - " x+5 \n" - " end \n" - " var y = test3(4); \n" - " func fib(x) \n" - " if x < 3 then \n" - " 1 \n" - " else \n" - " fib(x-1) + fib(x-2); \n" - " end \n" - " end \n" - " \n" - " func fib2(x) \n" - " var a=1 \n" - " var b=1 \n" - " sprint(a) \n" - " sprint(b) \n" - " while x > 2 do \n" - " var c=a+b \n" - " a=b \n" - " b=c \n" - " sprint(b) \n" - " x=x-1 \n" - " end \n" - " b \n" - " end \n" - " \n" - " func assign(z) \n" - " var y = { 'this', 'is', 'a', 'lame', 'day', 'to', 'die'} \n" - " y[3] = z \n" - " var i = 0 \n" - " while y[i] != nil do \n" - " sprint(y[i]) \n" - " i = i+1 \n" - " end \n" - " end \n" - " \n" - " sprint(fib(12)); \n" - " assign(\"good\"); \n" - " fib2(20); \n" - " sprint('ok'); \n" - " sprint(-5); \n" - " // final comment with no newline" - ); -} -#endif - -#ifdef STB_THREADS -extern void __stdcall Sleep(unsigned long); - -void * thread_1(void *x) -{ - Sleep(80); - printf("thread 1\n"); fflush(stdout); - return (void *) 2; -} - -void * thread_2(void *y) -{ - stb_work(thread_1, NULL, y); - Sleep(50); - printf("thread 2\n"); fflush(stdout); - return (void *) 3; -} - -stb_semaphore stest; -stb_mutex mutex; -volatile int tc1, tc2; - -void *thread_3(void *p) -{ - stb_mutex_begin(mutex); - ++tc1; - stb_mutex_end(mutex); - stb_sem_waitfor(stest); - stb_mutex_begin(mutex); - ++tc2; - stb_mutex_end(mutex); - return NULL; -} - -void test_threads(void) -{ - volatile int a=0,b=0; - //stb_work_numthreads(2); - stb_work(thread_2, (void *) &a, (void *) &b); - while (a==0 || b==0) { - Sleep(10); - //printf("a=%d b=%d\n", a, b); - } - c(a==2 && b == 3, "stb_thread"); - stb_work_numthreads(4); - stest = stb_sem_new(8); - mutex = stb_mutex_new(); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - while (tc1 < 4) - Sleep(10); - c(tc1 == 4, "stb_work 1"); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - Sleep(40); - while (tc1 != 8 || tc2 != 8) - Sleep(10); - c(tc1 == 8 && tc2 == 8, "stb_work 2"); - stb_work_numthreads(2); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - stb_work(thread_3, NULL, NULL); - while (tc1 < 10) - Sleep(10); - c(tc1 == 10, "stb_work 1"); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - stb_sem_release(stest); - - Sleep(100); - stb_sem_delete(stest); - stb_mutex_delete(mutex); -} -#else -void test_threads(void) -{ -} -#endif - -void *thread4(void *p) -{ - return NULL; -} - -#ifdef STB_THREADS -stb_threadqueue *tq; -stb_sync synch; -stb_mutex msum; - -volatile int thread_sum; - -void *consume1(void *p) -{ - volatile int *q = (volatile int *) p; - for(;;) { - int z; - stb_threadq_get_block(tq, &z); - stb_mutex_begin(msum); - thread_sum += z; - *q += z; - stb_mutex_end(msum); - stb_sync_reach(synch); - } -} - -void test_threads2(void) -{ - int array[256],i,n=0; - volatile int which[4]; - synch = stb_sync_new(); - stb_sync_set_target(synch,2); - stb_work_reach(thread4, NULL, NULL, synch); - stb_sync_reach_and_wait(synch); - printf("ok\n"); - - tq = stb_threadq_new(4, 1, TRUE,TRUE); - msum = stb_mutex_new(); - thread_sum = 0; - stb_sync_set_target(synch, 65); - for (i=0; i < 4; ++i) { - which[i] = 0; - stb_create_thread(consume1, (int *) &which[i]); - } - for (i=1; i <= 64; ++i) { - array[i] = i; - n += i; - stb_threadq_add_block(tq, &array[i]); - } - stb_sync_reach_and_wait(synch); - stb_barrier(); - c(thread_sum == n, "stb_threadq 1"); - c(which[0] + which[1] + which[2] + which[3] == n, "stb_threadq 2"); - printf("(Distribution: %d %d %d %d)\n", which[0], which[1], which[2], which[3]); - - stb_sync_delete(synch); - stb_threadq_delete(tq); - stb_mutex_delete(msum); -} -#else -void test_threads2(void) -{ -} -#endif - -char tc[] = "testing compression test quick test voila woohoo what the hell"; - -unsigned char storage1[1 << 23]; -int test_compression(unsigned char *buffer, int length) -{ - unsigned char *storage2; - int c_len = stb_compress(storage1, buffer, length); - int dc_len; - printf("Compressed %d to %d\n", length, c_len); - dc_len = stb_decompress_length(storage1); - storage2 = malloc(dc_len); - dc_len = stb_decompress(storage2, storage1, c_len); - if (dc_len != length) { free(storage2); return -1; } - if (memcmp(buffer, storage2, length) != 0) { free(storage2); return -1; } - free(storage2); - return c_len; -} - -#if 0 -int test_en_compression(char *buffer, int length) -{ - int c_len = stb_en_compress(storage1, buffer, length); - int dc_len; - printf("Encompressed %d to %d\n", length, c_len); - dc_len = stb_en_decompress(storage2, storage1, c_len); - if (dc_len != length) return -1; - if (memcmp(buffer, storage2, length) != 0) return -1; - return c_len; -} -#endif - -#define STR_x "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -#define STR_y "yyyyyyyyyyyyyyyyyy" - -#define STR_xy STR_x STR_y -#define STR_xyyxy STR_xy STR_y STR_xy - -#define STR_1 "testing" -#define STR_2 STR_xyyxy STR_xy STR_xyyxy STR_xyyxy STR_xy STR_xyyxy -#define STR_3 "buh" - -char buffer[] = STR_1 "\r\n" STR_2 STR_2 STR_2 "\n" STR_3; -char str1[] = STR_1; -char str2[] = STR_2 STR_2 STR_2; -char str3[] = STR_3; - -int sum(short *s) -{ - int i,total=0; - for (i=0; i < stb_arr_len(s); ++i) - total += s[i]; - return total; -} - -stb_uint stb_adler32_old(stb_uint adler32, stb_uchar *buffer, stb_uint buflen) -{ - const stb_uint ADLER_MOD = 65521; - stb_uint s1 = adler32 & 0xffff; - stb_uint s2 = adler32 >> 16; - - while (buflen-- > 0) { // NOTE: much faster implementations are possible! - s1 += *buffer++; if (s1 > ADLER_MOD) s1 -= ADLER_MOD; - s2 += s1 ; if (s2 > ADLER_MOD) s2 -= ADLER_MOD; - } - return (s2 << 16) + s1; -} - -int sample_test[3][5] = -{ - { 1,2,3,4,5 }, - { 6,7,8,9,10, }, - { 11,12,13,14,15 }, -}; - -typedef struct { unsigned short x,y,z; } struct1; -typedef struct { double a; int x,y,z; } struct2; - -char *args_raw[] = { "foo", "-dxrf", "bar", "-ts" }; -char *args[8]; - -void do_compressor(int,char**); -void test_sha1(void); - -int alloc_num, alloc_size; -void dumpfunc(void *ptr, int sz, char *file, int line) -{ - printf("%p (%6d) -- %3d:%s\n", ptr, sz, line, file); - alloc_size += sz; - alloc_num += 1; -} - -char *expects(stb_matcher *m, char *s, int result, int len, char *str) -{ - int res2,len2=0; - res2 = stb_lex(m, s, &len2); - c(result == res2 && len == len2, str); - return s + len; -} - -void test_lex(void) -{ - stb_matcher *m = stb_lex_matcher(); - // tok_en5 .3 20.1 20. .20 .1 - char *s = "tok_en5.3 20.1 20. .20.1"; - - stb_lex_item(m, "[a-zA-Z_][a-zA-Z0-9_]*", 1 ); - stb_lex_item(m, "[0-9]*\\.?[0-9]*" , 2 ); - stb_lex_item(m, "[\r\n\t ]+" , 3 ); - stb_lex_item(m, "." , -99 ); - s=expects(m,s,1,7, "stb_lex 1"); - s=expects(m,s,2,2, "stb_lex 2"); - s=expects(m,s,3,1, "stb_lex 3"); - s=expects(m,s,2,4, "stb_lex 4"); - s=expects(m,s,3,1, "stb_lex 5"); - s=expects(m,s,2,3, "stb_lex 6"); - s=expects(m,s,3,1, "stb_lex 7"); - s=expects(m,s,2,3, "stb_lex 8"); - s=expects(m,s,2,2, "stb_lex 9"); - s=expects(m,s,0,0, "stb_lex 10"); - stb_matcher_free(m); -} - -typedef struct Btest -{ - struct Btest stb_bst_fields(btest_); - int v; -} Btest; - -stb_bst(Btest, btest_, BT2,bt2,v, int, a - b) - -void bst_test(void) -{ - Btest *root = NULL, *t; - int items[500], sorted[500]; - int i,j,z; - for (z=0; z < 10; ++z) { - for (i=0; i < 500; ++i) - items[i] = stb_rand() & 0xfffffff; - - // check for collisions, and retrry if so - memcpy(sorted, items, sizeof(sorted)); - qsort(sorted, 500, sizeof(sorted[0]), stb_intcmp(0)); - for (i=1; i < 500; ++i) - if (sorted[i-1] == sorted[i]) - break; - if (i != 500) { --z; break; } - - for (i=0; i < 500; ++i) { - t = malloc(sizeof(*t)); - t->v = items[i]; - root = btest_insert(root, t); - #ifdef STB_DEBUG - btest__validate(root,1); - #endif - for (j=0; j <= i; ++j) - c(btest_find(root, items[j]) != NULL, "stb_bst 1"); - for ( ; j < 500; ++j) - c(btest_find(root, items[j]) == NULL, "stb_bst 2"); - } - - t = btest_first(root); - for (i=0; i < 500; ++i) - t = btest_next(root,t); - c(t == NULL, "stb_bst 5"); - t = btest_last(root); - for (i=0; i < 500; ++i) - t = btest_prev(root,t); - c(t == NULL, "stb_bst 6"); - - memcpy(sorted, items, sizeof(sorted)); - qsort(sorted, 500, sizeof(sorted[0]), stb_intcmp(0)); - t = btest_first(root); - for (i=0; i < 500; ++i) { - assert(t->v == sorted[i]); - t = btest_next(root, t); - } - assert(t == NULL); - - if (z==1) - stb_reverse(items, 500, sizeof(items[0])); - else if (z) - stb_shuffle(items, 500, sizeof(items[0]), stb_rand()); - - for (i=0; i < 500; ++i) { - t = btest_find(root, items[i]); - assert(t != NULL); - root = btest_remove(root, t); - c(btest_find(root, items[i]) == NULL, "stb_bst 5"); - #ifdef STB_DEBUG - btest__validate(root, 1); - #endif - for (j=0; j <= i; ++j) - c(btest_find(root, items[j]) == NULL, "stb_bst 3"); - for ( ; j < 500; ++j) - c(btest_find(root, items[j]) != NULL, "stb_bst 4"); - free(t); - } - } -} - -extern void stu_uninit(void); - -stb_define_sort(sort_int, int, *a < *b) - -stb_rand_define(prime_rand, 1) -void test_packed_floats(void); -void test_parser_generator(void); - -void rec_print(stb_dirtree2 *d, int depth) -{ - int i; - for (i=0; i < depth; ++i) printf(" "); - printf("%s (%d)\n", d->relpath, stb_arr_len(d->files)); - for (i=0; i < stb_arr_len(d->subdirs); ++i) - rec_print(d->subdirs[i], depth+1); - d->weight = (float) stb_arr_len(d->files); -} - -#ifdef MAIN_TEST -int main(int argc, char **argv) -{ - char *z; - stb__wchar buffer7[1024],buffer9[1024]; - char buffer8[4096]; - FILE *f; - char *p1 = "foo/bar\\baz/test.xyz"; - char *p2 = "foo/.bar"; - char *p3 = "foo.bar"; - char *p4 = "foo/bar"; - char *wildcards[] = { "*foo*", "*bar", "baz", "*1*2*3*", "*/CVS/repository", "*oof*" }; - char **s; - char buf[256], *p; - int n,len2,*q,i; - stb_matcher *mt=NULL; - - if (argc > 1) { - do_compressor(argc,argv); - return 0; - } - test_classes(); - //show(); - - //stb_malloc_check_counter(2,2); - //_CrtSetBreakAlloc(10398); - - stbprint("Checking {!if} the {$fancy} print function {#works}? - should\n"); - stbprint(" - align\n"); - stbprint("But {#3this}} {one}} - shouldn't\n"); - - #if 0 - { - int i; - char **s = stb_readdir_recursive("/sean", NULL); - stb_dirtree *d = stb_dirtree_from_files_relative("", s, stb_arr_len(s)); - stb_dirtree **e; - rec_print(d, 0); - e = stb_summarize_tree(d,12,4); - for (i=0; i < stb_arr_len(e); ++i) { - printf("%s\n", e[i]->fullpath); - } - stb_arr_free(e); - - stb_fatal("foo"); - } - #endif - - stb_("Started stb.c"); - test_threads2(); - test_threads(); - - for (i=0; i < 1023 && 5+77*i < 0xd800; ++i) - buffer7[i] = 5+77*i; - buffer7[i++] = 0xd801; - buffer7[i++] = 0xdc02; - buffer7[i++] = 0xdbff; - buffer7[i++] = 0xdfff; - buffer7[i] = 0; - p = stb_to_utf8(buffer8, buffer7, sizeof(buffer8)); - c(p != NULL, "stb_to_utf8"); - if (p != NULL) { - stb_from_utf8(buffer9, buffer8, sizeof(buffer9)/2); - c(!memcmp(buffer7, buffer9, i*2), "stb_from_utf8"); - } - - z = "foo.*[bd]ak?r"; - c( stb_regex(z, "muggle man food is barfy") == 1, "stb_regex 1"); - c( stb_regex("foo.*bar", "muggle man food is farfy") == 0, "stb_regex 2"); - c( stb_regex("[^a-zA-Z]foo[^a-zA-Z]", "dfoobar xfood") == 0, "stb_regex 3"); - c( stb_regex(z, "muman foob is bakrfy") == 1, "stb_regex 4"); - z = "foo.*[bd]bk?r"; - c( stb_regex(z, "muman foob is bakrfy") == 0, "stb_regex 5"); - c( stb_regex(z, "muman foob is bbkrfy") == 1, "stb_regex 6"); - - stb_regex(NULL,NULL); - - #if 0 - test_parser_generator(); - stb_wrapper_listall(dumpfunc); - if (alloc_num) - printf("Memory still in use: %d allocations of %d bytes.\n", alloc_num, alloc_size); - #endif - - test_script(); - p = stb_file("sieve.stua", NULL); - if (p) { - stua_run_script(p); - free(p); - } - stua_uninit(); - - //stb_wrapper_listall(dumpfunc); - printf("Memory still in use: %d allocations of %d bytes.\n", alloc_num, alloc_size); - - c(stb_alloc_count_alloc == stb_alloc_count_free, "stb_alloc 0"); - - bst_test(); - - c(stb_alloc_count_alloc == stb_alloc_count_free, "stb_alloc 0"); - -#if 0 - // stb_block - { - int inuse=0, freespace=0; - int *x = malloc(10000*sizeof(*x)); - stb_block *b = stb_block_new(1, 10000); - #define BLOCK_COUNT 1000 - int *p = malloc(sizeof(*p) * BLOCK_COUNT); - int *l = malloc(sizeof(*l) * BLOCK_COUNT); - int i, n, k = 0; - - memset(x, 0, 10000 * sizeof(*x)); - - n = 0; - while (n < BLOCK_COUNT && k < 1000) { - l[n] = 16 + (rand() & 31); - p[n] = stb_block_alloc(b, l[n], 0); - if (p[n] == 0) - break; - inuse += l[n]; - - freespace = 0; - for (i=0; i < b->len; ++i) - freespace += b->freelist[i].len; - assert(freespace + inuse == 9999); - - for (i=0; i < l[n]; ++i) - x[ p[n]+i ] = p[n]; - ++n; - - if (k > 20) { - int sz; - i = (stb_rand() % n); - sz = l[i]; - stb_block_free(b, p[i], sz); - inuse -= sz; - p[i] = p[n-1]; - l[i] = l[n-1]; - --n; - - freespace = 0; - for (i=0; i < b->len; ++i) - freespace += b->freelist[i].len; - assert(freespace + inuse == 9999); - } - - - ++k; - - // validate - if ((k % 50) == 0) { - int j; - for (j=0; j < n; ++j) { - for (i=0; i < l[j]; ++i) - assert(x[ p[j]+i ] == p[j]); - } - } - - if ((k % 200) == 0) { - stb_block_compact_freelist(b); - } - } - - for (i=0; i < n; ++i) - stb_block_free(b, p[i], l[i]); - - stb_block_destroy(b); - free(p); - free(l); - free(x); - } - - blockfile_test(); -#endif - - mt = stb_lex_matcher(); - for (i=0; i < 5; ++i) - stb_lex_item_wild(mt, wildcards[i], i+1); - - c(1==stb_lex(mt, "this is a foo in the middle",NULL), "stb_matcher_match 1"); - c(0==stb_lex(mt, "this is a bar in the middle",NULL), "stb_matcher_match 2"); - c(0==stb_lex(mt, "this is a baz in the middle",NULL), "stb_matcher_match 3"); - c(2==stb_lex(mt, "this is a bar",NULL), "stb_matcher_match 4"); - c(0==stb_lex(mt, "this is a baz",NULL), "stb_matcher_match 5"); - c(3==stb_lex(mt, "baz",NULL), "stb_matcher_match 6"); - c(4==stb_lex(mt, "1_2_3_4",NULL), "stb_matcher_match 7"); - c(0==stb_lex(mt, "1 3 3 3 3 2 ",NULL), "stb_matcher_match 8"); - c(4==stb_lex(mt, "1 3 3 3 2 3 ",NULL), "stb_matcher_match 9"); - c(5==stb_lex(mt, "C:/sean/prj/old/gdmag/mipmap/hqp/adol-c/CVS/Repository",NULL), "stb_matcher_match 10"); - stb_matcher_free(mt); - - { - #define SSIZE 500000 - static int arr[SSIZE],arr2[SSIZE]; - int i,good; - for (i=0; i < SSIZE; ++i) - arr2[i] = stb_rand(); - memcpy(arr,arr2,sizeof(arr)); - printf("stb_define_sort:\n"); - sort_int(arr, SSIZE); - good = 1; - for (i=0; i+1 < SSIZE; ++i) - if (arr[i] > arr[i+1]) - good = 0; - c(good, "stb_define_sort"); - printf("qsort:\n"); - qsort(arr2, SSIZE, sizeof(arr2[0]), stb_intcmp(0)); - printf("done\n"); - // check for bugs - memset(arr, 0, sizeof(arr[0]) * 1000); - sort_int(arr, 1000); - } - - - c(stb_alloc_count_alloc == stb_alloc_count_free, "stb_alloc -2"); - - c( stb_is_prime( 2), "stb_is_prime 1"); - c( stb_is_prime( 3), "stb_is_prime 2"); - c( stb_is_prime( 5), "stb_is_prime 3"); - c( stb_is_prime( 7), "stb_is_prime 4"); - c(!stb_is_prime( 9), "stb_is_prime 5"); - c( stb_is_prime(11), "stb_is_prime 6"); - c(!stb_is_prime(25), "stb_is_prime 7"); - c(!stb_is_prime(27), "stb_is_prime 8"); - c( stb_is_prime(29), "stb_is_prime 9"); - c( stb_is_prime(31), "stb_is_prime a"); - c(!stb_is_prime(33), "stb_is_prime b"); - c(!stb_is_prime(35), "stb_is_prime c"); - c(!stb_is_prime(36), "stb_is_prime d"); - - for (n=7; n < 64; n += 3) { - int i; - stb_perfect s; - unsigned int *p = malloc(n * sizeof(*p)); - for (i=0; i < n; ++i) - p[i] = i*i; - c(stb_perfect_create(&s, p, n), "stb_perfect_hash 1"); - stb_perfect_destroy(&s); - for (i=0; i < n; ++i) - p[i] = stb_rand(); - c(stb_perfect_create(&s, p, n), "stb_perfect_hash 2"); - stb_perfect_destroy(&s); - for (i=0; i < n; ++i) - p[i] = (0x80000000 >> stb_log2_ceil(n>>1)) * i; - c(stb_perfect_create(&s, p, n), "stb_perfect_hash 2"); - stb_perfect_destroy(&s); - for (i=0; i < n; ++i) - p[i] = (int) malloc(1024); - c(stb_perfect_create(&s, p, n), "stb_perfect_hash 3"); - stb_perfect_destroy(&s); - for (i=0; i < n; ++i) - free((void *) p[i]); - free(p); - } - printf("Maximum attempts required to find perfect hash: %d\n", - stb_perfect_hash_max_failures); - - p = "abcdefghijklmnopqrstuvwxyz"; - c(stb_ischar('c', p), "stb_ischar 1"); - c(stb_ischar('x', p), "stb_ischar 2"); - c(!stb_ischar('#', p), "stb_ischar 3"); - c(!stb_ischar('X', p), "stb_ischar 4"); - p = "0123456789"; - c(!stb_ischar('c', p), "stb_ischar 5"); - c(!stb_ischar('x', p), "stb_ischar 6"); - c(!stb_ischar('#', p), "stb_ischar 7"); - c(!stb_ischar('X', p), "stb_ischar 8"); - p = "#####"; - c(!stb_ischar('c', p), "stb_ischar a"); - c(!stb_ischar('x', p), "stb_ischar b"); - c(stb_ischar('#', p), "stb_ischar c"); - c(!stb_ischar('X', p), "stb_ischar d"); - p = "xXyY"; - c(!stb_ischar('c', p), "stb_ischar e"); - c(stb_ischar('x', p), "stb_ischar f"); - c(!stb_ischar('#', p), "stb_ischar g"); - c(stb_ischar('X', p), "stb_ischar h"); - - c(stb_alloc_count_alloc == stb_alloc_count_free, "stb_alloc 1"); - - q = stb_wordwrapalloc(15, "How now brown cow. Testinglishously. Okey dokey"); - // How now brown - // cow. Testinglis - // hously. Okey - // dokey - c(stb_arr_len(q) == 8, "stb_wordwrap 8"); - c(q[2] == 14 && q[3] == 15, "stb_wordwrap 9"); - c(q[4] == 29 && q[5] == 12, "stb_wordwrap 10"); - stb_arr_free(q); - - q = stb_wordwrapalloc(20, "How now brown cow. Testinglishously. Okey dokey"); - // How now brown cow. - // Testinglishously. - // Okey dokey - c(stb_arr_len(q) == 6, "stb_wordwrap 1"); - c(q[0] == 0 && q[1] == 18, "stb_wordwrap 2"); - c(q[2] == 19 && q[3] == 17, "stb_wordwrap 3"); - c(q[4] == 37 && q[5] == 10, "stb_wordwrap 4"); - stb_arr_free(q); - - q = stb_wordwrapalloc(12, "How now brown cow. Testinglishously. Okey dokey"); - // How now - // brown cow. - // Testinglisho - // usly. Okey - // dokey - c(stb_arr_len(q) == 10, "stb_wordwrap 5"); - c(q[4] == 19 && q[5] == 12, "stb_wordwrap 6"); - c(q[6] == 31 && q[3] == 10, "stb_wordwrap 7"); - stb_arr_free(q); - - //test_script(); - - //test_packed_floats(); - - c(stb_alloc_count_alloc == stb_alloc_count_free, "stb_alloc 0"); - if (stb_alloc_count_alloc != stb_alloc_count_free) { - printf("%d allocs, %d frees\n", stb_alloc_count_alloc, stb_alloc_count_free); - } - test_lex(); - - mt = stb_regex_matcher(".*foo.*bar.*"); - c(stb_matcher_match(mt, "foobarx") == 1, "stb_matcher_match 1"); - c(stb_matcher_match(mt, "foobar") == 1, "stb_matcher_match 2"); - c(stb_matcher_match(mt, "foo bar") == 1, "stb_matcher_match 3"); - c(stb_matcher_match(mt, "fo foo ba ba bar ba") == 1, "stb_matcher_match 4"); - c(stb_matcher_match(mt, "fo oo oo ba ba bar foo") == 0, "stb_matcher_match 5"); - stb_free(mt); - - mt = stb_regex_matcher(".*foo.?bar.*"); - c(stb_matcher_match(mt, "abfoobarx") == 1, "stb_matcher_match 6"); - c(stb_matcher_match(mt, "abfoobar") == 1, "stb_matcher_match 7"); - c(stb_matcher_match(mt, "abfoo bar") == 1, "stb_matcher_match 8"); - c(stb_matcher_match(mt, "abfoo bar") == 0, "stb_matcher_match 9"); - c(stb_matcher_match(mt, "abfo foo ba ba bar ba") == 0, "stb_matcher_match 10"); - c(stb_matcher_match(mt, "abfo oo oo ba ba bar foo") == 0, "stb_matcher_match 11"); - stb_free(mt); - - mt = stb_regex_matcher(".*m((foo|bar)*baz)m.*"); - c(stb_matcher_match(mt, "abfoobarx") == 0, "stb_matcher_match 12"); - c(stb_matcher_match(mt, "a mfoofoofoobazm d") == 1, "stb_matcher_match 13"); - c(stb_matcher_match(mt, "a mfoobarbazfoom d") == 0, "stb_matcher_match 14"); - c(stb_matcher_match(mt, "a mbarbarfoobarbazm d") == 1, "stb_matcher_match 15"); - c(stb_matcher_match(mt, "a mfoobarfoo bazm d") == 0, "stb_matcher_match 16"); - c(stb_matcher_match(mt, "a mm foobarfoobarfoobar ") == 0, "stb_matcher_match 17"); - stb_free(mt); - - mt = stb_regex_matcher("f*|z"); - c(stb_matcher_match(mt, "fz") == 0, "stb_matcher_match 0a"); - c(stb_matcher_match(mt, "ff") == 1, "stb_matcher_match 0b"); - c(stb_matcher_match(mt, "z") == 1, "stb_matcher_match 0c"); - stb_free(mt); - - mt = stb_regex_matcher("m(f|z*)n"); - c(stb_matcher_match(mt, "mfzn") == 0, "stb_matcher_match 0d"); - c(stb_matcher_match(mt, "mffn") == 0, "stb_matcher_match 0e"); - c(stb_matcher_match(mt, "mzn") == 1, "stb_matcher_match 0f"); - c(stb_matcher_match(mt, "mn") == 1, "stb_matcher_match 0g"); - c(stb_matcher_match(mt, "mzfn") == 0, "stb_matcher_match 0f"); - - c(stb_matcher_find(mt, "manmanmannnnnnnmmmmmmmmm ") == 0, "stb_matcher_find 1"); - c(stb_matcher_find(mt, "manmanmannnnnnnmmmmmmmmm ") == 0, "stb_matcher_find 2"); - c(stb_matcher_find(mt, "manmanmannnnnnnmmmmmmmmmffzzz ") == 0, "stb_matcher_find 3"); - c(stb_matcher_find(mt, "manmanmannnnnnnmmmmmmmmmnfzzz ") == 1, "stb_matcher_find 4"); - c(stb_matcher_find(mt, "mmmfn aanmannnnnnnmmmmmm fzzz ") == 1, "stb_matcher_find 5"); - c(stb_matcher_find(mt, "mmmzzn anmannnnnnnmmmmmm fzzz ") == 1, "stb_matcher_find 6"); - c(stb_matcher_find(mt, "mm anmannnnnnnmmmmmm fzmzznzz ") == 1, "stb_matcher_find 7"); - c(stb_matcher_find(mt, "mm anmannnnnnnmmmmmm fzmzzfnzz ") == 0, "stb_matcher_find 8"); - c(stb_matcher_find(mt, "manmfnmannnnnnnmmmmmmmmmffzzz ") == 1, "stb_matcher_find 9"); - stb_free(mt); - - mt = stb_regex_matcher(".*m((foo|bar)*|baz)m.*"); - c(stb_matcher_match(mt, "abfoobarx") == 0, "stb_matcher_match 18"); - c(stb_matcher_match(mt, "a mfoofoofoobazm d") == 0, "stb_matcher_match 19"); - c(stb_matcher_match(mt, "a mfoobarbazfoom d") == 0, "stb_matcher_match 20"); - c(stb_matcher_match(mt, "a mbazm d") == 1, "stb_matcher_match 21"); - c(stb_matcher_match(mt, "a mfoobarfoom d") == 1, "stb_matcher_match 22"); - c(stb_matcher_match(mt, "a mm foobarfoobarfoobar ") == 1, "stb_matcher_match 23"); - stb_free(mt); - - mt = stb_regex_matcher("[a-fA-F]..[^]a-zA-Z]"); - c(stb_matcher_match(mt, "Axx1") == 1, "stb_matcher_match 24"); - c(stb_matcher_match(mt, "Fxx1") == 1, "stb_matcher_match 25"); - c(stb_matcher_match(mt, "Bxx]") == 0, "stb_matcher_match 26"); - c(stb_matcher_match(mt, "Cxxz") == 0, "stb_matcher_match 27"); - c(stb_matcher_match(mt, "gxx[") == 0, "stb_matcher_match 28"); - c(stb_matcher_match(mt, "-xx0") == 0, "stb_matcher_match 29"); - stb_free(mt); - - c(stb_wildmatch("foo*bar", "foobarx") == 0, "stb_wildmatch 0a"); - c(stb_wildmatch("foo*bar", "foobar") == 1, "stb_wildmatch 1a"); - c(stb_wildmatch("foo*bar", "foo bar") == 1, "stb_wildmatch 2a"); - c(stb_wildmatch("foo*bar", "fo foo ba ba bar ba") == 0, "stb_wildmatch 3a"); - c(stb_wildmatch("foo*bar", "fo oo oo ba ba ar foo") == 0, "stb_wildmatch 4a"); - - c(stb_wildmatch("*foo*bar*", "foobar") == 1, "stb_wildmatch 1b"); - c(stb_wildmatch("*foo*bar*", "foo bar") == 1, "stb_wildmatch 2b"); - c(stb_wildmatch("*foo*bar*", "fo foo ba ba bar ba") == 1, "stb_wildmatch 3b"); - c(stb_wildmatch("*foo*bar*", "fo oo oo ba ba ar foo") == 0, "stb_wildmatch 4b"); - - c(stb_wildmatch("foo*bar*", "foobarx") == 1, "stb_wildmatch 1c"); - c(stb_wildmatch("foo*bar*", "foobabar") == 1, "stb_wildmatch 2c"); - c(stb_wildmatch("foo*bar*", "fo foo ba ba bar ba") == 0, "stb_wildmatch 3c"); - c(stb_wildmatch("foo*bar*", "fo oo oo ba ba ar foo") == 0, "stb_wildmatch 4c"); - - c(stb_wildmatch("*foo*bar", "foobar") == 1, "stb_wildmatch 1d"); - c(stb_wildmatch("*foo*bar", "foo bar") == 1, "stb_wildmatch 2d"); - c(stb_wildmatch("*foo*bar", "fo foo ba ba bar ba") == 0, "stb_wildmatch 3d"); - c(stb_wildmatch("*foo*bar", "fo oo oo ba ba ar foo") == 0, "stb_wildmatch 4d"); - - c(stb_wildfind("foo*bar", "xyfoobarx") == 2, "stb_wildfind 0a"); - c(stb_wildfind("foo*bar", "aaafoobar") == 3, "stb_wildfind 1a"); - c(stb_wildfind("foo*bar", "foo bar") == 0, "stb_wildfind 2a"); - c(stb_wildfind("foo*bar", "fo foo ba ba bar ba") == 3, "stb_wildfind 3a"); - c(stb_wildfind("foo*bar", "fo oo oo ba ba ar foo") == -1, "stb_wildfind 4a"); - - c(stb_wildmatch("*foo*;*bar*", "foobar") == 1, "stb_wildmatch 1e"); - c(stb_wildmatch("*foo*;*bar*", "afooa") == 1, "stb_wildmatch 2e"); - c(stb_wildmatch("*foo*;*bar*", "abara") == 1, "stb_wildmatch 3e"); - c(stb_wildmatch("*foo*;*bar*", "abaza") == 0, "stb_wildmatch 4e"); - c(stb_wildmatch("*foo*;*bar*", "foboar") == 0, "stb_wildmatch 5e"); - - test_sha1(); - - n = sizeof(args_raw)/sizeof(args_raw[0]); - memcpy(args, args_raw, sizeof(args_raw)); - s = stb_getopt(&n, args); - c(n >= 1 && !strcmp(args[1], "bar" ), "stb_getopt 1"); - c(stb_arr_len(s) >= 2 && !strcmp(s[2] , "r" ), "stb_getopt 2"); - stb_getopt_free(s); - - n = sizeof(args_raw)/sizeof(args_raw[0]); - memcpy(args, args_raw, sizeof(args_raw)); - s = stb_getopt_param(&n, args, "f"); - c(stb_arr_len(s) >= 3 && !strcmp(s[3] , "fbar"), "stb_getopt 3"); - stb_getopt_free(s); - - n = sizeof(args_raw)/sizeof(args_raw[0]); - memcpy(args, args_raw, sizeof(args_raw)); - s = stb_getopt_param(&n, args, "x"); - c(stb_arr_len(s) >= 2 && !strcmp(s[1] , "xrf" ), "stb_getopt 4"); - stb_getopt_free(s); - - n = sizeof(args_raw)/sizeof(args_raw[0]); - memcpy(args, args_raw, sizeof(args_raw)); - s = stb_getopt_param(&n, args, "s"); - c(s == NULL && n == 0 , "stb_getopt 5"); - stb_getopt_free(s); - -#if 0 - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, -1, -1) == 1, "stb_csample_int 1"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, 1, -3) == 2, "stb_csample_int 2"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, 12, -2) == 5, "stb_csample_int 3"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, 15, 1) == 10, "stb_csample_int 4"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, 5, 4) == 15, "stb_csample_int 5"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, 3, 3) == 14, "stb_csample_int 6"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, -2, 5) == 11, "stb_csample_int 7"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, -7, 0) == 1, "stb_csample_int 8"); - c(*stb_csample_int(sample_test[0], 1, 5, 5, 3, 2, 1) == 8, "stb_csample_int 9"); -#endif - - c(!strcmp(stb_splitpath(buf, p1, STB_PATH ), "foo/bar\\baz/"), "stb_splitpath 1"); - c(!strcmp(stb_splitpath(buf, p1, STB_FILE ), "test"), "stb_splitpath 2"); - c(!strcmp(stb_splitpath(buf, p1, STB_EXT ), ".xyz"), "stb_splitpath 3"); - c(!strcmp(stb_splitpath(buf, p1, STB_PATH_FILE ), "foo/bar\\baz/test"), "stb_splitpath 4"); - c(!strcmp(stb_splitpath(buf, p1, STB_FILE_EXT ), "test.xyz"), "stb_splitpath 5"); - - c(!strcmp(stb_splitpath(buf, p2, STB_PATH ), "foo/"), "stb_splitpath 6"); - c(!strcmp(stb_splitpath(buf, p2, STB_FILE ), ""), "stb_splitpath 7"); - c(!strcmp(stb_splitpath(buf, p2, STB_EXT ), ".bar"), "stb_splitpath 8"); - c(!strcmp(stb_splitpath(buf, p2, STB_PATH_FILE ), "foo/"), "stb_splitpath 9"); - c(!strcmp(stb_splitpath(buf, p2, STB_FILE_EXT ), ".bar"), "stb_splitpath 10"); - - c(!strcmp(stb_splitpath(buf, p3, STB_PATH ), "./"), "stb_splitpath 11"); - c(!strcmp(stb_splitpath(buf, p3, STB_FILE ), "foo"), "stb_splitpath 12"); - c(!strcmp(stb_splitpath(buf, p3, STB_EXT ), ".bar"), "stb_splitpath 13"); - c(!strcmp(stb_splitpath(buf, p3, STB_PATH_FILE ), "foo"), "stb_splitpath 14"); - - c(!strcmp(stb_splitpath(buf, p4, STB_PATH ), "foo/"), "stb_splitpath 16"); - c(!strcmp(stb_splitpath(buf, p4, STB_FILE ), "bar"), "stb_splitpath 17"); - c(!strcmp(stb_splitpath(buf, p4, STB_EXT ), ""), "stb_splitpath 18"); - c(!strcmp(stb_splitpath(buf, p4, STB_PATH_FILE ), "foo/bar"), "stb_splitpath 19"); - c(!strcmp(stb_splitpath(buf, p4, STB_FILE_EXT ), "bar"), "stb_splitpath 20"); - - c(!strcmp(p=stb_dupreplace("testfootffooo foo fox", "foo", "brap"), "testbraptfbrapo brap fox"), "stb_dupreplace 1"); free(p); - c(!strcmp(p=stb_dupreplace("testfootffooo foo fox", "foo", "" ), "testtfo fox" ), "stb_dupreplace 2"); free(p); - c(!strcmp(p=stb_dupreplace("abacab", "a", "aba"), "abababacabab" ), "stb_dupreplace 3"); free(p); - - -#if 0 - m = stb_mml_parse("
xy<&f>"); - c(m != NULL, "stb_mml_parse 1"); - if (m) { - c(!strcmp(m->child[0]->child[0]->child[1]->tag, "d"), "stb_mml_parse 2"); - c(!strcmp(m->child[0]->child[1]->leaf_data, "<&f>"), "stb_mml_parse 3"); - } - if (m) - stb_mml_free(m); - c(stb_alloc_count_alloc == stb_alloc_count_free, "stb_alloc 1"); - if (stb_alloc_count_alloc != stb_alloc_count_free) { - printf("%d allocs, %d frees\n", stb_alloc_count_alloc, stb_alloc_count_free); - } -#endif - - c(stb_linear_remap(3.0f,0,8,1,2) == 1.375, "stb_linear_remap()"); - - c(stb_bitreverse(0x1248fec8) == 0x137f1248, "stb_bitreverse() 1"); - c(stb_bitreverse8(0x4e) == 0x72, "stb_bitreverse8() 1"); - c(stb_bitreverse8(0x31) == 0x8c, "stb_bitreverse8() 2"); - for (n=1; n < 255; ++n) { - unsigned int m = stb_bitreverse8((uint8) n); - c(stb_bitreverse8((uint8) m) == (unsigned int) n, "stb_bitreverse8() 3"); - } - - for (n=2; n <= 31; ++n) { - c(stb_is_pow2 ((1 << n) ) == 1 , "stb_is_pow2() 1"); - c(stb_is_pow2 ((1 << n)+1) == 0 , "stb_is_pow2() 2"); - c(stb_is_pow2 ((1 << n)-1) == 0 , "stb_is_pow2() 3"); - - c(stb_log2_floor((1 << n) ) == n , "stb_log2_floor() 1"); - c(stb_log2_floor((1 << n)+1) == n , "stb_log2_floor() 2"); - c(stb_log2_floor((1 << n)-1) == n-1, "stb_log2_floor() 3"); - - c(stb_log2_ceil ((1 << n) ) == n , "stb_log2_ceil() 1"); - c(stb_log2_ceil ((1 << n)+1) == n+1, "stb_log2_ceil() 2"); - c(stb_log2_ceil ((1 << n)-1) == n , "stb_log2_ceil() 3"); - - c(stb_bitreverse(1 << n) == 1U << (31-n), "stb_bitreverse() 2"); - } - - c(stb_log2_floor(0) == -1, "stb_log2_floor() 4"); - c(stb_log2_ceil (0) == -1, "stb_log2_ceil () 4"); - - c(stb_log2_floor(-1) == 31, "stb_log2_floor() 5"); - c(stb_log2_ceil (-1) == 32, "stb_log2_ceil () 5"); - - c(stb_bitcount(0xffffffff) == 32, "stb_bitcount() 1"); - c(stb_bitcount(0xaaaaaaaa) == 16, "stb_bitcount() 2"); - c(stb_bitcount(0x55555555) == 16, "stb_bitcount() 3"); - c(stb_bitcount(0x00000000) == 0, "stb_bitcount() 4"); - - c(stb_lowbit8(0xf0) == 4, "stb_lowbit8 1"); - c(stb_lowbit8(0x10) == 4, "stb_lowbit8 2"); - c(stb_lowbit8(0xf3) == 0, "stb_lowbit8 3"); - c(stb_lowbit8(0xf8) == 3, "stb_lowbit8 4"); - c(stb_lowbit8(0x60) == 5, "stb_lowbit8 5"); - - for (n=0; n < sizeof(buf); ++n) - buf[n] = 0; - - for (n = 0; n < 200000; ++n) { - unsigned int k = stb_rand(); - int i,z=0; - for (i=0; i < 32; ++i) - if (k & (1 << i)) ++z; - c(stb_bitcount(k) == z, "stb_bitcount() 5"); - - buf[k >> 24] = 1; - - if (k != 0) { - if (stb_is_pow2(k)) { - c(stb_log2_floor(k) == stb_log2_ceil(k), "stb_is_pow2() 1"); - c(k == 1U << stb_log2_floor(k), "stb_is_pow2() 2"); - } else { - c(stb_log2_floor(k) == stb_log2_ceil(k)-1, "stb_is_pow2() 3"); - } - } - - c(stb_bitreverse(stb_bitreverse(n)) == (uint32) n, "stb_bitreverse() 3"); - } - - // make sure reasonable coverage from stb_rand() - for (n=0; n < sizeof(buf); ++n) - c(buf[n] != 0, "stb_rand()"); - - for (n=0; n < sizeof(buf); ++n) - buf[n] = 0; - - for (n=0; n < 60000; ++n) { - float z = (float) stb_frand(); - int n = (int) (z * sizeof(buf)); - c(z >= 0 && z < 1, "stb_frand() 1"); - c(n >= 0 && n < sizeof(buf), "stb_frand() 2"); - buf[n] = 1; - } - - // make sure reasonable coverage from stb_frand(), - // e.g. that the range remap isn't incorrect - for (n=0; n < sizeof(buf); ++n) - c(buf[n] != 0, "stb_frand()"); - - - // stb_arr - { - short *s = NULL; - - c(sum(s) == 0, "stb_arr 1"); - - stb_arr_add(s); s[0] = 3; - stb_arr_push(s,7); - - c( stb_arr_valid(s,1), "stb_arr 2"); - c(!stb_arr_valid(s,2), "stb_arr 3"); - - // force a realloc - stb_arr_push(s,0); - stb_arr_push(s,0); - stb_arr_push(s,0); - stb_arr_push(s,0); - - c(sum(s) == 10, "stb_arr 4"); - stb_arr_push(s,0); - s[0] = 1; s[1] = 5; s[2] = 20; - c(sum(s) == 26, "stb_arr 5"); - stb_arr_setlen(s,2); - c(sum(s) == 6, "stb_arr 6"); - stb_arr_setlen(s,1); - c(sum(s) == 1, "stb_arr 7"); - stb_arr_setlen(s,0); - c(sum(s) == 0, "stb_arr 8"); - - stb_arr_push(s,3); - stb_arr_push(s,4); - stb_arr_push(s,5); - stb_arr_push(s,6); - stb_arr_push(s,7); - stb_arr_deleten(s,1,3); - c(stb_arr_len(s)==2 && sum(s) == 10, "stb_arr_9"); - - stb_arr_push(s,2); - // 3 7 2 - stb_arr_insertn(s,2,2); - // 3 7 x x 2 - s[2] = 5; - s[3] = 6; - c(s[0]==3 && s[1] == 7 && s[2] == 5 && s[3] == 6 && s[4] == 2, "stb_arr 10"); - stb_arr_free(s); - } - - #if 1 - f= stb_fopen("data/stb.test", "wb"); - fwrite(buffer, 1, sizeof(buffer)-1, f); - stb_fclose(f, stb_keep_yes); - #ifndef WIN32 - sleep(1); // andLinux has some synchronization problem here - #endif - #else - f= fopen("data/stb.test", "wb"); - fwrite(buffer, 1, sizeof(buffer)-1, f); - fclose(f); - #endif - if (!stb_fexists("data/stb.test")) { - fprintf(stderr, "Error: couldn't open file just written, or stb_fexists() is broken.\n"); - } - - f = fopen("data/stb.test", "rb"); - // f = NULL; // test stb_fatal() - if (!f) { stb_fatal("Error: couldn't open file just written\n"); } - else { - char temp[4]; - int len1 = stb_filelen(f), len2; - int n1,n2; - if (fread(temp,1,4,f) == 0) { - int n = ferror(f); - if (n) { stb_fatal("Error reading from stream: %d", n); } - if (feof(f)) stb_fatal("Weird, read 0 bytes and hit eof"); - stb_fatal("Read 0, but neither feof nor ferror is true"); - } - fclose(f); - p = stb_file("data/stb.test", &len2); - if (p == NULL) stb_fatal("Error: stb_file() failed"); - c(len1 == sizeof(buffer)-1, "stb_filelen()"); - c(len2 == sizeof(buffer)-1, "stb_file():n"); - c(memcmp(p, buffer, sizeof(buffer)-1) == 0, "stb_file()"); - c(strcmp(p, buffer)==0, "stb_file() terminated"); - free(p); - - s = stb_stringfile("data/stb.test", &n1); - c(n1 == 3, "stb_stringfile():n"); - n2 = 0; - while (s[n2]) ++n2; - c(n1 == n2, "stb_stringfile():n length matches the non-NULL strings"); - if (n2 == 3) { - c(strcmp(s[0],str1)==0, "stb_stringfile()[0]"); - c(strcmp(s[1],str2)==0, "stb_stringfile()[1]"); - c(strcmp(s[2],str3)==0, "stb_stringfile()[2] (no terminating newlines)"); - } - free(s); - - f = fopen("data/stb.test", "rb"); - stb_fgets(buf, sizeof(buf), f); - //c(strcmp(buf, str1)==0, "stb_fgets()"); - p = stb_fgets_malloc(f); - n1 = strlen(p); - n2 = strlen(str2); - c(strcmp(p, str2)==0, "stb_fgets_malloc()"); - free(p); - stb_fgets(buf, sizeof(buf), f); - c(strcmp(buf, str3)==0, "stb_fgets()3"); - } - - c( stb_prefix("foobar", "foo"), "stb_prefix() 1"); - c(!stb_prefix("foo", "foobar"), "stb_prefix() 2"); - c( stb_prefix("foob", "foob" ), "stb_prefix() 3"); - - stb_strncpy(buf, "foobar", 6); c(strcmp(buf,"fooba" )==0, "stb_strncpy() 1"); - stb_strncpy(buf, "foobar", 8); c(strcmp(buf,"foobar")==0, "stb_strncpy() 2"); - - c(!strcmp(p=stb_duplower("FooBar"), "foobar"), "stb_duplower()"); free(p); - strcpy(buf, "FooBar"); - stb_tolower(buf); - c(!strcmp(buf, "foobar"), "stb_tolower()"); - - p = stb_strtok(buf, "foo=ba*r", "#=*"); - c(!strcmp(buf, "foo" ), "stb_strtok() 1"); - c(!strcmp(p , "ba*r"), "stb_strtok() 2"); - p = stb_strtok(buf, "foobar", "#=*"); - c(*p == 0, "stb_strtok() 3"); - - c(!strcmp(stb_skipwhite(" \t\n foo"), "foo"), "stb_skipwhite()"); - - s = stb_tokens("foo == ba*r", "#=*", NULL); - c(!strcmp(s[0], "foo "), "stb_tokens() 1"); - c(!strcmp(s[1], " ba"), "stb_tokens() 2"); - c(!strcmp(s[2], "r"), "stb_tokens() 3"); - c(s[3] == 0, "stb_tokens() 4"); - free(s); - - s = stb_tokens_allowempty("foo == ba*r", "#=*", NULL); - c(!strcmp(s[0], "foo "), "stb_tokens_allowempty() 1"); - c(!strcmp(s[1], "" ), "stb_tokens_allowempty() 2"); - c(!strcmp(s[2], " ba"), "stb_tokens_allowempty() 3"); - c(!strcmp(s[3], "r"), "stb_tokens_allowempty() 4"); - c(s[4] == 0, "stb_tokens_allowempty() 5"); - free(s); - - s = stb_tokens_stripwhite("foo == ba*r", "#=*", NULL); - c(!strcmp(s[0], "foo"), "stb_tokens_stripwhite() 1"); - c(!strcmp(s[1], "" ), "stb_tokens_stripwhite() 2"); - c(!strcmp(s[2], "ba"), "stb_tokens_stripwhite() 3"); - c(!strcmp(s[3], "r"), "stb_tokens_stripwhite() 4"); - c(s[4] == 0, "stb_tokens_stripwhite() 5"); - free(s); - - s = stb_tokens_quoted("foo =\"=\" ba*\"\"r \" foo\" bah ", "#=*", NULL); - c(!strcmp(s[0], "foo"), "stb_tokens_quoted() 1"); - c(!strcmp(s[1], "= ba"), "stb_tokens_quoted() 2"); - c(!strcmp(s[2], "\"r foo bah"), "stb_tokens_quoted() 3"); - c(s[3] == 0, "stb_tokens_quoted() 4"); - free(s); - - - p = stb_file("stb.h", &len2); - if (p) { - uint32 z = stb_adler32_old(1, p, len2); - uint32 x = stb_adler32 (1, p, len2); - c(z == x, "stb_adler32() 1"); - memset(p,0xff,len2); - z = stb_adler32_old((65520<<16) + 65520, p, len2); - x = stb_adler32 ((65520<<16) + 65520, p, len2); - c(z == x, "stb_adler32() 2"); - free(p); - } - - // stb_hheap - { - #define HHEAP_COUNT 100000 - void **p = malloc(sizeof(*p) * HHEAP_COUNT); - int i, j; - #if 0 - stb_hheap *h2, *h = stb_newhheap(sizeof(struct1),0); - - for (i=0; i < HHEAP_COUNT; ++i) - p[i] = stb_halloc(h); - stb_shuffle(p, HHEAP_COUNT, sizeof(*p), stb_rand()); - for (i=0; i < HHEAP_COUNT; ++i) - stb_hfree(p[i]); - - c(h->num_alloc == 0, "stb_hheap 1"); - stb_delhheap(h); - - h = stb_newhheap(sizeof(struct1),0); - h2 = stb_newhheap(sizeof(struct2),8); - - for (i=0; i < HHEAP_COUNT; ++i) { - if (i & 1) - p[i] = stb_halloc(h); - else { - p[i] = stb_halloc(h2); - c((((int) p[i]) & 4) == 0, "stb_hheap 2"); - } - } - - stb_shuffle(p, HHEAP_COUNT, sizeof(*p), stb_rand()); - for (i=0; i < HHEAP_COUNT; ++i) - stb_hfree(p[i]); - - c(h->num_alloc == 0, "stb_hheap 3"); - c(h2->num_alloc == 0, "stb_hheap 4"); - - stb_delhheap(h); - stb_delhheap(h2); - #else - for (i=0; i < HHEAP_COUNT; ++i) - p[i] = malloc(32); - stb_shuffle(p, HHEAP_COUNT, sizeof(*p), stb_rand()); - for (i=0; i < HHEAP_COUNT; ++i) - free(p[i]); - #endif - - // now use the same array of pointers to do pointer set operations - for (j=100; j < HHEAP_COUNT; j += 25000) { - stb_ps *ps = NULL; - for (i=0; i < j; ++i) - ps = stb_ps_add(ps, p[i]); - - for (i=0; i < HHEAP_COUNT; ++i) - c(stb_ps_find(ps, p[i]) == (i < j), "stb_ps 1"); - c(stb_ps_count(ps) == j, "stb_ps 1b"); - - for (i=j; i < HHEAP_COUNT; ++i) - ps = stb_ps_add(ps, p[i]); - - for (i=0; i < j; ++i) - ps = stb_ps_remove(ps, p[i]); - - for (i=0; i < HHEAP_COUNT; ++i) - c(stb_ps_find(ps, p[i]) == !(i < j), "stb_ps 2"); - - stb_ps_delete(ps); - } - - #define HHEAP_COUNT2 100 - // now use the same array of pointers to do pointer set operations - for (j=1; j < 40; ++j) { - stb_ps *ps = NULL; - for (i=0; i < j; ++i) - ps = stb_ps_add(ps, p[i]); - - for (i=0; i < HHEAP_COUNT2; ++i) - c(stb_ps_find(ps, p[i]) == (i < j), "stb_ps 3"); - c(stb_ps_count(ps) == j, "stb_ps 3b"); - - for (i=j; i < HHEAP_COUNT2; ++i) - ps = stb_ps_add(ps, p[i]); - - for (i=0; i < j; ++i) - ps = stb_ps_remove(ps, p[i]); - - for (i=0; i < HHEAP_COUNT2; ++i) - c(stb_ps_find(ps, p[i]) == !(i < j), "stb_ps 4"); - - stb_ps_delete(ps); - } - - free(p); - } - - - n = test_compression(tc, sizeof(tc)); - c(n >= 0, "stb_compress()/stb_decompress() 1"); - - p = stb_file("stb.h", &len2); - if (p) { - FILE *f = fopen("data/stb_h.z", "wb"); - if (stb_compress_stream_start(f)) { - int i; - void *q; - int len3; - - for (i=0; i < len2; ) { - int n = stb_rand() % 10; - if (n <= 6) n = 1 + stb_rand()%16; - else if (n <= 8) n = 20 + stb_rand() % 1000; - else n = 15000; - if (i + n > len2) n = len2 - i; - stb_write(p + i, n); - i += n; - } - stb_compress_stream_end(1); - - q = stb_decompress_fromfile("data/stb_h.z", &len3); - c(len3 == len2, "stb_compress_stream 2"); - if (len2 == len3) - c(!memcmp(p,q,len2), "stb_compress_stream 3"); - if (q) free(q); - } else { - c(0, "stb_compress_stream 1"); - } - - free(p); - stb_compress_window(65536*4); - } - - p = stb_file("stb.h", &len2); - if (p) { - n = test_compression(p, len2); - c(n >= 0, "stb_compress()/stb_decompress() 2"); - #if 0 - n = test_en_compression(p, len2); - c(n >= 0, "stb_en_compress()/stb_en_decompress() 2"); - #endif - free(p); - } else { - fprintf(stderr, "No stb.h to compression test.\n"); - } - - p = stb_file("data/test.bmp", &len2); - if (p) { - n = test_compression(p, len2); - c(n == 106141, "stb_compress()/stb_decompress() 4"); - #if 0 - n = test_en_compression(p, len2); - c(n >= 0, "stb_en_compress()/stb_en_decompress() 4"); - #endif - free(p); - } - - // the hardcoded compressed lengths being verified _could_ - // change if you changed the compressor parameters; but pure - // performance optimizations shouldn't change them - p = stb_file("data/cantrbry.zip", &len2); - if (p) { - n = test_compression(p, len2); - c(n == 642787, "stb_compress()/stb_decompress() 3"); - #if 0 - n = test_en_compression(p, len2); - c(n >= 0, "stb_en_compress()/stb_en_decompress() 3"); - #endif - free(p); - } - - p = stb_file("data/bible.txt", &len2); - if (p) { - n = test_compression(p, len2); - c(n == 2022520, "stb_compress()/stb_decompress() 4"); - #if 0 - n = test_en_compression(p, len2); - c(n >= 0, "stb_en_compress()/stb_en_decompress() 4"); - #endif - free(p); - } - - { - int len = 1 << 25, o=0; // 32MB - char *buffer = malloc(len); - int i; - for (i=0; i < 8192; ++i) - buffer[o++] = (char) stb_rand(); - for (i=0; i < (1 << 15); ++i) - buffer[o++] = 1; - for (i=0; i < 64; ++i) - buffer[o++] = buffer[i]; - for (i=0; i < (1 << 21); ++i) - buffer[o++] = 2; - for (i=0; i < 64; ++i) - buffer[o++] = buffer[i]; - for (i=0; i < (1 << 21); ++i) - buffer[o++] = 3; - for (i=0; i < 8192; ++i) - buffer[o++] = buffer[i]; - for (i=0; i < (1 << 21); ++i) - buffer[o++] = 4; - assert(o < len); - stb_compress_window(1 << 24); - i = test_compression(buffer, len); - c(n >= 0, "stb_compress() 6"); - free(buffer); - } - - #ifdef STB_THREADS - stb_thread_cleanup(); - #endif - stb_ischar(0,NULL); - stb_wrapper_listall(dumpfunc); - printf("Memory still in use: %d allocations of %d bytes.\n", alloc_num, alloc_size); - - // force some memory checking - for (n=1; n < 20; ++n) - malloc(1 << n); - - printf("Finished stb.c with %d errors.\n", count); - - #ifdef _MSC_VER - if (count) - __asm int 3; - #endif - - return 0; -} - -#endif - - - - - -// NIST test vectors - -struct -{ - int length; - char *message; - char *digest; -} sha1_tests[] = -{ -{ 24, -"616263", -"a9993e364706816aba3e25717850c26c9cd0d89d", -},{ - 1304, -"ec29561244ede706b6eb30a1c371d74450a105c3f9735f7fa9fe38cf67f304a5736a106e" -"92e17139a6813b1c81a4f3d3fb9546ab4296fa9f722826c066869edacd73b25480351858" -"13e22634a9da44000d95a281ff9f264ecce0a931222162d021cca28db5f3c2aa24945ab1" -"e31cb413ae29810fd794cad5dfaf29ec43cb38d198fe4ae1da2359780221405bd6712a53" -"05da4b1b737fce7cd21c0eb7728d08235a9011", -"970111c4e77bcc88cc20459c02b69b4aa8f58217", -},{ - 2096, -"5fc2c3f6a7e79dc94be526e5166a238899d54927ce470018fbfd668fd9dd97cbf64e2c91" -"584d01da63be3cc9fdff8adfefc3ac728e1e335b9cdc87f069172e323d094b47fa1e652a" -"fe4d6aa147a9f46fda33cacb65f3aa12234746b9007a8c85fe982afed7815221e43dba55" -"3d8fe8a022cdac1b99eeeea359e5a9d2e72e382dffa6d19f359f4f27dc3434cd27daeeda" -"8e38594873398678065fbb23665aba9309d946135da0e4a4afdadff14db18e85e71dd93c" -"3bf9faf7f25c8194c4269b1ee3d9934097ab990025d9c3aaf63d5109f52335dd3959d38a" -"e485050e4bbb6235574fc0102be8f7a306d6e8de6ba6becf80f37415b57f9898a5824e77" -"414197422be3d36a6080", - "0423dc76a8791107d14e13f5265b343f24cc0f19", -},{ - 2888, -"0f865f46a8f3aed2da18482aa09a8f390dc9da07d51d1bd10fe0bf5f3928d5927d08733d" -"32075535a6d1c8ac1b2dc6ba0f2f633dc1af68e3f0fa3d85e6c60cb7b56c239dc1519a00" -"7ea536a07b518ecca02a6c31b46b76f021620ef3fc6976804018380e5ab9c558ebfc5cb1" -"c9ed2d974722bf8ab6398f1f2b82fa5083f85c16a5767a3a07271d67743f00850ce8ec42" -"8c7f22f1cf01f99895c0c844845b06a06cecb0c6cf83eb55a1d4ebc44c2c13f6f7aa5e0e" -"08abfd84e7864279057abc471ee4a45dbbb5774afa24e51791a0eada11093b88681fe30b" -"aa3b2e94113dc63342c51ca5d1a6096d0897b626e42cb91761058008f746f35465465540" -"ad8c6b8b60f7e1461b3ce9e6529625984cb8c7d46f07f735be067588a0117f23e34ff578" -"00e2bbe9a1605fde6087fb15d22c5d3ac47566b8c448b0cee40373e5ba6eaa21abee7136" -"6afbb27dbbd300477d70c371e7b8963812f5ed4fb784fb2f3bd1d3afe883cdd47ef32bea" -"ea", - "6692a71d73e00f27df976bc56df4970650d90e45", -},{ - 3680, -"4893f1c763625f2c6ce53aacf28026f14b3cd8687e1a1d3b60a81e80fcd1e2b038f9145a" -"b64a0718f948f7c3c9ac92e3d86fb669a5257da1a18c776291653688338210a3242120f1" -"01788e8acc9110db9258b1554bf3d26602516ea93606a25a7f566c0c758fb39ecd9d876b" -"c5d8abc1c3205095382c2474cb1f8bbdb45c2c0e659cb0fc703ec607a5de6bcc7a28687d" -"b1ee1c8f34797bb2441d5706d210df8c2d7d65dbded36414d063c117b52a51f7a4eb9cac" -"0782e008b47459ed5acac0bc1f20121087f992ad985511b33c866d18e63f585478ee5a5e" -"654b19d81231d98683ae3f0533565aba43dce408d7e3c4c6be11d8f05165f29c9dcb2030" -"c4ee31d3a04e7421aa92c3231a1fc07e50e95fea7389a5e65891afaba51cf55e36a9d089" -"bf293accb356d5d06547307d6e41456d4ed146a056179971c56521c83109bf922866186e" -"184a99a96c7bb96df8937e35970e438412a2b8d744cf2ad87cb605d4232e976f9f151697" -"76e4e5b6b786132c966b25fc56d815c56c819af5e159aa39f8a93d38115f5580cda93bc0" -"73c30b39920e726fe861b72483a3f886269ab7a8eefe952f35d25c4eb7f443f4f3f26e43" -"d51fb54591e6a6dad25fcdf5142033084e5624bdd51435e77dea86b8", - "dc5859dd5163c4354d5d577b855fa98e37f04384", -},{ - 4472, -"cf494c18a4e17bf03910631471bca5ba7edea8b9a63381e3463517961749848eb03abefd" -"4ce676dece3740860255f57c261a558aa9c7f11432f549a9e4ce31d8e17c79450ce2ccfc" -"148ad904aedfb138219d7052088520495355dadd90f72e6f69f9c6176d3d45f113f275b7" -"fbc2a295784d41384cd7d629b23d1459a22e45fd5097ec9bf65fa965d3555ec77367903c" -"32141065fc24da5c56963d46a2da3c279e4035fb2fb1c0025d9dda5b9e3443d457d92401" -"a0d3f58b48469ecb1862dc975cdbe75ca099526db8b0329b03928206f084c633c04eef5e" -"8e377f118d30edf592504be9d2802651ec78aeb02aea167a03fc3e23e5fc907c324f283f" -"89ab37e84687a9c74ccf055402db95c29ba2c8d79b2bd4fa96459f8e3b78e07e923b8119" -"8267492196ecb71e01c331f8df245ec5bdf8d0e05c91e63bb299f0f6324895304dda721d" -"39410458f117c87b7dd6a0ee734b79fcbe482b2c9e9aa0cef03a39d4b0c86de3bc34b4aa" -"dabfa373fd2258f7c40c187744d237080762382f547a36adb117839ca72f8ebbc5a20a07" -"e86f4c8bb923f5787698d278f6db0040e76e54645bb0f97083995b34b9aa445fc4244550" -"58795828dd00c32471ec402a307f5aa1b37b1a86d6dae3bcbfbe9ba41cab0beeabf489af" -"0073d4b3837d3f14b815120bc3602d072b5aeefcdec655fe756b660eba7dcf34675acbce" -"317746270599424b9248791a0780449c1eabbb9459cc1e588bfd74df9b1b711c85c09d8a" -"a171b309281947e8f4b6ac438753158f4f36fa", - "4c17926feb6e87f5bca7890d8a5cde744f231dab", -},{ - 5264, -"8236153781bd2f1b81ffe0def1beb46f5a70191142926651503f1b3bb1016acdb9e7f7ac" -"ced8dd168226f118ff664a01a8800116fd023587bfba52a2558393476f5fc69ce9c65001" -"f23e70476d2cc81c97ea19caeb194e224339bcb23f77a83feac5096f9b3090c51a6ee6d2" -"04b735aa71d7e996d380b80822e4dfd43683af9c7442498cacbea64842dfda238cb09992" -"7c6efae07fdf7b23a4e4456e0152b24853fe0d5de4179974b2b9d4a1cdbefcbc01d8d311" -"b5dda059136176ea698ab82acf20dd490be47130b1235cb48f8a6710473cfc923e222d94" -"b582f9ae36d4ca2a32d141b8e8cc36638845fbc499bce17698c3fecae2572dbbd4705524" -"30d7ef30c238c2124478f1f780483839b4fb73d63a9460206824a5b6b65315b21e3c2f24" -"c97ee7c0e78faad3df549c7ca8ef241876d9aafe9a309f6da352bec2caaa92ee8dca3928" -"99ba67dfed90aef33d41fc2494b765cb3e2422c8e595dabbfaca217757453fb322a13203" -"f425f6073a9903e2dc5818ee1da737afc345f0057744e3a56e1681c949eb12273a3bfc20" -"699e423b96e44bd1ff62e50a848a890809bfe1611c6787d3d741103308f849a790f9c015" -"098286dbacfc34c1718b2c2b77e32194a75dda37954a320fa68764027852855a7e5b5274" -"eb1e2cbcd27161d98b59ad245822015f48af82a45c0ed59be94f9af03d9736048570d6e3" -"ef63b1770bc98dfb77de84b1bb1708d872b625d9ab9b06c18e5dbbf34399391f0f8aa26e" -"c0dac7ff4cb8ec97b52bcb942fa6db2385dcd1b3b9d567aaeb425d567b0ebe267235651a" -"1ed9bf78fd93d3c1dd077fe340bb04b00529c58f45124b717c168d07e9826e33376988bc" -"5cf62845c2009980a4dfa69fbc7e5a0b1bb20a5958ca967aec68eb31dd8fccca9afcd30a" -"26bab26279f1bf6724ff", - "11863b483809ef88413ca9b0084ac4a5390640af", -},{ - 6056, -"31ec3c3636618c7141441294fde7e72366a407fa7ec6a64a41a7c8dfda150ca417fac868" -"1b3c5be253e3bff3ab7a5e2c01b72790d95ee09b5362be835b4d33bd20e307c3c702aa15" -"60cdc97d190a1f98b1c78e9230446e31d60d25155167f73e33ed20cea27b2010514b57ba" -"b05ed16f601e6388ea41f714b0f0241d2429022e37623c11156f66dd0fa59131d8401dba" -"f502cffb6f1d234dcb53e4243b5cf9951688821586a524848123a06afa76ab8058bcfa72" -"27a09ce30d7e8cb100c8877bb7a81b615ee6010b8e0daced7cc922c971940b757a9107de" -"60b8454dda3452e902092e7e06faa57c20aadc43c8012b9d28d12a8cd0ba0f47ab4b377f" -"316902e6dff5e4f2e4a9b9de1e4359f344e66d0565bd814091e15a25d67d89cf6e30407b" -"36b2654762bbe53a6f204b855a3f9108109e351825cf9080c89764c5f74fb4afef89d804" -"e7f7d097fd89d98171d63eaf11bd719df44c5a606be0efea358e058af2c265b2da2623fd" -"afc62b70f0711d0150625b55672060cea6a253c590b7db1427a536d8a51085756d1e6ada" -"41d9d506b5d51bcae41249d16123b7df7190e056777a70feaf7d9f051fdbbe45cbd60fc6" -"295dda84d4ebbd7284ad44be3ee3ba57c8883ead603519b8ad434e3bf630734a9243c00a" -"a07366b8f88621ec6176111f0418c66b20ff9a93009f43432aaea899dad0f4e3ae72e9ab" -"a3f678f140118eb7117230c357a5caa0fe36c4e6cf1957bbe7499f9a68b0f1536e476e53" -"457ed826d9dea53a6ded52e69052faaa4d3927b9a3f9e8b435f424b941bf2d9cd6849874" -"42a44d5acaa0da6d9f390d1a0dd6c19af427f8bb7c082ae405a8dd535dea76aa360b4faa" -"d786093e113424bb75b8cc66c41af637a7b2acdca048a501417919cf9c5cd3b2fa668860" -"d08b6717eea6f125fa1b0bae1dbb52aafce8ae2deaf92aeb5be003fb9c09fedbc286ffb5" -"e16ad8e07e725faa46ebc35500cf205fc03250075ddc050c263814b8d16d141db4ca289f" -"386719b28a09a8e5934722202beb3429899b016dfeb972fee487cdd8d18f8a681042624f" -"51", - "f43937922444421042f76756fbed0338b354516f", -},{ - 6848, -"21b9a9686ec200456c414f2e6963e2d59e8b57e654eced3d4b57fe565b51c9045c697566" -"44c953178f0a64a6e44d1b46f58763c6a71ce4c373b0821c0b3927a64159c32125ec916b" -"6edd9bf41c3d80725b9675d6a97c8a7e3b662fac9dbcf6379a319a805b5341a8d360fe00" -"5a5c9ac1976094fea43566d66d220aee5901bd1f2d98036b2d27eb36843e94b2e5d1f09c" -"738ec826de6e0034cf8b1dca873104c5c33704cae290177d491d65f307c50a69b5c81936" -"a050e1fe2b4a6f296e73549323b6a885c3b54ee5eca67aa90660719126b590163203909e" -"470608f157f033f017bcf48518bf17d63380dabe2bc9ac7d8efe34aedcae957aeb68f10c" -"8ad02c4465f1f2b029d5fbb8e8538d18be294394b54b0ee6e67a79fce11731604f3ac4f8" -"d6ffa9ef3d2081f3d1c99ca107a7bf3d624324a7978ec38af0bcd0d7ee568572328b212b" -"9dc831efb7880e3f4d6ca7e25f8e80d73913fb8edfffd758ae4df61b4140634a92f49314" -"6138ebdcdaa083ea72d52a601230aa6f77874dcad9479f5bcac3763662cc30cb99823c5f" -"f469dcbd64c028286b0e579580fd3a17b56b099b97bf62d555798f7a250e08b0e4f238c3" -"fcf684198bd48a68c208a6268be2bb416eda3011b523388bce8357b7f26122640420461a" -"bcabcb5004519adfa2d43db718bce7d0c8f1b4645c89315c65df1f0842e5741244bba3b5" -"10801d2a446818635d0e8ffcd80c8a6f97ca9f878793b91780ee18eb6c2b99ffac3c38ef" -"b7c6d3af0478317c2b9c421247eba8209ea677f984e2398c7c243696a12df2164417f602" -"d7a1d33809c865b73397550ff33fe116166ae0ddbccd00e2b6fc538733830ac39c328018" -"bcb87ac52474ad3cce8780d6002e14c6734f814cb551632bcc31965c1cd23d048b9509a4" -"e22ab88f76a6dba209d5dd2febd1413a64d32be8574a22341f2a14e4bd879abb35627ef1" -"35c37be0f80843006a7cc7158d2bb2a71bf536b36de20ca09bb5b674e5c408485106e6fa" -"966e4f2139779b46f6010051615b5b41cda12d206d48e436b9f75d7e1398a656abb0087a" -"a0eb453368fc1ecc71a31846080f804d7b67ad6a7aa48579c3a1435eff7577f4e6004d46" -"aac4130293f6f62ae6d50c0d0c3b9876f0728923a94843785966a27555dd3ce68602e7d9" -"0f7c7c552f9bda4969ec2dc3e30a70620db6300e822a93e633ab9a7a", - "5d4d18b24b877092188a44be4f2e80ab1d41e795", -},{ - 7640, -"1c87f48f4409c3682e2cf34c63286dd52701b6c14e08669851a6dc8fa15530ad3bef692c" -"7d2bf02238644561069df19bdec3bccae5311fce877afc58c7628d08d32d9bd2dc1df0a6" -"24360e505944219d211f33bff62e9ff2342ac86070240a420ccaf14908e6a93c1b27b6e2" -"0324e522199e83692805cc4c7f3ea66f45a490a50d4dd558aa8e052c45c1a5dfad452674" -"edc7149024c09024913f004ceee90577ff3eaec96a1eebbdc98b440ffeb0cad9c6224efc" -"9267d2c192b53dc012fb53010926e362ef9d4238d00df9399f6cbb9acc389a7418007a6c" -"a926c59359e3608b548bdeece213f4e581d02d273781dffe26905ec161956f6dfe1c008d" -"6da8165d08f8062eea88e80c055b499f6ff8204ffdb303ab132d9b0cba1e5675f3525bbe" -"4cf2c3f2b00506f58336b36aefd865d37827f2fad7d1e59105b52f1596ea19f848037dfe" -"dc9136e824ead5505e2995d4c0769276548835430667f333fc77375125b29c1b1535602c" -"10fe161864f49a98fc274ae7335a736be6bf0a98cd019d120b87881103f86c0a6efadd8c" -"aa405b6855c384141b4f8751cc42dc0cb2913382210baaa84fe242ca66679472d815c08b" -"f3d1a7c6b5705a3de17ad157522de1eb90c568a8a1fbcbb422cca293967bb14bfdd91bc5" -"a9c4d2774dee524057e08f937f3e2bd8a04ced0fc7b16fb78a7b16ee9c6447d99e53d846" -"3726c59066af25c317fc5c01f5dc9125809e63a55f1cd7bdf7f995ca3c2655f4c7ab940f" -"2aa48bc3808961eb48b3a03c731ce627bb67dd0037206c5f2c442fc72704258548c6a9db" -"e16da45e40da009dc8b2600347620eff8361346116b550087cb9e2ba6b1d6753622e8b22" -"85589b90a8e93902aa17530104455699a1829efef153327639b2ae722d5680fec035575c" -"3b48d9ec8c8e9550e15338cc76b203f3ab597c805a8c6482676deabc997a1e4ba857a889" -"97ceba32431443c53d4d662dd5532aa177b373c93bf93122b72ed7a3189e0fa171dfabf0" -"520edf4b9d5caef595c9a3a13830c190cf84bcf9c3596aadb2a674fbc2c951d135cb7525" -"3ee6c59313444f48440a381e4b95f5086403beb19ff640603394931f15d36b1cc9f3924f" -"794c965d4449bfbdd8b543194335bdf70616dc986b49582019ac2bf8e68cfd71ec67e0aa" -"dff63db39e6a0ef207f74ec6108fae6b13f08a1e6ae01b813cb7ee40961f95f5be189c49" -"c43fbf5c594f5968e4e820a1d38f105f2ff7a57e747e4d059ffb1d0788b7c3c772b9bc1f" -"e147c723aca999015230d22c917730b935e902092f83e0a8e6db9a75d2626e0346e67e40" -"8d5b815439dab8ccb8ea23f828fff6916c4047", - "32e0f5d40ceec1fbe45ddd151c76c0b3fef1c938", -},{ - 8432, -"084f04f8d44b333dca539ad2f45f1d94065fbb1d86d2ccf32f9486fe98f7c64011160ec0" -"cd66c9c7478ed74fde7945b9c2a95cbe14cedea849978cc2d0c8eb0df48d4834030dfac2" -"b043e793b6094a88be76b37f836a4f833467693f1aa331b97a5bbc3dbd694d96ce19d385" -"c439b26bc16fc64919d0a5eab7ad255fbdb01fac6b2872c142a24aac69b9a20c4f2f07c9" -"923c9f0220256b479c11c90903193d4e8f9e70a9dbdf796a49ca5c12a113d00afa844694" -"de942601a93a5c2532031308ad63c0ded048633935f50a7e000e9695c1efc1e59c426080" -"a7d1e69a93982a408f1f6a4769078f82f6e2b238b548e0d4af271adfa15aa02c5d7d7052" -"6e00095ffb7b74cbee4185ab54385f2707e8362e8bd1596937026f6d95e700340b6338ce" -"ba1ee854a621ce1e17a016354016200b1f98846aa46254ab15b7a128b1e840f494b2cdc9" -"daccf14107c1e149a7fc27d33121a5cc31a4d74ea6945816a9b7a83850dc2c11d26d767e" -"ec44c74b83bfd2ef8a17c37626ed80be10262fe63cf9f804b8460c16d62ae63c8dd0d124" -"1d8aaac5f220e750cb68d8631b162d80afd6b9bf929875bf2e2bc8e2b30e05babd8336be" -"31e41842673a66a68f0c5acd4d7572d0a77970f42199a4da26a56df6aad2fe420e0d5e34" -"448eb2ed33afbfb35dffaba1bf92039df89c038bae3e11c02ea08aba5240c10ea88a45a1" -"d0a8631b269bec99a28b39a3fc5b6b5d1381f7018f15638cc5274ab8dc56a62b2e9e4fee" -"f172be20170b17ec72ff67b81c15299f165810222f6a001a281b5df1153a891206aca89e" -"e7baa761a5af7c0493a3af840b9219e358b1ec1dd301f35d4d241b71ad70337bda42f0ea" -"dc9434a93ed28f96b6ea073608a314a7272fefd69d030cf22ee6e520b848fa705ed6160f" -"e54bd3bf5e89608506e882a16aced9c3cf80657cd03749f34977ced9749caa9f52b683e6" -"4d96af371b293ef4e5053a8ea9422df9dd8be45d5574730f660e79bf4cbaa5f3c93a79b4" -"0f0e4e86e0fd999ef4f26c509b0940c7a3eaf1f87c560ad89aff43cd1b9d4863aa3ebc41" -"a3dd7e5b77372b6953dae497fc7f517efe99e553052e645e8be6a3aeb362900c75ce712d" -"fcba712c4c25583728db9a883302939655ef118d603e13fcf421d0cea0f8fb7c49224681" -"d013250defa7d4fd64b69b0b52e95142e4cc1fb6332486716a82a3b02818b25025ccd283" -"198b07c7d9e08519c3c52c655db94f423912b9dc1c95f2315e44be819477e7ff6d2e3ccd" -"daa6da27722aaadf142c2b09ce9472f7fd586f68b64d71fc653decebb4397bf7af30219f" -"25c1d496514e3c73b952b8aa57f4a2bbf7dcd4a9e0456aaeb653ca2d9fa7e2e8a532b173" -"5c4609e9c4f393dd70901393e898ed704db8e9b03b253357f333a66aba24495e7c3d1ad1" -"b5200b7892554b59532ac63af3bdef590b57bd5df4fbf38d2b3fa540fa5bf89455802963" -"036bd173fe3967ed1b7d", - "ee976e4ad3cad933b283649eff9ffdb41fcccb18", -},{ - 9224, -"bd8320703d0cac96a96aeefa3abf0f757456bf42b3e56f62070fc03e412d3b8f4e4e427b" -"c47c4600bb423b96de6b4910c20bc5c476c45feb5b429d4b35088813836fa5060ceb26db" -"bb9162e4acd683ef879a7e6a0d6549caf0f0482de8e7083d03ed2f583de1b3ef505f4b2c" -"cd8a23d86c09d47ba05093c56f21a82c815223d777d0cabb7ee4550423b5deb6690f9394" -"1862ae41590ea7a580dda79229d141a786215d75f77e74e1db9a03c9a7eb39eb35adf302" -"5e26eb31ca2d2ca507edca77d9e7cfcfd136784f2117a2afafa87fa468f08d07d720c933" -"f61820af442d260d172a0a113494ca169d33a3aeaacdcc895b356398ed85a871aba769f6" -"071abd31e9f2f5834721d0fef6f6ee0fc0e38760b6835dfcc7dbefb592e1f0c3793af7ad" -"f748786d3364f3cfd5686b1a18711af220e3637d8fad08c553ce9d5dc1183d48e8337b16" -"1fe69b50e1920316dbffec07425b5d616a805a699576590e0939f5c965bce6c7342d314a" -"c37b9c4d30166567c4f633f182de4d6b00e20a1c762789f915eaa1c89ac31b85222b1f05" -"403dedd94db9ce75ff4e49923d1999d032695fa0a1c595617830c3c9a7ab758732fcec26" -"85ae14350959b6a5f423ef726587e186b055a8daf6fa8fdefa02841b2fdbca1616dcee78" -"c685fc6dcc09f24a36097572eba3c37a3eabe98bc23836085f63ef71a54b4488615d83b2" -"6ed28c9fce78852df9b6cf8a75ca3899a7567298e91bc4ffdd04ffab0066b43b8286a4bb" -"555c78808496b252c6e0e4d153631f11f68baf88630e052acc2af5d2af2e22e4f23bb630" -"314c561a577455f86b6727bcad3c19d3e271404dec30af3d9dd0ed63cd9fa708aadfa12a" -"500ef2d99a6b71e137b56ba90036975b88004b45f577ef800f0fb3cf97577dc9da37253b" -"8675e5c8bb7e0bd26564f19eca232fb25f280f82e014424c9fbdd1411d7556e5d7906bb8" -"62206316ba03385cd820c54c82ed35b36735bc486b1885d84053eba036c1ebfb5422d93d" -"a71c53deda7f74db07cd4959cdfa898ba37080d76b564d344b124dd7b80cd70ed3b52a6c" -"f9c9a32695d134bd39eb11ddeecdac86c808e469bd8a7995b667c452e7d9a54d5c85bcf6" -"d5ffdc27d491bc06f438f02c7cf018073431587c78ba08d18a8daccb2d3b26136f612ade" -"c673f3cd5eb83412b29652d55a10d0d6238d0b5365db272c917349450aff062c36191cfc" -"d45660819083f89cd42ecae9e26934a020cafeb9b2b68d544edf59574c0ca159fd195dbf" -"3e3e74244d942fffdbd4ed7f626219bab88b5a07e50b09a832d3e8ad82091114e54f2c35" -"6b48e55e36589ebad3ac6077cb7b1827748b00670df65bbf0a2e65caad3f8a97d654d64e" -"1c7dad171cafbc37110d2f7ca66524dc08fe60593e914128bd95f41137bfe819b5ca835f" -"e5741344b5c907ce20a35f4f48726141c6398e753ed9d46d3692050628c78859d5014fe4" -"dd3708e58d4d9807f8dac540492e32fa579491717ad4145c9efc24cf95605660b2e09b89" -"9369b74d3ebff41e707917ff314d93e6ac8dfd643ef2c087cd9912005b4b2681da01a369" -"42a756a3e22123cbf38c429373c6a8663130c24b24b2690b000013960b1c46a32d1d5397" -"47", - "2df09b10933afedfcd3f2532dfd29e7cb6213859", -},{ - 10016, -"7a94978bec7f5034b12c96b86498068db28cd2726b676f54d81d8d7350804cc106bead8a" -"252b465a1f413b1c41e5697f8cece49ec0dea4dfb9fa7b1bfe7a4a00981875b420d094bb" -"1ce86c1b8c2e1dbebf819c176b926409fdec69042e324e71d7a8d75006f5a11f512811fe" -"6af88a12f450e327950b18994dfc3f740631beda6c78bca5fe23d54e6509120e05cd1842" -"d3639f1466cf26585030e5b4aefe0404fe900afc31e1980f0193579085342f1803c1ba27" -"0568f80eaf92440c4f2186b736f6ab9dc7b7522ccdcfc8cf12b6375a2d721aa89b5ef482" -"112a42c31123aebabcb485d0e72d6b6b70c44e12d2da98d1f87fa9df4f37847e1ffec823" -"1b8be3d737d282ddb9cc4b95937acfa0f028ba450def4d134a7d0fc88119bf7296e18cd4" -"4f56890b661b5b72ddfa34c29228067e13caf08eb3b7fd29de800df9a9ae137aad4a81a4" -"16a301c9f74b66c0e163e243b3187996b36eb569de3d9c007d78df91f9b554eef0eaa663" -"88754ce20460b75d95e2d0747229a1502a5652cf39ca58e1daa0e9321d7ab3093981cd70" -"23a7ee956030dd70177028a66ad619ad0629e631f91228b7c5db8e81b276d3b168c1edb1" -"bc0888d1cbcbb23245c2d8e40c1ff14bfe13f9c70e93a1939a5c45eef9351e795374b9e1" -"b5c3a7bd642477ba7233e1f590ab44a8232c53099a3c0a6ffe8be8b7ca7b58e6fedf700f" -"6f03dd7861ee1ef857e3f1a32a2e0baa591d0c7ca04cb231cc254d29cda873f00d68f465" -"00d6101cfdc2e8004c1f333d8007325d06ffe6b0ff7b80f24ba51928e65aa3cb78752028" -"27511207b089328bb60264595a2cebfc0b84d9899f5eca7ea3e1d2f0f053b4e67f975500" -"7ff3705ca4178ab9c15b29dd99494135f35befbcec05691d91f6361cad9c9a32e0e65577" -"f14d8dc66515081b51d09e3f6c25eea868cf519a83e80c935968cae6fce949a646ad53c5" -"6ee1f07dda23daef3443310bc04670afedb1a0132a04cb64fa84b4af4b3dc501044849cd" -"dd4adb8d733d1eac9c73afa4f7d75864c87787f4033ffe5ba707cbc14dd17bd1014b8b61" -"509c1f55a25cf6c0cbe49e4ddcc9e4de3fa38f7203134e4c7404ee52ef30d0b3f4e69bcc" -"7d0b2e4d8e60d9970e02cc69d537cfbc066734eb9f690a174e0194ca87a6fadad3883d91" -"6bd1700a052b26deee832701590d67e6f78938eac7c4beef3061a3474dd90dd588c1cd6e" -"6a4cda85b110fd08a30dcd85a3ebde910283366a17a100db920885600db7578be46bcfa6" -"4765ba9a8d6d5010cb1766d5a645e48365ed785e4b1d8c7c233c76291c92ef89d70bc77f" -"bf37d7ce9996367e5b13b08242ce73971f1e0c6ff2d7920fb9c821768a888a7fe0734908" -"33efb854cbf482aed5cb594fb715ec82a110130664164db488666d6198279006c1aa521f" -"9cf04250476c934eba0914fd586f62d6c5825b8cf82cd7ef915d93106c506ea6760fd8b0" -"bf39875cd1036b28417de54783173446026330ef701c3a6e5b6873b2025a2c1666bb9e41" -"a40adb4a81c1052047dabe2ad092df2ae06d6d67b87ac90be7d826ca647940c4da264cad" -"43c32a2bb8d5e27f87414e6887561444a80ed879ce91af13e0fbd6af1b5fa497ad0cbd2e" -"7f0f898f52f9e4710de2174e55ad07c45f8ead3b02cac6c811becc51e72324f2439099a0" -"5740090c1b165ecae7dec0b341d60a88f46d7ad8624aac231a90c93fad61fcfbbea12503" -"59fcd203862a6b0f1d71ac43db6c58a6b60c2c546edc12dd658998e8", - "f32e70862a16e3e8b199e9d81a9949d66f812cad", -},{ - 10808, -"88dd7f273acbe799219c23184782ac0b07bade2bc46b4f8adbd25ed3d59c0fd3e2931638" -"837d31998641bbb7374c7f03d533ca60439ac4290054ff7659cc519bdda3dff2129a7bdb" -"66b3300068931ade382b7b813c970c8e15469187d25cb04b635403dc50ea6c65ab38a97c" -"431f28a41ae81c16192bd0c103f03b8fa815d6ea5bf0aa7fa534ad413b194eb12eb74f5d" -"62b3d3a7411eb8c8b09a261542bf6880acbdfb617a42e577009e482992253712f8d4c8bd" -"1c386bad068c7aa10a22111640041f0c35dabd0de00ebf6cd82f89cbc49325df12419278" -"ec0d5ebb670577b2fe0c3e0840c5dd0dc5b3da00669eed8ead380f968b00d42f4967faec" -"c131425fce1f7edb01cbec7e96d3c26fa6390a659e0ab069ef3edadc07e077bb816f1b22" -"98830a0fe2b393693bb79f41feca89577c5230e0a6c34b860dc1fdb10d85aa054481082c" -"494779d59ba798fcd817116c3059b7831857d0364352b354ce3b960fbb61a1b8a04d47ca" -"a0ead52a9bea4bada2646cdbaec211f391dac22f2c5b8748e36bfc3d4e8ea45131ca7f52" -"af09df21babe776fcecbb5c5dfa352c790ab27b9a5e74242bbd23970368dbefd7c3c74d1" -"61ae01c7e13c65b415f38aa660f51b69ea1c9a504fe1ad31987cb9b26a4db2c37d7b326c" -"50dbc8c91b13925306ff0e6098532dee7282a99c3ddf99f9e1024301f76e31e58271870b" -"d94b9356e892a6a798d422a48c7fd5b80efe855a4925cc93b8cf27badec5498338e2b538" -"70758b45d3e7a2fa059ed88df320a65e0a7cf87fa7e63b74cea1b7371e221f8004726642" -"30d4d57945a85b23d58f248c8cd06ccfabfa969ab8cb78317451fab60e4fdfa796e2e2a8" -"b46405839a91266d37e8d38bae545fb4060c357923b86d62f5d59d7bef5af20fbb9c7fb4" -"2c6fd487748ed3b9973dbf4b1f2c9615129fa10d21cc49c622842c37c01670be71715765" -"a98814634efbdee66bf3420f284dbd3efafc8a9117a8b9a72d9b81aa53ded78c409f3f90" -"bad6e30d5229e26f4f0cea7ee82c09e3b60ec0e768f35a7fb9007b869f9bfc49c518f648" -"3c951d3b6e22505453266ec4e7fe6a80dbe6a2458a1d6cd93044f2955607412091009c7d" -"6cd81648a3b0603c92bfdff9ec3c0104b07ed2105962ca7c56ede91cb932073c337665e2" -"409387549f9a46da05bc21c5126bd4b084bc2c06ab1019c51df30581aa4464ab92978c13" -"f6d7c7ac8d30a78f982b9a43181bbe3c3eb9f7a1230b3e53b98a3c2a028317827fbe8cf6" -"ec5e3e6b2a084d517d472b25f72fab3a34415bba488f14e7f621cfa72396ba40890e8c60" -"b04815601a0819c9bebc5e18b95e04be3f9c156bd7375d8cc8a97c13ce0a3976123419fa" -"592631317ca638c1182be06886f9663d0e8e6839573df8f52219eeb5381482a6a1681a64" -"173660bfbb6d98bf06ee31e601ee99b4b99b5671ed0253260b3077ed5b977c6a79b4ff9a" -"08efd3cba5c39bec1a1e9807d40bbf0c988e0fd071cf2155ed7b014c88683cd869783a95" -"4cbfced9c0e80c3a92d45b508985cbbc533ba868c0dc4f112e99400345cf7524e42bf234" -"5a129e53da4051c429af2ef09aba33ae3c820ec1529132a203bd2b81534f2e865265f55c" -"9395caf0e0d3e1762c95eaaec935e765dc963b3e0d0a04b28373ab560fa9ba5ca71ced5d" -"17bb8b56f314f6f0d0bc8104b3f1835eca7eaac15adf912cf9a6945cfd1de392342dd596" -"d67e7ffcb7e086a6c1ea318aa2e0c2b5c2da079078232c637de0d317a1f26640bc1dac5b" -"e8699b53edc86e4bfdfaf797a2ae350bf4ea29790face675c4d2e85b8f37a694c91f6a14" -"1fd561274392ee6ee1a14424d5c134a69bcb4333079400f03615952fc4c99bf03f5733a8" -"dc71524269fc5c648371f5f3098314d9d10258", - "08632c75676571a5db5971f5d99cb8de6bf1792a", -},{ - 11600, -"85d43615942fcaa449329fd1fe9efb17545eb252cac752228f1e9d90955a3cf4e72cb116" -"3c3d8e93ccb7e4826206ff58b3e05009ee82ab70943db3f18a32925d6d5aed1525c91673" -"bd33846571af815b09bb236466807d935b5816a8be8e9becbe65d05d765bcc0bc3ae66c2" -"5320ebe9fff712aa5b4931548b76b0fd58f6be6b83554435587b1725873172e130e1a3ca" -"3d9d0425f4632d79cca0683780f266a0633230e4f3b25f87b0c390092f7b13c66ab5e31b" -"5a58dbcac8dd26a0600bf85507057bb36e870dfae76da8847875a1a52e4596d5b4b0a211" -"2435d27e1dc8dd5016d60feaf2838746d436a2983457b72e3357059b2bf1e9148bb0551a" -"e2b27d5a39abd3d1a62c36331e26668e8baabc2a1ef218b5e7a51a9ca35795bcd54f403a" -"188eafafb30d82896e45ddaea4f418629a1fb76a0f539c7114317bac1e2a8fba5a868bce" -"40abd40f6b9ced3fa8c0329b4de5ca03cc84d75b8746ef31e6c8d0a0a79b4f747690928e" -"be327f8bbe9374a0df4c39c845bf3322a49fda9455b36db5a9d6e4ea7d4326cf0e0f7cd8" -"0ff74538f95cec01a38c188d1243221e9272ccc1053e30787c4cf697043cca6fc3730d2a" -"431ecbf60d73ee667a3ab114c68d578c66dc1c659b346cb148c053980190353f6499bfef" -"acfd1d73838d6dc1188c74dd72b690fb0481eee481a3fd9af1d4233f05d5ae33a7b10d7d" -"d643406cb1f88d7dd1d77580dcbee6f757eeb2bfbcc940f2cddb820b2718264b1a64115c" -"b85909352c44b13d4e70bbb374a8594d8af7f41f65b221bf54b8d1a7f8f9c7da563550cb" -"2b062e7a7f21d5e07dd9da8d82e5a89074627597551c745718094c2eb316ca077526d27f" -"9a589c461d891dc7cd1bc20ba3f464da53c97924219c87a0f683dfb3b3ac8793c59e78ac" -"fac109439221ac599a6fd8d2754946d6bcba60784805f7958c9e34ff287ad1dbbc888848" -"fa80cc4200dbb8c5e4224535906cbffdd0237a77a906c10ced740f9c0ce7821f2dbf8c8d" -"7d41ecfcc7dfdc0846b98c78b765d01fb1eb15ff39149ab592e5dd1152665304bba85bbf" -"4705751985aaaf31245361554d561a2337e3daeef58a826492fd886d5f18ef568c1e772e" -"f6461170407695e3254eb7bf0c683811ddde5960140d959114998f08bdb24a104095987d" -"3255d590e0dbd41ae32b1ae4f4ea4a4f011de1388034231e034756870c9f2d9f23788723" -"27055a7de2b5e931dfb53e7780b6d4294bf094e08567025b026db9203b681565a1d52f30" -"318d0ebe49471b22ba5fd62e1ed6c8966c99b853c9062246a1ace51ef7523c7bf93bef53" -"d8a9cb96d6a04f0da1eca888df66e0380a72525a7ecc6115d08569a66248f6ba34e2341b" -"fd01a78f7b3c1cfe0754e0d26cba2fa3f951ef14d5749ff8933b8aba06fa40fb570b467c" -"54ce0d3f0bed21e998e5a36b3bc2f9e1ae29c4bab59c121af6fad67c0b45959cd6a86194" -"14b90b4535fb95f86ca7e64502acc135eff4f8a3abe9dde84238fab7a7d402454a3f07ad" -"ec05ec94b2891e0879037fae6acaa31dcecf3f85236ade946f5ad69ad4077beb65099285" -"38ee09f2bc38e5704da67b5006b5e39cd765aafcd740c7dadb99d0c547126e1324610fcb" -"7353dac2c110e803fca2b17485b1c4b78690bc4f867e6f043b2568889f67985a465a48eb" -"ee915200589e915756d4968d26529c3ffe3dbe70e84c682ad08a0c68db571634fbb0210d" -"c1b16b8b725886465c8c51f36a5e27d0f78e5643e051d3bddd512ce511f6bdf3dfe42759" -"00c5fea9d248c2b3f36911ed0ff41a19f6445521f251724657ea8f795b3ead0928a1657f" -"308dd7c7c1e7e490d9849df43becfa5cc25ed09ef614fd69ddc7e5e3147623901d647876" -"fb60077ffc48c51ed7d02b35f6802e3715fc708a0c88b82fe9cba0a442d38d09ca5ae483" -"21487bdef1794e7636bf7457dd2b51a391880c34d229438347e5fec8555fe263f08ba87b" -"b16dcde529248a477628067d13d0cb3bf51776f4d39fb3fbc5f669e91019323e40360e4b" -"78b6584f077bf9e03b66", - "ab7213f6becb980d40dc89fbda0ca39f225a2d33", -},{ - 12392, -"7ae3ca60b3a96be914d24980fb5652eb68451fed5fa47abe8e771db8301fbd5331e64753" -"93d96a4010d6551701e5c23f7ecb33bec7dd7bade21381e9865d410c383a139cb4863082" -"8e9372bd197c5b5788b6599853e8487bddfd395e537772fdd706b6a1de59c695d63427da" -"0dc3261bce2e1ae3cd6de90ec45ecd7e5f14580f5672b6ccd8f9336330dffcd6a3612a74" -"975afc08fb136450e25dc6b071ddfc28fca89d846c107fd2e4bd7a19a4ff6f482d62896d" -"a583c3277e23ab5e537a653112cdf2306043b3cc39f5280bd744fe81d66f497b95650e7d" -"dfd704efcb929b13e00c3e3a7d3cd53878af8f1506d9de05dba9c39a92604b394ea25acb" -"a2cda7b4ae8b08098ba3f0fdea15359df76517be84377f33631c844313ac335aa0d590fe" -"c472d805521f0905d44ca40d7391b292184105acd142c083761c1a038c4f5ed869ea3696" -"99592a37817f64cb4205b66be1f1de6fa47a08e1bf1a94312fe61a29e71bab242af95a7b" -"38d4fb412c682b30256d91e2a46b634535d02b495240cbdb842cbe17cba6a2b94073f3d5" -"f9621ac92ddda66f98bed997216466b4bb0579d58945f8d7450808d9e285d4f1709d8a1d" -"416aa57d4a1a72bfcbfecdda33de2cff3e90e0cc60c897c4663224fc5bbe8316a83c1773" -"802837a57bc7e9238173ed41ea32fe5fe38e546014a16d5e80700d9bac7a84bb03902f31" -"79e641f86f6bc383d656daf69801499633fb367ea7593195934c72bc9bf9624c0c845ebf" -"c36eb7ad4b22fdfb45ca7d4f0d6708c69a21f6eaa6db6bde0f0bd9dc7ec9c6e24626d0a7" -"8fbeeed4b391f871e80e6a9d207165832d4ff689296f9bca15dc03c7c0381659ea5335eb" -"aafdc3e50d18e46b00f1844870d09c25afcdb0ff1ae69dd8f94f91aca6095ba6f2b6e594" -"c4acfe9903485d21b684e31a6acc2162d40e1a7bb8114a860a07e76f5265666555f2418d" -"f11ef8f7499656d12215f5da8d7d041ac72648d15d7661ad93b24f3f071334b0921d5bb0" -"6f2c7ab09f5034518b5ae21cec379373e87d51c77d44a70c2337606aadeb9036716fd920" -"a824e7ae18ce3de9f0ec3456f3454027d8c476b3f1854b240c309f6f9786fa8a073915d9" -"7a019ce99aec3260c5f6b6346cd9c41cb9267f4475958e45289965548238c6b9f91a8784" -"b4e0957ba8b73956012c9a2fc3428434b1c1679f6ed2a3e8e2c90238df428622046f668e" -"e2b053f55e64ffd45600e05a885e3264af573bacee93d23d72a0222b5442ac80bc0a8b79" -"4c2afcf3bc881d20c111f57e3450b50a703f3db1fc5de2076a006f3b7eed694b93269874" -"3b03c2ed2684bad445e69a692e744c7ac3a04f1e0e52b7a6708076d1fbffdb3f1c995828" -"7d5f884e29407030f2db06811092efd80ae08da9daec39744c5ecd3ca771663b8f4968d4" -"2a88c2c9821c73ae2a5a4d9e2551f82c03583b9c4dea775423b4748d24eb604e8ee3159b" -"a6de9bea5b22eed6264e011734ed02b2c74ce06dda890b8604ed7ba49e7bf30e28c9871b" -"e90f5cead67eaf52b5d3181c822b10701219b28ef6f6bebfa278e38acf863e2a1d4b1e40" -"fd8a0ac6ce31054446301046148bf10dc3ae3385e2026e7762bdc8003ffebc4263191a59" -"c72f4f90db03e7d52808506b33bfe1dfa53f1a3daa152e83974fbe56cfd4e8f4e7f7806a" -"084b9d0795b858100eced0b5355a72446f37779d6c67ade60a627b8077ae1f3996b03bc3" -"a5c290651c8609f0d879fbf578cbab35086e1159dd6ddbe3bf7fb5654edcc8f09e4f80d0" -"258c9376d7c53fb68f78d333b18b70170d9a11070790c956f5744c78c986b1baf08b7631" -"7a65c5f07ae6f57eb0e65488659324d29709e3735623d0426e90aa8c4629bb080881150c" -"02be1c004da84414ac001c2eb6138c26388f5a36d594f3acef0e69e2cb43b870efa84da0" -"cff9c923a9880202aed64ad76260f53c45bb1584b3e388a909d13586094b924680006a1d" -"25d4dd36c579a8ec9d3fa63c082d977a5a5021440b5314b51850f2daa6e6af6ae88cb5b1" -"44242bceb1d4771e641101f8abfc3a9b19f2de64e35e76458ad22072ba57925d73015de5" -"66c66fcaa28fdc656f90de967ad51afd331e246d74ed469d63dd7d219935c59984bd9629" -"09d1af296eb3121d782650e7d038063bab5fa854aac77de5ffebeb53d263f521e3fc02ac" -"70", - "b0e15d39025f5263e3efa255c1868d4a37041382", -},{ - 13184, -"fa922061131282d91217a9ff07463843ae34ff7f8c28b6d93b23f1ea031d5020aa92f660" -"8c3d3df0ee24a8958fd41af880ee454e36e26438defb2de8f09c018607c967d2f0e8b80a" -"00c91c0eabe5b4c253e319b45e6106ff8bf0516f866020e5ba3f59fd669c5aeff310ebb3" -"85007069d01c64f72d2b02f4ec0b45c5ecf313056afcb52b17e08b666d01fecc42adb5b4" -"9ea00c60cacac2e0a953f1324bdd44aec00964a22a3cb33916a33da10d74ec6c6577fb37" -"5dc6ac8a6ad13e00cba419a8636d4daac8383a2e98fe90790cde7b59cfaa17c410a52abc" -"d68b127593d2fcbafd30578d195d890e981ae09e6772cb4382404a4e09f1a33c958b57db" -"ccee54ae335b6c91443206a0c100135647b844f226417a1f70317fd350d9f3789d81894a" -"aff4730072401aaeb8b713ead4394e2e64b6917d6eee2549af7bd0952f12035719065320" -"ca0d2dfe2847c6a2357c52bee4a676b12bafff66597bd479aa29299c1896f63a7523a85a" -"b7b916c5930ab66b4d191103cefc74f2f7e0e96e354f65e355ae43959a0af1880d14ea9d" -"1569e4fd47174aba7f5decb430b3f6baf80a1ef27855227b62487250d3602970e423423c" -"7ca90920685bcf75adfbe2a61ce5bd9228947b32f567927cb1a5bd8727c03aef91d6367b" -"ae7d86fd15c0977ac965a88b0d7236037aefb8d24eec8d2a07c633e031a7b9147c4c7714" -"110bfc7e261448a5d0f73c3619664e1c533c81a0acbf95d502227a33f84f0b8249e3f9fa" -"5c7905a8192b7313fc56bb20679e81333d32c797ac5162204a0eaa0e64507635921c485b" -"8f17c4e2484667a733197529e2a833eed83c57229b11bd820b5a5b78f1867787dbc217ea" -"28bfba785fb545cbc5a840a12eea428213e1aaa4e50a900ba13efcf4a5345574c2481c5d" -"927ada610bba567a55630c89d905db3d9b67fe36c9cc3d6a947664c83e69f51c74711a33" -"df66dd3ff6af9b7c1605b614d4798b4192b9a4b1508f2e2ec5aaad7eaea1ee8867353db9" -"b8d7d9a6f16aa5f339492073238c979082879aee7f94ac4be8133eaacbaedfb044e2ad4e" -"93ba0fa071dea615a5cd80d1d2678f4f93ae5a4bc9cdf3df345a29ec41d8febb23805ce4" -"2541036f3f05c63ae736f79a29802045fad9f370cabf843458c1b636ca41f387fd7821c9" -"1abbd1946afcb9186b936403233f28a5b467595131a6bc07b0873e51a08de66b5d7709a6" -"02c1bd0e7f6e8f4beb0579c51bda0e0c738ef876fcd9a40ab7873c9c31c1d63a588eebc7" -"8d9a0ae6fa35cd1a269e0d2bc68252cbd7c08d79e96f0aa6be22a016136a2b8abe9d3c9c" -"f9d60eeafe3dbc76d489b24d68c36167df4c38cf2b21cf03dc5e659e39018c3490f1237e" -"ca3f85b742ab0045d86a899c4126ad60a147cbc95b71814c274d6478668df41eb32acfb4" -"bbf024fb4e3d6be0b60653a0471afc3037ab67dcb00a2b2e24b26911e1880136e56106b7" -"f3c570fbe6f311d94624cb001914ff96fbbf481f71686aa17be0850568058fc1ee8900b4" -"7af5cf51c5ed9e00a8b532c131f42513f6b8df14a9bbc2e9ede5a560681184d41a147552" -"edfbdef98d95e6a7793229d25ba9b0b395a020aa1c0731de89e662246d59ec22e5d8f4b4" -"6fbc048efcffbc234744c5c66417070f9c751c81788f04691ccb1a09d60c46f6f73375bf" -"e2e646cf6290069541a8dfe216374c925e94d06ece72e851e81d3e8acd011f82526c2f9f" -"55955c6752dc10e93153ab58627e30fa2c573e4042954337982eec1f741be058c85bad86" -"bf3a02ed96d3201dadd48bd4de8105200dfcbcc400c3c3dd717abfc562ebe338b14b1eb5" -"ecbe9227661e49c58bf8233770d813faafc78b05711135adcc4ce4c65095ca0bdc1debc0" -"b6e5d195dbc582ce94b3afa14a422edf9b69abd7ae869a78c3a26fb50ef7122ec5af8d0c" -"78ef082ca114f8817c3d93b31809870caea2eb9533fa767c2954efb9ba07e4f1077e9f9b" -"be845661eabea2c91079321477a7c167c7234528d63d6aabbe723e0e337b2e61138a310a" -"3fd04368aa4215b7af9d0334a8a74681bcb86b4af87a0329a1ed9dc7c9aef14521785eda" -"0eeb97bdff8c9945fd0ee04e84d0dae091a69c0bfcdcd4150878fed839c0db6565fc1fed" -"0e7d6ae2efde7a59d58a9fb3b07e6f7cea51ba93f771c18b2eafa252d7fe171085776052" -"a6a17e6858f0a20b7e8be54413523989bf20a028a84d9ce98b78e6ee0b8362df49de5344" -"b409cc322354672a21ea383e870d047551a3af71aaf2f44f49a859cf001e61b592dd036f" -"c6625bf7b91ea0fb78c1563cceb8c4345bf4a9fbe6ee2b6bf5e81083", - "8b6d59106f04300cb57c7c961945cd77f3536b0a", -},{ - 13976, -"162cca41155de90f6e4b76a34261be6666ef65bdb92b5831b47604ce42e0c6c8d2eda265" -"ab9a3716809bf2e745e7831a41768d0f6349a268d9ac6e6adfb832a5d51b75d7951cf60e" -"03d9e40de6d351f1f6ade5143531cf32839401ca6dfb9dc7473daa607aeb0c3d1e8eb3db" -"cc2f1231ad1dd394d7eac9d8dab726b895b1ee774fdcabc8031063ecfa41c71a9f03ad23" -"904cc056f17c76a1059c43faffe30dfd157fdfd7d792e162bf7a889109550a0fc4c41523" -"2af0c0d72dcbc2595299e1a1c2aeae549f7970e994c15e0ab02f113d740d38c32a4d8ec0" -"79cd099d37d954ab7ef2800902cdf7c7a19fb14b3c98aaf4c6ad93fe9a9bc7a61229828e" -"55ad4d6270d1bdbca9975d450f9be91e5699bd7ee22e8c9c22e355cf1f6793f3551cb510" -"c1d5cd363bdf8cab063e6e49a6383221f1188d64692c1f84c910a696de2e72fb9886193f" -"61ab6b41ad0ea894d37ff1261bf1fd1f187e0d0c38ab223d99ec6d6b1e6b079fc305e24e" -"2d9500c98676e2d587434495d6e107b193c06fb12d5d8eaa7b0c001d08f4d91cae5bdcae" -"6624ee755e95ca8e4c5ef5b903d7f5ba438abeffd6f16d82d88138f157e7a50d1c91fb50" -"c770f6d222fcbf6daf791b1f8379e3b157a3b496ddb2e71650c1c4ac4fc5f2aceb5b3228" -"ffc44e15c02d4baa9434e60928a93f21bc91cfd3c2719f53a8c9bcd2f2dee65a8bbc88f9" -"5d7ced211fc3b04f6e8b74eb2026d66fd57fa0cccea43f0a0381782e6fee5660afed674d" -"cb2c28cb54d2bdbbaf78e534b0742ede6b5e659b46cd516d5362a194dd0822f6417935c4" -"ff05815b118fe5687cd8b050240015cfe449d9dfde1f4fdb105586e429b2c1849aac2791" -"ef73bc54603190eba39037ec057e784bb92d497e705dfcde2addb3514b4f1926f12d5440" -"850935779019b23bd0f2977a8c9478c424a7eaaeec04f3743a77bee2bec3937412e707bc" -"92a070046e2f9c35fe5cc3f755bbb91a182e683591ab7e8cff40633730546e81522f588f" -"07bdf142b78e115d2a22d2eb5664fcdb7574c1ee5ba9abd307d7d29078cd5223c222fc69" -"60324c40cc639be84dad96b01059efce7b08538ebef89bafab834609c7e82774a14e5be6" -"62067edba6111efa8ae270f5066442b17e3f31a793581c8a3f96d92921ec26981594e28a" -"08987d020b97ad2ba5c662836e35fd3fd954bcec52b579528913959d0d942fbf1c4b9910" -"ba010c3700359a4eb7616541257f0f7727cc71b580cc903f718ecc408a315b6bbfa7f6e3" -"beb9d258804bd2731ee2fb75e763281baf1effc4690a23d5f952ab5d4311d4f5885af2eb" -"f27cad9f6d84692cb903064bbd11ca751f919b4811b7722c6ec80c360521e34d357b5c8b" -"ba6d42e5c632730f53add99ab8aa9c607b6796216753086ede158bc670d04900aca66ce8" -"357bd72d19fb147b5fde8ee4df6a0184573a2e65ba3fd3a0cb04dac5eb36d17d2f639a6e" -"b602645f3ab4da9de4c9999d6506e8e242a5a3216f9e79a4202558ecdc74249ad3caaf90" -"71b4e653338b48b3ba3e9daf1e51e49384268d63f37ce87c6335de79175cdf542d661bcd" -"74b8f5107d6ab492f54b7c3c31257ecb0b426b77ed2e2ed22bbfdaf49653e1d54e5988fa" -"d71397546f9955659f22b3a4117fc823a1e87d6fb6fb8ab7d302a1316975e8baf0c0adbd" -"35455655f6a596b6ac3be7c9a8ea34166119d5e70dfbc1aa6e14ff98eff95e94ef576656" -"5d368ec8857fb0b029bcb990d420a5ca6bc7ab08053eb4dbfc4612a345d56faefc5e03a4" -"43520b224de776a5b618e1aa16edc513d5fcefcd413031b0ddc958a6fca45d108fbde065" -"3cf2d11cb00a71cd35f57993875598b4e33e2384623a0986859105d511c717c21d6534bf" -"69fd3d7cf1682e4fc25298d90df951e77a316996beac61bb7078988118c906548af92cfe" -"72cd4b102ffad584e5e721a0cdb5621ed07dda8955d84bea57a5afa4ba06289ddfac3a9e" -"765538fd9392fc7904cedb65e38cd90967f01845ff819777a22d199f608e62c13e6ba98b" -"40824b38c784bdb41d62c4014fc7e8d93be52695e975e54d1ff92b412f451177143d74a6" -"bde0ee53a986043ab465a1ef315ac4c538e775ef4178fde5f2ea560a364de18b8fe9578a" -"ad80027c3fd32dcf0967d9d03789b1cdf19040762f626289cf3af8afe5a8e0a152d9258e" -"981872c1ec95cd7f8d65812e55cb5cbd8db61b3f068a23d9652372dfbf18d43a663c5a0d" -"026b0898e383ce5c95b0ba7fb5ed6b7304c7c9d3ba64f38d1dc579465148ccfa7271f2e3" -"e0e97e9ddac7c0874f0f396cf07851638a734df393687b7b0343afd1652ff32a2da17b3a" -"4c99d79c02256c73f32625527e5666594a8a42a12135eddb022e743371b3ab7b12ad6785" -"7635eed03558ac673d17280769b2368056276d5d72f5dbc75525f8a7558bd90b544aa6cb" -"dd964e6c70be79441969bfdf471f17a2dc0c92", - "6144c4786145852e2a01b20604c369d1b9721019", -},{ - 14768, -"c9bed88d93806b89c2d028866842e6542ab88c895228c96c1f9f05125f8697c7402538b0" -"6465b7ae33daef847500f73d20c598c86e4804e633e1c4466e61f3ed1e9baadc5723bbed" -"9455a2ff4f99b852cfe6aa3442852ade0b18e4995ddab4250928165a9441de108d4a293d" -"1d95935de022aa17f366a31d4f4c4c54557a4235a9d56473444787ddc5c06c87087aef24" -"fa8280b7ac74d76ba685e4be7dc705e5a8a97c6c8fbd201ee5bf522438d23371c60c155d" -"93352f8fb8cc9421fe4b66ffabad46909c2c1099944fc55ed424c90aecca4f50d0331153" -"2e2844c3ff8ecb495de7ab26941cbf177b79ad7b05f918b713c417da8cf6e67db0a2dcee" -"a9179d8d636191759e13955f4244f0c4f2d88842e3015641ef0417d6e54144e8246e4591" -"6823e2c6e39bfa3b90b97781c44981710689f2ce20e70a26760d65f9971b291e12338461" -"8b3b56710dde2afaa2d46b0e2164d5c9482729350a0e256b2aa6b3fb099b618ebd7c11ca" -"62bdf176b502aedfdf9be57a8e4adbca4a4d6d8407984af2f6635f95a1e4930e375eb53f" -"245ab2ade5340c281bda87afded1268e537955c9819168bd60fd440533c75c9b1865e03f" -"de3a301d165f97aa6da236cf39cf3e49512f6350224f8d76ff02d0d3b9a99e5f70b23b9f" -"a85f72849fc98790df246c3a0f4437940e60d42b4317f72e2eb055d343a614f7f9648005" -"1e4dff186dff476462d9ced24dbb82eaa60cbbf6a0026e64001da36d30f529f48f3688b1" -"0ce9378ef3f50f5106e5007cd0eb037136254fda4f20d048769bd51a9d8d09a1e469a482" -"6aa0e25b6267b5a96abcb6e919a362fdd7b683d2f2dcec40ee5969311c07f6066ee22f36" -"89ca08381c85bea470040e9541e7a451cd43d62c2aa292a9dc4b95e3a7c4de2ba29663f3" -"8d5002eb64ceba6934bb1b0e2e55fba7fa706b514ebeeae1be4dd882d6512da066246a05" -"1d8bd042593bd0513e9cc47806ccdc7097e75bc75b8603834c85cd084e0ade3cc2c2b7e8" -"586eac62249f9769f5bdcd50e24e515f257548762db9adf3ee0846d67cfcd723d85d9588" -"09e6dd406f4c2637557c356fc52490a2a0763429ee298a1c72c098bb810e740c15faffc6" -"1e80cf6e18f86dc0e29bc150ce43ca71f5729356cd966277fd8b32366f6263c3a761b13d" -"544a631a25e1c4c8dea8d794abed47ccb4069d20f1dcb54e40a673ffb5f7b2eb31fb7d44" -"36fd8252f92dc35bb9a18fc55099b17e0807e79caf4f9641ee4bbbc2d6922508bcfae236" -"475bf78bc796548bc8d60659e816af68e5e43352fa64b5086c97c22c60ddcbbbefb9d9ef" -"7cd57c64454604793910f4f90aedb4fb824a86061a93bb79c9b0272a1ad0d24e8165f099" -"ef6f14a6a4fea09845f280022e061804090d7ab79f7bddcbef264b6f7d4e9971eddb9ca7" -"d0e79a8dbe7cff2fa59f514a608d66ae8c44d5e69745aa1b19995e366812064567d3ca20" -"9e12994c901d1b1f489be7253615f7c339b5581afd4d262e879ab8480ecb18990d3db61f" -"96895dcde9c065e645f52baafefcbe34d072dba373fd1c786fd56c3f3284be7260eaff9a" -"6a8348b762ed59e20ea443313b1164db53c3989c32fcae5b366f190b9548e8cff46df961" -"350369b490354ed8e530a91f5072967eff45c63540862fb2deab02b3ae05deac65414368" -"ac3549f277da92b692947de47cba9c1579526931e31c3490c1d3605f9bafcf468c2e9b47" -"981407ea40b0b59754621943095a2d4f4ba266ac545fe7447e54f69555a7ac9ff1e8f001" -"834fa65f2d4523061726e4d3bf4680519032dc21b7389e9f3229e4c2295d354482f8b803" -"b06ca3a8cb3ff786e60f6bc59dd3a5bfed63b0aa493bab78e97bbefb6633534d84de826f" -"4e2ccc3069050d50a2caace6c9de15ffc2656988d94b736e5688df0351a3a6a4c875cd99" -"ef304f3cc7a0585df2b0b3e6c62f86bba0d43de47b80c4eec1c4f98e60a36188219919cf" -"36dc10ee11e174a67d226ad9e71f02a7fca26ad67a4862773f3defc6a747545314063e5f" -"ce7a3f890ec57daa5532acfd027739832437c8a58dcbe11c2842e60e8ca64979d081fbd5" -"a1a028f59317212fb5869abc689a156171d69e4f4c93b949c3459904c00192d3603cd184" -"48d64b843c57f34aee7830f313e58e2abc41b44be46a96c845ffebcb7120e21d1d751046" -"c072adf65dd901a39c8019742054be5e159ea88d0885ee05fcd4c189bafe5abb68603186" -"5dc570b9342fa7f41fd5c1c87e68371ab19a83c82ae1d890c678102d5da8e6c29845657c" -"027ba07362cba4d24950ab38e747925e22ce8df9eaec1ae2c6d23374b360c8352feb6cb9" -"913e4fc49bde6caf5293030d0d234a8ecd616023cc668262591f812de208738e5336a9e6" -"9f9be2479b86be1e1369761518dfc93797ed3a55308878a944581eba50bc9c7f7a0e75c7" -"6a28acd95b277857726f3f684eefc215e0a696f47d65d30431d710d957c08ef96682b385" -"0ee5ba1c8417aafc1af2846a127ec155b4b7fb369e90eb3a5c3793a3389bbc6b532ca32b" -"f5e1f03c2280e71c6e1ae21312d4ff163eee16ebb1fdee8e887bb0d453829b4e6ed5fa70" -"8f2053f29b81e277be46", - "a757ead499a6ec3d8ab9814f839117354ae563c8" -} -}; - -void test_sha1(void) -{ - unsigned char buffer[4000]; - int i; - for (i=0; i < sizeof(sha1_tests) / sizeof(sha1_tests[0]); ++i) { - stb_uint len = sha1_tests[i].length / 8; - unsigned char digest[20], fdig[20]; - unsigned int h; - assert(len <= sizeof(buffer)); - assert(strlen(sha1_tests[i].message) == len*2); - assert(strlen(sha1_tests[i].digest) == 20 * 2); - for (h=0; h < len; ++h) { - char v[3]; - v[0] = sha1_tests[i].message[h*2]; - v[1] = sha1_tests[i].message[h*2+1]; - v[2] = 0; - buffer[h] = (unsigned char) strtol(v, NULL, 16); - } - stb_sha1(digest, buffer, len); - for (h=0; h < 20; ++h) { - char v[3]; - int res; - v[0] = sha1_tests[i].digest[h*2]; - v[1] = sha1_tests[i].digest[h*2+1]; - v[2] = 0; - res = digest[h] == strtol(v, NULL, 16); - c(res, sha1_tests[i].digest); - if (!res) - break; - } - { - int z; - FILE *f = fopen("data/test.bin", "wb"); - if (!f) stb_fatal("Couldn't write to test.bin"); - fwrite(buffer, len, 1, f); - fclose(f); - #ifdef _WIN32 - z = stb_sha1_file(fdig, "data/test.bin"); - if (!z) stb_fatal("Couldn't digest test.bin"); - c(memcmp(digest, fdig, 20)==0, "stb_sh1_file"); - #endif - } - } -} - - -#if 0 - -stb__obj zero, one; - -void test_packed_floats(void) -{ - stb__obj *p; - float x,y,*q; - clock_t a,b,c; - int i; - stb_float_init(); - for (i=-10; i < 10; ++i) { - float f = (float) pow(10,i); - float g = f * 10; - float delta = (g - f) / 10000; - while (f < g) { - stb__obj z = stb_float(f); - float k = stb_getfloat(z); - float p = stb_getfloat_table(z); - assert((z & 1) == 1); - assert(f == k); - assert(k == p); - f += delta; - } - } - - zero = stb_float(0); - one = stb_float(1); - - p = malloc(8192 * 4); - for (i=0; i < 8192; ++i) - p[i] = stb_rand(); - for (i=0; i < 8192; ++i) - if ((stb_rand() & 31) < 28) - p[i] = zero; - - q = malloc(4 * 1024); - - a = clock(); - - x = y = 0; - for (i=0; i < 200000000; ++i) - q[i&1023] = stb_getfloat_table(p[i&8191]); - b = clock(); - for (i=0; i < 200000000; ++i) - q[i&1023] = stb_getfloat_table2(p[i&8191]); - c = clock(); - free(p); - - free(q); - - printf("Table: %d\nIFs: %d\n", b-a, c-b); -} -#endif - - -void do_compressor(int argc,char**argv) -{ - char *p; - size_t slen; - unsigned int len; - - int window; - if (argc == 2) { - p = stb_file(argv[1], &slen); - len = (unsigned int) slen; - if (p) { - unsigned int dlen, clen = stb_compress_tofile("data/dummy.bin", p, len); - char *q = stb_decompress_fromfile("data/dummy.bin", &dlen); - - if (len != dlen) { - printf("FAILED %d -> %d\n", len, clen); - } else { - int z = memcmp(q,p,dlen); - if (z != 0) - printf("FAILED %d -> %d\n", len, clen); - else - printf("%d -> %d\n", len, clen); - } - } - return; - } - - window = atoi(argv[1]); - if (window && argc == 4) { - p = stb_file(argv[3], &slen); - len = (int) slen; - if (p) { - stb_compress_hashsize(window); - stb_compress_tofile(argv[2], p, len); - } - } else if (argc == 3) { - p = stb_decompress_fromfile(argv[2], &len); - if (p) { - FILE *f = fopen(argv[1], "wb"); - fwrite(p,1,len,f); - fclose(f); - } else { - fprintf(stderr, "FAILED.\n"); - } - } else { - fprintf(stderr, "Usage: stb \n" - " or stb \n"); - } -} - -#if 0 -// naive backtracking implementation -int wildmatch(char *expr, char *candidate) -{ - while(*expr) { - if (*expr == '?') { - if (!*candidate) return 0; - ++candidate; - ++expr; - } else if (*expr == '*') { - ++expr; - while (*expr == '*' || *expr =='?') ++expr; - // '*' at end of expression matches anything - if (!*expr) return 1; - // now scan candidate 'til first match - while (*candidate) { - if (*candidate == *expr) { - // check this candidate - if (stb_wildmatch(expr+1, candidate+1)) - return 1; - // if not, then backtrack - } - ++candidate; - } - } else { - if (*expr != *candidate) - return 0; - ++expr, ++candidate; - } - } - return *candidate != 0; -} - -int stb_matcher_find_slow(stb_matcher *m, char *str) -{ - int result = 1; - int i,j,y,z; - uint16 *previous = NULL; - uint16 *current = NULL; - uint16 *temp; - - stb_arr_setsize(previous, 4); - stb_arr_setsize(current, 4); - - previous = stb__add_if_inactive(m, previous, m->start_node); - previous = stb__eps_closure(m,previous); - if (stb__clear_goalcheck(m, previous)) - goto done; - - while (*str) { - y = stb_arr_len(previous); - for (i=0; i < y; ++i) { - stb_nfa_node *n = &m->nodes[previous[i]]; - z = stb_arr_len(n->out); - for (j=0; j < z; ++j) { - if (n->out[j].match == *str) - current = stb__add_if_inactive(m, current, n->out[j].node); - else if (n->out[j].match == -1) { - if (*str != '\n') - current = stb__add_if_inactive(m, current, n->out[j].node); - } else if (n->out[j].match < -1) { - int z = -n->out[j].match - 2; - if (m->charset[(uint8) *str] & (1 << z)) - current = stb__add_if_inactive(m, current, n->out[j].node); - } - } - } - ++str; - stb_arr_setlen(previous, 0); - - temp = previous; - previous = current; - current = temp; - - if (!m->match_start) - previous = stb__add_if_inactive(m, previous, m->start_node); - previous = stb__eps_closure(m,previous); - if (stb__clear_goalcheck(m, previous)) - goto done; - } - - result=0; - -done: - stb_arr_free(previous); - stb_arr_free(current); - - return result; -} -#endif - - - - - -#if 0 // parser generator -////////////////////////////////////////////////////////////////////////// -// -// stb_parser -// -// Generates an LR(1) parser from a grammar, and can parse with it - - - -// Symbol representations -// -// Client: Internal: -// - c=0 e aka epsilon -// - c=1 $ aka end of string -// > 0 2<=c= 0 ? encode_term(x) : encode_nonterm(x)) - -stb_bitset **compute_first(short ** productions) -{ - int i, changed; - stb_bitset **first = malloc(sizeof(*first) * num_symbols); - - assert(symset); - for (i=0; i < num_symbols; ++i) - first[i] = stb_bitset_new(0, symset); - - for (i=END; i < first_nonterm; ++i) - stb_bitset_setbit(first[i], i); - - for (i=0; i < stb_arr_len(productions); ++i) { - if (productions[i][2] == 0) { - int nt = encode_nonterm(productions[i][0]); - stb_bitset_setbit(first[nt], EPS); - } - } - - do { - changed = 0; - for (i=0; i < stb_arr_len(productions); ++i) { - int j, nt = encode_nonterm(productions[i][0]); - for (j=2; productions[i][j]; ++j) { - int z = encode_symbol(productions[i][j]); - changed |= stb_bitset_unioneq_changed(first[nt], first[z], symset); - if (!stb_bitset_testbit(first[z], EPS)) - break; - } - if (!productions[i][j] && !stb_bitset_testbit(first[nt], EPS)) { - stb_bitset_setbit(first[nt], EPS); - changed = 1; - } - } - } while (changed); - return first; -} - -stb_bitset **compute_follow(short ** productions, stb_bitset **first, int start) -{ - int i,j,changed; - stb_bitset **follow = malloc(sizeof(*follow) * num_symbols); - - assert(symset); - for (i=0; i < num_symbols; ++i) - follow[i] = (i >= first_nonterm ? stb_bitset_new(0, symset) : NULL); - - stb_bitset_setbit(follow[start], END); - do { - changed = 0; - for (i=0; i < stb_arr_len(productions); ++i) { - int nt = encode_nonterm(productions[i][0]); - for (j=2; productions[i][j]; ++j) { - if (productions[i][j] < 0) { - int k,z = encode_nonterm(productions[i][j]); - for (k=j+1; productions[i][k]; ++k) { - int q = encode_symbol(productions[i][k]); - changed |= stb_bitset_unioneq_changed(follow[z], first[q], symset); - if (!stb_bitset_testbit(first[q], EPS)) - break; - } - if (!productions[i][k] == 0) - changed |= stb_bitset_unioneq_changed(follow[z], follow[nt], symset); - } - } - } - } while (changed); - - for (i=first_nonterm; i < num_symbols; ++i) - stb_bitset_clearbit(follow[i], EPS); - - return follow; -} - -void first_for_prod_plus_sym(stb_bitset **first, stb_bitset *out, short *prod, int symbol) -{ - stb_bitset_clearall(out, symset); - for(;*prod;++prod) { - int z = encode_symbol(*prod); - stb_bitset_unioneq_changed(out, first[z], symset); - if (!stb_bitset_testbit(first[z], EPS)) - return; - } - stb_bitset_unioneq_changed(out, first[symbol], symset); -} - -#define Item(p,c,t) ((void *) (size_t) (((t) << 18) + ((c) << 12) + ((p) << 2))) -#define ItemProd(i) ((((uint32) (size_t) (i)) >> 2) & 1023) -#define ItemCursor(i) ((((uint32) (size_t) (i)) >> 12) & 63) -#define ItemLookahead(i) (((uint32) (size_t) (i)) >> 18) - -static void pc(stb_ps *p) -{ -} - -typedef struct -{ - short *prod; - int prod_num; -} ProdRef; - -typedef struct -{ - stb_bitset **first; - stb_bitset **follow; - short ** prod; - ProdRef ** prod_by_nt; -} Grammar; - -stb_ps *itemset_closure(Grammar g, stb_ps *set) -{ - stb_bitset *lookahead; - int changed,i,j,k, list_len; - if (set == NULL) return set; - lookahead = stb_bitset_new(0, symset); - do { - void **list = stb_ps_getlist(set, &list_len); - changed = 0; - for (i=0; i < list_len; ++i) { - ProdRef *prod; - int nt, *looklist; - int p = ItemProd(list[i]), c = ItemCursor(list[i]), t = ItemLookahead(list[i]); - if (g.prod[p][c] >= 0) continue; - nt = encode_nonterm(g.prod[p][c]); - first_for_prod_plus_sym(g.first, lookahead, g.prod[p]+c+1, t); - looklist = stb_bitset_getlist(lookahead, 1, first_nonterm); - - prod = g.prod_by_nt[nt]; - for (j=0; j < stb_arr_len(prod); ++j) { - assert(prod[j].prod[0] == g.prod[p][c]); - // matched production; now iterate terminals - for (k=0; k < stb_arr_len(looklist); ++k) { - void *item = Item(prod[j].prod_num,2,looklist[k]); - if (!stb_ps_find(set, item)) { - changed = 1; - set = stb_ps_add(set, item); - pc(set); - } - } - } - stb_arr_free(looklist); - } - free(list); - } while (changed); - free(lookahead); - return set; -} - -stb_ps *itemset_goto(Grammar g, stb_ps *set, int sym) -{ - int i, listlen; - void **list = stb_ps_fastlist(set, &listlen); - stb_ps *out = NULL; - for (i=0; i < listlen; ++i) { - int p,c; - if (!stb_ps_fastlist_valid(list[i])) continue; - p = ItemProd(list[i]), c = ItemCursor(list[i]); - if (encode_symbol(g.prod[p][c]) == sym) { - void *z = Item(p,c+1,ItemLookahead(list[i])); - if (!stb_ps_find(out, z)) - out = stb_ps_add(out, z); - pc(out); - } - } - return itemset_closure(g, out); -} - -void itemset_all_nextsym(Grammar g, stb_bitset *out, stb_ps *set) -{ - int i, listlen; - void **list = stb_ps_fastlist(set, &listlen); - stb_bitset_clearall(out, symset); - pc(set); - for (i=0; i < listlen; ++i) { - if (stb_ps_fastlist_valid(list[i])) { - int p = ItemProd(list[i]); - int c = ItemCursor(list[i]); - if (g.prod[p][c]) - stb_bitset_setbit(out, encode_symbol(g.prod[p][c])); - } - } -} - -stb_ps ** generate_items(Grammar g, int start_prod) -{ - stb_ps ** all=NULL; - int i,j,k; - stb_bitset *try = stb_bitset_new(0,symset); - stb_ps *set = NULL; - void *item = Item(start_prod, 2, END); - set = stb_ps_add(set, item); - pc(set); - set = itemset_closure(g, set); - pc(set); - stb_arr_push(all, set); - for (i = 0; i < stb_arr_len(all); ++i) { - // only try symbols that appear in all[i]... there's a smarter way to do this, - // which is to take all[i], and divide it up by symbol - pc(all[i]); - itemset_all_nextsym(g, try, all[i]); - for (j = 1; j < num_symbols; ++j) { - if (stb_bitset_testbit(try, j)) { - stb_ps *out; - if (stb_arr_len(all) > 4) pc(all[4]); - if (i == 1 && j == 29) { - if (stb_arr_len(all) > 4) pc(all[4]); - out = itemset_goto(g, all[i], j); - if (stb_arr_len(all) > 4) pc(all[4]); - } else - out = itemset_goto(g, all[i], j); - pc(out); - if (stb_arr_len(all) > 4) pc(all[4]); - if (out != NULL) { - // add it to the array if it's not already there - for (k=0; k < stb_arr_len(all); ++k) - if (stb_ps_eq(all[k], out)) - break; - if (k == stb_arr_len(all)) { - stb_arr_push(all, out); - pc(out); - if (stb_arr_len(all) > 4) pc(all[4]); - } else - stb_ps_delete(out); - } - } - } - } - free(try); - return all; -} - -typedef struct -{ - int num_stack; - int function; -} Reduction; - -typedef struct -{ - short *encode_term; - Reduction *reductions; - short **action_goto; // terminals are action, nonterminals are goto - int start; - int end_term; -} Parser; - -enum -{ - A_error, A_accept, A_shift, A_reduce, A_conflict -}; - -typedef struct -{ - uint8 type; - uint8 cursor; - short prod; - short value; -} Action; - -Parser *parser_create(short **productions, int num_prod, int start_nt, int end_term) -{ - short *mini_rule = malloc(4 * sizeof(mini_rule[0])); - Action *actions; - Grammar g; - stb_ps ** sets; - Parser *p = malloc(sizeof(*p)); - int i,j,n; - stb_bitset *mapped; - int min_s=0, max_s=0, termset, ntset, num_states, num_reductions, init_prod; - - int synth_start; - - // remap sparse terminals and nonterminals - - for (i=0; i < num_prod; ++i) { - for (j=2; productions[i][j]; ++j) { - if (productions[i][j] < min_s) min_s = productions[i][j]; - if (productions[i][j] > max_s) max_s = productions[i][j]; - } - } - synth_start = --min_s; - - termset = (max_s + 32) >> 5; - ntset = (~min_s + 32) >> 5; - memset(encode_term, 0, sizeof(encode_term)); - memset(encode_nonterm, 0, sizeof(encode_nonterm)); - - mapped = stb_bitset_new(0, termset); - n = 2; - for (i=0; i < num_prod; ++i) - for (j=2; productions[i][j]; ++j) - if (productions[i][j] > 0) - if (!stb_bitset_testbit(mapped, productions[i][j])) { - stb_bitset_setbit(mapped, productions[i][j]); - encode_term[productions[i][j]] = n++; - } - free(mapped); - - first_nonterm = n; - - mapped = stb_bitset_new(0, ntset); - for (i=0; i < num_prod; ++i) - for (j=2; productions[i][j]; ++j) - if (productions[i][j] < 0) - if (!stb_bitset_testbit(mapped, ~productions[i][j])) { - stb_bitset_setbit(mapped, ~productions[i][j]); - encode_nonterm[~productions[i][j]] = n++; - } - free(mapped); - - // add a special start state for internal processing - p->start = n++; - encode_nonterm[synth_start] = p->start; - mini_rule[0] = synth_start; - mini_rule[1] = -32768; - mini_rule[2] = start_nt; - mini_rule[3] = 0; - - p->end_term = end_term; - - num_symbols = n; - - // create tables - g.prod = NULL; - g.prod_by_nt = malloc(num_symbols * sizeof(g.prod_by_nt[0])); - for (i=0; i < num_symbols; ++i) - g.prod_by_nt[i] = NULL; - - for (i=0; i < num_prod; ++i) { - stb_arr_push(g.prod, productions[i]); - } - init_prod = stb_arr_len(g.prod); - stb_arr_push(g.prod, mini_rule); - - num_reductions = stb_arr_len(g.prod); - p->reductions = malloc(num_reductions * sizeof(*p->reductions)); - - symset = (num_symbols + 31) >> 5; - g.first = compute_first(g.prod); - g.follow = compute_follow(g.prod, g.first, p->start); - - for (i=0; i < stb_arr_len(g.prod); ++i) { - ProdRef pr = { g.prod[i], i }; - stb_arr_push(g.prod_by_nt[encode_nonterm(g.prod[i][0])], pr); - } - - sets = generate_items(g, init_prod); - - num_states = stb_arr_len(sets); - // now generate tables - - actions = malloc(sizeof(*actions) * first_nonterm); - p->action_goto = (short **) stb_array_block_alloc(num_states, sizeof(short) * num_symbols); - for (i=0; i < num_states; ++i) { - int j,n; - void **list = stb_ps_getlist(sets[i], &n); - memset(actions, 0, sizeof(*actions) * first_nonterm); - for (j=0; j < n; ++j) { - int p = ItemProd(list[j]), c = ItemCursor(list[j]), t = ItemLookahead(list[j]); - if (g.prod[p][c] == 0) { - if (p == init_prod) { - // @TODO: check for conflicts - assert(actions[t].type == A_error || actions[t].type == A_accept); - actions[t].type = A_accept; - } else { - // reduce production p - if (actions[t].type == A_reduce) { - // is it the same reduction we already have? - if (actions[t].prod != p) { - // no, it's a reduce-reduce conflict! - printf("Reduce-reduce conflict for rule %d and %d, lookahead %d\n", p, actions[t].prod, t); - // @TODO: use precedence - actions[t].type = A_conflict; - } - } else if (actions[t].type == A_shift) { - printf("Shift-reduce conflict for rule %d and %d, lookahead %d\n", actions[t].prod, p, t); - actions[t].type = A_conflict; - } else if (actions[t].type == A_accept) { - assert(0); - } else if (actions[t].type == A_error) { - actions[t].type = A_reduce; - actions[t].prod = p; - } - } - } else if (g.prod[p][c] > 0) { - int a = encode_symbol(g.prod[p][c]), k; - stb_ps *out = itemset_goto(g, sets[i], a); - for (k=0; k < stb_arr_len(sets); ++k) - if (stb_ps_eq(sets[k], out)) - break; - assert(k < stb_arr_len(sets)); - // shift k - if (actions[a].type == A_shift) { - if (actions[a].value != k) { - printf("Shift-shift conflict! Rule %d and %d with lookahead %d/%d\n", actions[a].prod, p, a,t); - actions[a].type = A_conflict; - } - } else if (actions[a].type == A_reduce) { - printf("Shift-reduce conflict for rule %d and %d, lookahead %d/%d\n", p, actions[a].prod, a,t); - actions[a].type = A_conflict; - } else if (actions[a].type == A_accept) { - assert(0); - } else if (actions[a].type == A_error) { - actions[a].type = A_shift; - actions[a].prod = p; - actions[a].cursor = c; - actions[a].value = k; - } - } - } - // @TODO: recompile actions into p->action_goto - } - - free(mini_rule); - stb_pointer_array_free(g.first , num_symbols); free(g.first ); - stb_pointer_array_free(g.follow, num_symbols); free(g.follow); - stb_arr_free(g.prod); - for (i=0; i < num_symbols; ++i) - stb_arr_free(g.prod_by_nt[i]); - free(g.prod_by_nt); - for (i=0; i < stb_arr_len(sets); ++i) - stb_ps_delete(sets[i]); - stb_arr_free(sets); - - return p; -} - -void parser_destroy(Parser *p) -{ - free(p); -} - -#if 0 -enum nonterm -{ - N_globals = -50, - N_global, N_vardef, N_varinitlist, N_varinit, N_funcdef, N_optid, N_optparamlist, - N_paramlist, N_param, N_optinit, N_optcomma, N_statements, N_statement, - N_optexpr, N_assign, N_if, N_ifcore, N_else, N_dictdef, N_dictdef2, - N_dictdefitem, N_expr, - N__last -}; - -short grammar[][10] = -{ - { N_globals , 0, N_globals, N_global }, - { N_globals , 0 }, - { N_global , 0, N_vardef }, - { N_global , 0, N_funcdef }, - { N_vardef , 0, ST_var, N_varinitlist, }, - { N_varinitlist, 0, N_varinitlist, ',', N_varinit }, - { N_varinitlist, 0, N_varinit, }, - { N_varinit , 0, ST_id, N_optinit, }, - { N_funcdef , 0, ST_func, N_optid, '(', N_optparamlist, ')', N_statements, ST_end }, - { N_optid , 0, ST_id }, - { N_optid , 0, }, - { N_optparamlist, 0, }, - { N_optparamlist, 0, N_paramlist, N_optcomma }, - { N_paramlist , 0, N_paramlist, ',', N_param }, - { N_paramlist , 0, N_param }, - { N_param , 0, ST_id, N_optinit }, - { N_optinit , 0, '=', N_expr }, - { N_optinit , 0, }, - { N_optcomma , 0, ',' }, - { N_optcomma , 0, }, - { N_statements , 0, N_statements, N_statement }, - { N_statement , 0, N_statement, ';' }, - { N_statement , 0, N_varinit }, - { N_statement , 0, ST_return, N_expr }, - { N_statement , 0, ST_break , N_optexpr }, - { N_optexpr , 0, N_expr }, - { N_optexpr , 0, }, - { N_statement , 0, ST_continue }, - { N_statement , 0, N_assign }, - { N_assign , 0, N_expr, '=', N_assign }, - //{ N_assign , 0, N_expr }, - { N_statement , 0, ST_while, N_expr, N_statements, ST_end }, - { N_statement , 0, ST_if, N_if, }, - { N_if , 0, N_ifcore, ST_end, }, - { N_ifcore , 0, N_expr, ST_then, N_statements, N_else, ST_end }, - { N_else , 0, ST_elseif, N_ifcore }, - { N_else , 0, ST_else, N_statements }, - { N_else , 0, }, - { N_dictdef , 0, N_dictdef2, N_optcomma }, - { N_dictdef2 , 0, N_dictdef2, ',', N_dictdefitem }, - { N_dictdef2 , 0, N_dictdefitem }, - { N_dictdefitem, 0, ST_id, '=', N_expr }, - { N_dictdefitem, 0, N_expr }, - { N_expr , 0, ST_number }, - { N_expr , 0, ST_string }, - { N_expr , 0, ST_id }, - { N_expr , 0, N_funcdef }, - { N_expr , 0, '-', N_expr }, - { N_expr , 0, '{', N_dictdef, '}' }, - { N_expr , 0, '(', N_expr, ')' }, - { N_expr , 0, N_expr, '.', ST_id }, - { N_expr , 0, N_expr, '[', N_expr, ']' }, - { N_expr , 0, N_expr, '(', N_dictdef, ')' }, -#if 0 -#define BINOP(op) { N_expr, 0, N_expr, op, N_expr } - BINOP(ST_and), BINOP(ST_or), BINOP(ST_eq), BINOP(ST_ne), - BINOP(ST_le), BINOP(ST_ge), BINOP('>') , BINOP('<' ), - BINOP('&'), BINOP('|'), BINOP('^'), BINOP('+'), BINOP('-'), - BINOP('*'), BINOP('/'), BINOP('%'), -#undef BINOP -#endif -}; - -short *grammar_list[stb_arrcount(grammar)]; - -void test_parser_generator(void) -{ - Parser *p; - int i; - assert(N__last <= 0); - for (i=0; i < stb_arrcount(grammar); ++i) - grammar_list[i] = grammar[i]; - p = parser_create(grammar_list, stb_arrcount(grammar), N_globals, 0); - parser_destroy(p); -} -#endif -#endif // parser generator - -#if 0 -// stb_threadtest.c - - -#include -#define STB_DEFINE -//#define STB_THREAD_TEST -#include "../stb.h" - -#define NUM_WORK 100 - -void *work_consumer(void *p) -{ - stb__thread_sleep(20); - return NULL; -} - -int pass; -stb_threadqueue *tq1, *tq2, *tq3, *tq4; -volatile float t1,t2; - -// with windows.h -// Worked correctly with 100,000,000 enqueue/dequeue WAITLESS -// (770 passes, 170000 per pass) -// Worked correctly with 2,500,000 enqueue/dequeue !WAITLESS -// (15 passes, 170000 per pass) -// Worked correctly with 1,500,000 enqueue/dequeue WAITLESS && STB_THREAD_TEST -// (9 passes, 170000 per pass) -// without windows.h -// Worked correctly with 1,000,000 enqueue/dequeue WAITLESS && STB_THREAD_TEST -// (6 passes, 170000 per pass) -// Worked correctly with 500,000 enqueue/dequeue !WAITLESS && STB_THREAD_TEST -// (3 passes, 170000 per pass) -// Worked correctly with 1,000,000 enqueue/dequeue WAITLESS -// (15 passes, 170000 per pass) -#define WAITLESS - -volatile int table[1000*1000*10]; - -void wait(int n) -{ -#ifndef WAITLESS - int j; - float y; - for (j=0; j < n; ++j) - y += 1 / (t1+j); - t2 = y; -#endif -} - -void *tq1_consumer(void *p) -{ - for(;;) { - int z; - float y = 0; - stb_threadq_get_block(tq1, &z); - wait(5000); - table[z] = pass; - } -} - -void *tq2_consumer(void *p) -{ - for(;;) { - int z; - if (stb_threadq_get(tq2, &z)) - table[z] = pass; - wait(1000); - } -} - -void *tq3_consumer(void *p) -{ - for(;;) { - int z; - stb_threadq_get_block(tq3, &z); - table[z] = pass; - wait(500); - } -} - -void *tq4_consumer(void *p) -{ - for (;;) { - int z; - stb_threadq_get_block(tq4, &z); - table[z] = pass; - wait(500); - } -} - -typedef struct -{ - int start, end; - stb_threadqueue *tq; - int delay; -} write_data; - -void *writer(void *q) -{ - int i; - write_data *p = (write_data *) q; - for (i=p->start; i < p->end; ++i) { - stb_threadq_add_block(p->tq, &i); - #ifndef WAITLESS - if (p->delay) stb__thread_sleep(p->delay); - else { - int j; - float z = 0; - for (j=0; j <= 20; ++j) - z += 1 / (t1+j); - t2 = z; - } - #endif - } - return NULL; -} - -write_data info[256]; -int pos; - -void start_writer(int z, int count, stb_threadqueue *tq, int delay) -{ - info[z].start = pos; - info[z].end = pos+count; - info[z].tq = tq; - info[z].delay = delay; - stb_create_thread(writer, &info[z]); - pos += count; -} - -int main(int argc, char **argv) -{ - int i; - stb_sync s = stb_sync_new(); - stb_sync_set_target(s, NUM_WORK+1); - stb_work_numthreads(2); - for (i=0; i < NUM_WORK; ++i) { - stb_work_reach(work_consumer, NULL, NULL, s); - } - printf("Started stb_work test.\n"); - - t1 = 1; - - // create the queues - tq1 = stb_threadq_new(4, 4, TRUE , TRUE); - tq2 = stb_threadq_new(4, 4, TRUE , FALSE); - tq3 = stb_threadq_new(4, 4, FALSE, TRUE); - tq4 = stb_threadq_new(4, 4, FALSE, FALSE); - - // start the consumers - stb_create_thread(tq1_consumer, NULL); - stb_create_thread(tq1_consumer, NULL); - stb_create_thread(tq1_consumer, NULL); - - stb_create_thread(tq2_consumer, NULL); - - stb_create_thread(tq3_consumer, NULL); - stb_create_thread(tq3_consumer, NULL); - stb_create_thread(tq3_consumer, NULL); - stb_create_thread(tq3_consumer, NULL); - stb_create_thread(tq3_consumer, NULL); - stb_create_thread(tq3_consumer, NULL); - stb_create_thread(tq3_consumer, NULL); - - stb_create_thread(tq4_consumer, NULL); - - for (pass=1; pass <= 5000; ++pass) { - int z = 0; - int last_n = -1; - int identical = 0; - pos = 0; - start_writer(z++, 50000, tq1, 0); - start_writer(z++, 50000, tq1, 0); - start_writer(z++, 50000, tq1, 0); - - start_writer(z++, 5000, tq2, 1); - start_writer(z++, 3000, tq2, 3); - start_writer(z++, 2000, tq2, 5); - - start_writer(z++, 5000, tq3, 3); - - start_writer(z++, 5000, tq4, 3); - #ifndef WAITLESS - stb__thread_sleep(8000); - #endif - for(;;) { - int n =0; - for (i=0; i < pos; ++i) { - if (table[i] == pass) - ++n; - } - if (n == pos) break; - if (n == last_n) { - ++identical; - if (identical == 3) { - printf("Problem slots:\n"); - for (i=0; i < pos; ++i) { - if (table[i] != pass) printf("%d ", i); - } - printf("\n"); - } else { - if (identical < 3) - printf("Processed %d of %d\n", n, pos); - else - printf("."); - } - } else { - identical = 0; - printf("Processed %d of %d\n", n, pos); - } - last_n = n; - #ifdef WAITLESS - stb__thread_sleep(750); - #else - stb__thread_sleep(3000); - #endif - } - printf("Finished pass %d\n", pass); - } - - stb_sync_reach_and_wait(s); - printf("stb_work test completed ok.\n"); - return 0; -} -#endif - - -#if 0 -////////////////////////////////////////////////////////////////////////////// -// -// collapse tree leaves up to parents until we only have N nodes -// useful for cmirror summaries - -typedef struct stb_summary_tree -{ - struct stb_summary_tree **children; - int num_children; - float weight; -} stb_summary_tree; - -STB_EXTERN void *stb_summarize_tree(void *tree, int limit, float reweight); - -#ifdef STB_DEFINE - -typedef struct stb_summary_tree2 -{ - STB__ARR(struct stb_summary_tree2 *) children; - int num_children; - float weight; - float weight_with_all_children; - float makes_target_weight; - float weight_at_target; - stb_summary_tree *original; - struct stb_summary_tree2 *target; - STB__ARR(struct stb_summary_tree2 *) targeters; -} stb_summary_tree2; - -static stb_summary_tree2 *stb__summarize_clone(stb_summary_tree *t) -{ - int i; - stb_summary_tree2 *s; - s = (stb_summary_tree2 *) malloc(sizeof(*s)); - s->original = t; - s->weight = t->weight; - s->weight_with_all_children = 0; - s->weight_at_target = 0; - s->target = NULL; - s->targeters = NULL; - s->num_children = t->num_children; - s->children = NULL; - for (i=0; i < s->num_children; ++i) - stb_arr_push(s->children, stb__summarize_clone(t->children[i])); - return s; -} - -static float stb__summarize_compute_targets(stb_summary_tree2 *parent, stb_summary_tree2 *node, float reweight, float weight) -{ - float total = 0; - if (node->weight == 0 && node->num_children == 1 && parent) { - node->target = parent; - return stb__summarize_compute_targets(parent, node->children[0], reweight, weight*reweight); - } else { - float total=0; - int i; - for (i=0; i < node->num_children; ++i) - total += stb__summarize_compute_targets(node, node->children[i], reweight, reweight); - node->weight_with_all_children = total + node->weight; - if (parent && node->weight_with_all_children) { - node->target = parent; - node->weight_at_target = node->weight_with_all_children * weight; - node->makes_target_weight = node->weight_at_target + parent->weight; - stb_arr_push(parent->targeters, node); - } else { - node->target = NULL; - node->weight_at_target = node->weight; - node->makes_target_weight = 0; - } - return node->weight_with_all_children * weight; - } -} - -static stb_summary_tree2 ** stb__summarize_make_array(STB__ARR(stb_summary_tree2 *) all, stb_summary_tree2 *tree) -{ - int i; - stb_arr_push(all, tree); - for (i=0; i < tree->num_children; ++i) - all = stb__summarize_make_array(all, tree->children[i]); - return all; -} - -typedef stb_summary_tree2 * stb__stree2; -stb_define_sort(stb__summarysort, stb__stree2, (*a)->makes_target_weight < (*b)->makes_target_weight) - -void *stb_summarize_tree(void *tree, int limit, float reweight) -{ - int i,j,k; - STB__ARR(stb_summary_tree *) ret=NULL; - STB__ARR(stb_summary_tree2 *) all=NULL; - - // first clone the tree so we can manipulate it - stb_summary_tree2 *t = stb__summarize_clone((stb_summary_tree *) tree); - if (reweight < 1) reweight = 1; - - // now compute how far up the tree each node would get pushed - // there's no value in pushing a node up to an empty node with - // only one child, so we keep pushing it up - stb__summarize_compute_targets(NULL, t, reweight, 1); - - all = stb__summarize_make_array(all, t); - - // now we want to iteratively find the smallest 'makes_target_weight', - // update that, and then fix all the others (which will be all descendents) - // to do this efficiently, we need a heap or a sorted binary tree - // what we have is an array. maybe we can insertion sort the array? - stb__summarysort(all, stb_arr_len(all)); - - for (i=0; i < stb_arr_len(all) - limit; ++i) { - stb_summary_tree2 *src, *dest; - src = all[i]; - dest = all[i]->target; - if (src->makes_target_weight == 0) continue; - assert(dest != NULL); - - for (k=0; k < stb_arr_len(all); ++k) - if (all[k] == dest) - break; - assert(k != stb_arr_len(all)); - assert(i < k); - - // move weight from all[i] to target - src->weight = dest->makes_target_weight; - src->weight = 0; - src->makes_target_weight = 0; - // recompute effect of other descendents - for (j=0; j < stb_arr_len(dest->targeters); ++j) { - if (dest->targeters[j]->weight) { - dest->targeters[j]->makes_target_weight = dest->weight + dest->targeters[j]->weight_at_target; - assert(dest->targeters[j]->makes_target_weight <= dest->weight_with_all_children); - } - } - STB_(stb__summarysort,_ins_sort)(all+i, stb_arr_len(all)-i); - } - // now the elements in [ i..stb_arr_len(all) ) are the relevant ones - for (; i < stb_arr_len(all); ++i) - stb_arr_push(ret, all[i]->original); - - // now free all our temp data - for (i=0; i < stb_arr_len(all); ++i) { - stb_arr_free(all[i]->children); - free(all[i]); - } - stb_arr_free(all); - return ret; -} -#endif - -#endif diff --git a/source/engine/thirdparty/stb/tests/stb.dsp b/source/engine/thirdparty/stb/tests/stb.dsp deleted file mode 100644 index 849b95b..0000000 --- a/source/engine/thirdparty/stb/tests/stb.dsp +++ /dev/null @@ -1,240 +0,0 @@ -# Microsoft Developer Studio Project File - Name="stb" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=stb - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "stb.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "stb.mak" CFG="stb - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "stb - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "stb - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "stb - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 - -!ELSEIF "$(CFG)" == "stb - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug\stb" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FR /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept -# SUBTRACT LINK32 /force - -!ENDIF - -# Begin Target - -# Name "stb - Win32 Release" -# Name "stb - Win32 Debug" -# Begin Source File - -SOURCE=.\grid_reachability.c -# End Source File -# Begin Source File - -SOURCE=.\stb.c -# End Source File -# Begin Source File - -SOURCE=..\stb.h -# End Source File -# Begin Source File - -SOURCE=..\stb_c_lexer.h -# End Source File -# Begin Source File - -SOURCE=..\stb_connected_components.h -# End Source File -# Begin Source File - -SOURCE=..\stb_divide.h -# End Source File -# Begin Source File - -SOURCE=..\stb_ds.h -# End Source File -# Begin Source File - -SOURCE=..\stb_dxt.h -# End Source File -# Begin Source File - -SOURCE=..\stb_easy_font.h -# End Source File -# Begin Source File - -SOURCE=..\stb_herringbone_wang_tile.h -# End Source File -# Begin Source File - -SOURCE=..\stb_image.h -# End Source File -# Begin Source File - -SOURCE=..\stb_image_write.h -# End Source File -# Begin Source File - -SOURCE=..\stb_include.h -# End Source File -# Begin Source File - -SOURCE=..\stb_leakcheck.h -# End Source File -# Begin Source File - -SOURCE=..\stb_malloc.h -# End Source File -# Begin Source File - -SOURCE=..\stb_perlin.h -# End Source File -# Begin Source File - -SOURCE=..\stb_rect_pack.h -# End Source File -# Begin Source File - -SOURCE=..\stb_sprintf.h -# End Source File -# Begin Source File - -SOURCE=.\stb_static.c -# End Source File -# Begin Source File - -SOURCE=..\stb_textedit.h -# End Source File -# Begin Source File - -SOURCE=..\stb_tilemap_editor.h -# End Source File -# Begin Source File - -SOURCE=..\stb_truetype.h -# End Source File -# Begin Source File - -SOURCE=..\stb_vorbis.c -# End Source File -# Begin Source File - -SOURCE=..\stb_voxel_render.h -# End Source File -# Begin Source File - -SOURCE=.\test_c_compilation.c -# End Source File -# Begin Source File - -SOURCE=.\test_c_lexer.c -# End Source File -# Begin Source File - -SOURCE=.\test_ds.c -# End Source File -# Begin Source File - -SOURCE=.\test_dxt.c -# End Source File -# Begin Source File - -SOURCE=.\test_easyfont.c -# End Source File -# Begin Source File - -SOURCE=.\test_image.c -# End Source File -# Begin Source File - -SOURCE=.\test_image_write.c -# End Source File -# Begin Source File - -SOURCE=.\test_packer.c -# End Source File -# Begin Source File - -SOURCE=.\test_perlin.c -# End Source File -# Begin Source File - -SOURCE=.\test_sprintf.c -# End Source File -# Begin Source File - -SOURCE=.\test_truetype.c -# End Source File -# Begin Source File - -SOURCE=.\test_vorbis.c -# End Source File -# Begin Source File - -SOURCE=.\test_voxel.c -# End Source File -# Begin Source File - -SOURCE=.\textedit_sample.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/stb.dsw b/source/engine/thirdparty/stb/tests/stb.dsw deleted file mode 100644 index eae18c8..0000000 --- a/source/engine/thirdparty/stb/tests/stb.dsw +++ /dev/null @@ -1,158 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "c_lexer_test"=.\c_lexer_test.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "herringbone"=.\herringbone.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "herringbone_map"=.\herringbone_map.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "image_test"=.\image_test.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "make_readme"=..\tools\make_readme.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "resize"=.\resize.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "stb"=.\stb.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name stb_cpp - End Project Dependency - Begin Project Dependency - Project_Dep_Name image_test - End Project Dependency - Begin Project Dependency - Project_Dep_Name c_lexer_test - End Project Dependency -}}} - -############################################################################### - -Project: "stb_cpp"=.\stb_cpp.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "stblib"=.\stblib.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "unicode"=..\tools\unicode\unicode.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "vorbseek"=.\vorbseek\vorbseek.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/source/engine/thirdparty/stb/tests/stb_c_lexer_fuzzer.cpp b/source/engine/thirdparty/stb/tests/stb_c_lexer_fuzzer.cpp deleted file mode 100644 index f6dd04a..0000000 --- a/source/engine/thirdparty/stb/tests/stb_c_lexer_fuzzer.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#define STB_C_LEX_C_DECIMAL_INTS Y -#define STB_C_LEX_C_HEX_INTS Y -#define STB_C_LEX_C_OCTAL_INTS Y -#define STB_C_LEX_C_DECIMAL_FLOATS Y -#define STB_C_LEX_C99_HEX_FLOATS Y -#define STB_C_LEX_C_IDENTIFIERS Y -#define STB_C_LEX_C_DQ_STRINGS Y -#define STB_C_LEX_C_SQ_STRINGS Y -#define STB_C_LEX_C_CHARS Y -#define STB_C_LEX_C_COMMENTS Y -#define STB_C_LEX_CPP_COMMENTS Y -#define STB_C_LEX_C_COMPARISONS Y -#define STB_C_LEX_C_LOGICAL Y -#define STB_C_LEX_C_SHIFTS Y -#define STB_C_LEX_C_INCREMENTS Y -#define STB_C_LEX_C_ARROW Y -#define STB_C_LEX_EQUAL_ARROW Y -#define STB_C_LEX_C_BITWISEEQ Y -#define STB_C_LEX_C_ARITHEQ Y - -#define STB_C_LEX_PARSE_SUFFIXES Y -#define STB_C_LEX_DECIMAL_SUFFIXES "uUlL" -#define STB_C_LEX_HEX_SUFFIXES "lL" -#define STB_C_LEX_OCTAL_SUFFIXES "lL" -#define STB_C_LEX_FLOAT_SUFFIXES "uulL" - -#define STB_C_LEX_0_IS_EOF N -#define STB_C_LEX_INTEGERS_AS_DOUBLES N -#define STB_C_LEX_MULTILINE_DSTRINGS Y -#define STB_C_LEX_MULTILINE_SSTRINGS Y -#define STB_C_LEX_USE_STDLIB N -#define STB_C_LEX_DOLLAR_IDENTIFIER Y -#define STB_C_LEX_FLOAT_NO_DECIMAL Y - -#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES Y -#define STB_C_LEX_DISCARD_PREPROCESSOR Y -#define STB_C_LEXER_DEFINITIONS - -#define STB_C_LEXER_IMPLEMENTATION -#define STB_C_LEXER_SELF_TEST -#include "../stb_c_lexer.h" -#include -#include -#include -#include - - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) -{ - if(size<3){ - return 0; - } - char *input_stream = (char *)malloc(size); - if (input_stream == NULL){ - return 0; - } - memcpy(input_stream, data, size); - - stb_lexer lex; - char *input_end = input_stream+size-1; - char *store = (char *)malloc(0x10000); - int len = 0x10000; - - stb_c_lexer_init(&lex, input_stream, input_end, store, len); - while (stb_c_lexer_get_token(&lex)) { - if (lex.token == CLEX_parse_error) { - break; - } - } - - free(input_stream); - free(store); - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/stb_cpp.cpp b/source/engine/thirdparty/stb/tests/stb_cpp.cpp deleted file mode 100644 index 65373a9..0000000 --- a/source/engine/thirdparty/stb/tests/stb_cpp.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#define WIN32_MEAN_AND_LEAN -#define WIN32_LEAN_AND_MEAN -//#include -#include -#define STB_DEFINE -#ifndef _M_AMD64 -#define STB_NPTR -#endif -#define STB_ONLY -#include "stb.h" -//#include "stb_file.h" - -int count; -void c(int truth, const char *error) -{ - if (!truth) { - fprintf(stderr, "Test failed: %s\n", error); - ++count; - } -} - -char *expects(stb_matcher *m, char *s, int result, int len, const char *str) -{ - int res2,len2=0; - res2 = stb_lex(m, s, &len2); - c(result == res2 && len == len2, str); - return s + len; -} - -void test_lex(void) -{ - stb_matcher *m = stb_lex_matcher(); - // tok_en5 .3 20.1 20. .20 .1 - char *s = (char*) "tok_en5.3 20.1 20. .20.1"; - - stb_lex_item(m, "[a-zA-Z_][a-zA-Z0-9_]*", 1 ); - stb_lex_item(m, "[0-9]*\\.?[0-9]*" , 2 ); - stb_lex_item(m, "[\r\n\t ]+" , 3 ); - stb_lex_item(m, "." , -99 ); - s=expects(m,s,1,7, "stb_lex 1"); - s=expects(m,s,2,2, "stb_lex 2"); - s=expects(m,s,3,1, "stb_lex 3"); - s=expects(m,s,2,4, "stb_lex 4"); - s=expects(m,s,3,1, "stb_lex 5"); - s=expects(m,s,2,3, "stb_lex 6"); - s=expects(m,s,3,1, "stb_lex 7"); - s=expects(m,s,2,3, "stb_lex 8"); - s=expects(m,s,2,2, "stb_lex 9"); - s=expects(m,s,0,0, "stb_lex 10"); - stb_matcher_free(m); -} - -int main(int argc, char **argv) -{ -#if 0 - char *p; - p = (char*) "abcdefghijklmnopqrstuvwxyz"; - c(stb_ischar('c', p), "stb_ischar 1"); - c(stb_ischar('x', p), "stb_ischar 2"); - c(!stb_ischar('#', p), "stb_ischar 3"); - c(!stb_ischar('X', p), "stb_ischar 4"); - p = (char*) "0123456789"; - c(!stb_ischar('c', p), "stb_ischar 5"); - c(!stb_ischar('x', p), "stb_ischar 6"); - c(!stb_ischar('#', p), "stb_ischar 7"); - c(!stb_ischar('X', p), "stb_ischar 8"); - p = (char*) "#####"; - c(!stb_ischar('c', p), "stb_ischar a"); - c(!stb_ischar('x', p), "stb_ischar b"); - c(stb_ischar('#', p), "stb_ischar c"); - c(!stb_ischar('X', p), "stb_ischar d"); - p = (char*) "xXyY"; - c(!stb_ischar('c', p), "stb_ischar e"); - c(stb_ischar('x', p), "stb_ischar f"); - c(!stb_ischar('#', p), "stb_ischar g"); - c(stb_ischar('X', p), "stb_ischar h"); -#endif - - test_lex(); - - if (count) { - _getch(); - } - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/stb_cpp.dsp b/source/engine/thirdparty/stb/tests/stb_cpp.dsp deleted file mode 100644 index 8bf9975..0000000 --- a/source/engine/thirdparty/stb/tests/stb_cpp.dsp +++ /dev/null @@ -1,98 +0,0 @@ -# Microsoft Developer Studio Project File - Name="stb_cpp" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=stb_cpp - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "stb_cpp.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "stb_cpp.mak" CFG="stb_cpp - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "stb_cpp - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "stb_cpp - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "stb_cpp - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "stb_cpp - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug\stb_cpp" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /GX /Zd /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "stb_cpp - Win32 Release" -# Name "stb_cpp - Win32 Debug" -# Begin Source File - -SOURCE=.\stb_cpp.cpp -# End Source File -# Begin Source File - -SOURCE=..\stb_vorbis.c -# End Source File -# Begin Source File - -SOURCE=.\test_cpp_compilation.cpp -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/stb_png.dict b/source/engine/thirdparty/stb/tests/stb_png.dict deleted file mode 100644 index 2a27994..0000000 --- a/source/engine/thirdparty/stb/tests/stb_png.dict +++ /dev/null @@ -1,8 +0,0 @@ -header_png="\x89PNG\x0d\x0a\x1a\x0a" - -section_idat="IDAT" -section_iend="IEND" -section_ihdr="IHDR" -section_plte="PLTE" -section_trns="tRNS" -section_cgbi="CgBI" diff --git a/source/engine/thirdparty/stb/tests/stb_static.c b/source/engine/thirdparty/stb/tests/stb_static.c deleted file mode 100644 index 07ce1f9..0000000 --- a/source/engine/thirdparty/stb/tests/stb_static.c +++ /dev/null @@ -1,12 +0,0 @@ -#define STBI_WINDOWS_UTF8 -#define STB_IMAGE_STATIC -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#define STB_IMAGE_WRITE_STATIC -#define STB_IMAGE_WRITE_IMPLEMENTATION -//#include "stb_image_write.h" - -#define STBTT_STATIC -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" diff --git a/source/engine/thirdparty/stb/tests/stbi_read_fuzzer.c b/source/engine/thirdparty/stb/tests/stbi_read_fuzzer.c deleted file mode 100644 index c25398e..0000000 --- a/source/engine/thirdparty/stb/tests/stbi_read_fuzzer.c +++ /dev/null @@ -1,28 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#define STB_IMAGE_IMPLEMENTATION - -#include "../stb_image.h" - - -int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) -{ - int x, y, channels; - - if(!stbi_info_from_memory(data, size, &x, &y, &channels)) return 0; - - /* exit if the image is larger than ~80MB */ - if(y && x > (80000000 / 4) / y) return 0; - - unsigned char *img = stbi_load_from_memory(data, size, &x, &y, &channels, 4); - - free(img); - - return 0; -} - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/stblib.dsp b/source/engine/thirdparty/stb/tests/stblib.dsp deleted file mode 100644 index c43513d..0000000 --- a/source/engine/thirdparty/stb/tests/stblib.dsp +++ /dev/null @@ -1,102 +0,0 @@ -# Microsoft Developer Studio Project File - Name="stblib" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=stblib - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "stblib.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "stblib.mak" CFG="stblib - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "stblib - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "stblib - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "stblib - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "stblib - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "stblib - Win32 Release" -# Name "stblib - Win32 Debug" -# Begin Source File - -SOURCE=.\prerelease\stb_lib.h -# End Source File -# Begin Source File - -SOURCE=..\stb_regex.h -# End Source File -# Begin Source File - -SOURCE=.\stblib_test.c -# End Source File -# Begin Source File - -SOURCE=.\stblib_test_companion.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/stblib_test.c b/source/engine/thirdparty/stb/tests/stblib_test.c deleted file mode 100644 index 9f2e176..0000000 --- a/source/engine/thirdparty/stb/tests/stblib_test.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "prerelease/stb_lib.h" -#define STB_LIB_IMPLEMENTATION -#include "prerelease/stb_lib.h" - -//#define STB_REGEX_IMPLEMENTATION -//#include "stb_regex.h" - -int main(int argc, char **argv) -{ - -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/stblib_test_companion.c b/source/engine/thirdparty/stb/tests/stblib_test_companion.c deleted file mode 100644 index 88f233c..0000000 --- a/source/engine/thirdparty/stb/tests/stblib_test_companion.c +++ /dev/null @@ -1,4 +0,0 @@ -//#include "stb_regex.h" -//#include "stb_regex.h" -#include "prerelease/stb_lib.h" -#include "prerelease/stb_lib.h" diff --git a/source/engine/thirdparty/stb/tests/stretch_test.dsp b/source/engine/thirdparty/stb/tests/stretch_test.dsp deleted file mode 100644 index dd0442c..0000000 --- a/source/engine/thirdparty/stb/tests/stretch_test.dsp +++ /dev/null @@ -1,89 +0,0 @@ -# Microsoft Developer Studio Project File - Name="stretch_test" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=stretch_test - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "stretch_test.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "stretch_test.mak" CFG="stretch_test - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "stretch_test - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "stretch_test - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "stretch_test - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\.." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "stretch_test - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "stretch_test___Win32_Debug" -# PROP BASE Intermediate_Dir "stretch_test___Win32_Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug\stretch_test" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "stretch_test - Win32 Release" -# Name "stretch_test - Win32 Debug" -# Begin Source File - -SOURCE=.\stretch_test.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tests/test.sbm b/source/engine/thirdparty/stb/tests/test.sbm deleted file mode 100644 index 9465605..0000000 --- a/source/engine/thirdparty/stb/tests/test.sbm +++ /dev/null @@ -1,60 +0,0 @@ -[link] --Xlinker advapi32.lib - -[args] --I .. -Wall -D_DEBUG - -[compilers] -#clang for x64,vcvars_2015_x64,clang --analyze -clang for x64,vcvars_2015_x64,clang -clang for x86,vcvars_2015_x86,clang --target=i386-pc-windows-msvc - -##### STATIC ANALYSIS -# -#[link] -# -#[args] -#-I .. -Wall -D_DEBUG -# -#[compilers] -#clang for x64,vcvars_2015_x64,clang --analyze -# -##### - -[link] -advapi32.lib - -[args] -/nologo -I .. -W3 -WX -D_DEBUG - -[compilers] -VS2015 for x64, vcvars_2015_x64 -VC6 , vcvars_vc6 -VS2008 for x86, vcvars_2008_x86 -VS2013 for x86, vcvars_2013_x86 -VS2015 for x86, vcvars_2015_x86 -clang-cl for x64, vcvars_2015_x64, clang-cl -clang-cl for x86, vcvars_2015_x86, clang-cl --target=i386-pc-windows-msvc -#these batch files don't path a cl executable on my machine?!? -#VS2008 for x64, vcvars_2008_x64 -#VS2013 for x64, vcvars_2013_x64 - -[projects] -c_lexer_test.c -image_test.c image_write_test.c -test_cpp_compilation.cpp stb_cpp.cpp ../stb_vorbis.c -resample_test.cpp --DTT_TEST test_c_compilation.c test_truetype.c -main.c stb.c -main.c stretchy_buffer_test.c -main.c test_c_compilation.c -main.c test_c_lexer.c -main.c test_dxt.c -main.c test_easyfont.c -main.c test_image.c -main.c test_image_write.c -main.c test_perlin.c -main.c test_sprintf.c -main.c test_vorbis.c ../stb_vorbis.c -main.c test_voxel.c -main.c textedit_sample.c diff --git a/source/engine/thirdparty/stb/tests/test_c_compilation.c b/source/engine/thirdparty/stb/tests/test_c_compilation.c deleted file mode 100644 index 8141d2b..0000000 --- a/source/engine/thirdparty/stb/tests/test_c_compilation.c +++ /dev/null @@ -1,50 +0,0 @@ -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "stb_image_resize2.h" - -#define STB_SPRINTF_IMPLEMENTATION -#include "stb_sprintf.h" - -#define STB_PERLIN_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION -#define STB_C_LEXER_IMPLEMENTATIOn -#define STB_DIVIDE_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#define STB_HERRINGBONE_WANG_TILE_IMEPLEMENTATIOn -#define STB_RECT_PACK_IMPLEMENTATION -#define STB_VOXEL_RENDER_IMPLEMENTATION -#define STB_EASY_FONT_IMPLEMENTATION -#define STB_DXT_IMPLEMENTATION -#define STB_INCLUDE_IMPLEMENTATION - -#include "stb_herringbone_wang_tile.h" -#include "stb_image.h" -#include "stb_image_write.h" -#include "stb_perlin.h" -#include "stb_c_lexer.h" -#include "stb_divide.h" -#include "stb_rect_pack.h" -#include "stb_dxt.h" -#include "stb_include.h" - -#include "stb_ds.h" - -#define STBVOX_CONFIG_MODE 1 -#include "stb_voxel_render.h" - -void STBTE_DRAW_RECT(int x0, int y0, int x1, int y1, unsigned int color) -{ -} - -void STBTE_DRAW_TILE(int x0, int y0, unsigned short id, int highlight, float *data) -{ -} - -#define STB_TILEMAP_EDITOR_IMPLEMENTATION -//#include "stb_tilemap_editor.h" // @TODO: it's broken - -int quicktest(void) -{ - char buffer[999]; - stbsp_sprintf(buffer, "test%%test"); - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/test_c_lexer.c b/source/engine/thirdparty/stb/tests/test_c_lexer.c deleted file mode 100644 index 7921b1c..0000000 --- a/source/engine/thirdparty/stb/tests/test_c_lexer.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "stb_c_lexer.h" - -#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit -#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit -#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit -#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit -#define STB_C_LEX_C99_HEX_FLOATS N // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit -#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id -#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring -#define STB_C_LEX_C_SQ_STRINGS N // single-quote-delimited strings with escapes CLEX_ssstring -#define STB_C_LEX_C_CHARS Y // single-quote-delimited character with escape CLEX_charlits -#define STB_C_LEX_C_COMMENTS Y // "/* comment */" -#define STB_C_LEX_CPP_COMMENTS Y // "// comment to end of line\n" -#define STB_C_LEX_C_COMPARISONS Y // "==" CLEX_eq "!=" CLEX_noteq "<=" CLEX_lesseq ">=" CLEX_greatereq -#define STB_C_LEX_C_LOGICAL Y // "&&" CLEX_andand "||" CLEX_oror -#define STB_C_LEX_C_SHIFTS Y // "<<" CLEX_shl ">>" CLEX_shr -#define STB_C_LEX_C_INCREMENTS Y // "++" CLEX_plusplus "--" CLEX_minusminus -#define STB_C_LEX_C_ARROW Y // "->" CLEX_arrow -#define STB_C_LEX_EQUAL_ARROW N // "=>" CLEX_eqarrow -#define STB_C_LEX_C_BITWISEEQ Y // "&=" CLEX_andeq "|=" CLEX_oreq "^=" CLEX_xoreq -#define STB_C_LEX_C_ARITHEQ Y // "+=" CLEX_pluseq "-=" CLEX_minuseq - // "*=" CLEX_muleq "/=" CLEX_diveq "%=" CLEX_modeq - // if both STB_C_LEX_SHIFTS & STB_C_LEX_ARITHEQ: - // "<<=" CLEX_shleq ">>=" CLEX_shreq - -#define STB_C_LEX_PARSE_SUFFIXES N // letters after numbers are parsed as part of those numbers, and must be in suffix list below -#define STB_C_LEX_DECIMAL_SUFFIXES "" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage -#define STB_C_LEX_HEX_SUFFIXES "" // e.g. "uUlL" -#define STB_C_LEX_OCTAL_SUFFIXES "" // e.g. "uUlL" -#define STB_C_LEX_FLOAT_SUFFIXES "" // - -#define STB_C_LEX_0_IS_EOF Y // if Y, ends parsing at '\0'; if N, returns '\0' as token -#define STB_C_LEX_INTEGERS_AS_DOUBLES N // parses integers as doubles so they can be larger than 'int', but only if STB_C_LEX_STDLIB==N -#define STB_C_LEX_MULTILINE_DSTRINGS N // allow newlines in double-quoted strings -#define STB_C_LEX_MULTILINE_SSTRINGS N // allow newlines in single-quoted strings -#define STB_C_LEX_USE_STDLIB Y // use strtod,strtol for parsing #s; otherwise inaccurate hack -#define STB_C_LEX_DOLLAR_IDENTIFIER Y // allow $ as an identifier character -#define STB_C_LEX_FLOAT_NO_DECIMAL Y // allow floats that have no decimal point if they have an exponent - -#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES N // if Y, all CLEX_ token names are defined, even if never returned - // leaving it as N should help you catch config bugs - -#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess - // still have #line, #pragma, etc) - -//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of whitespace characters if first char is whitespace - -#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions - -#include "stb_c_lexer.h" diff --git a/source/engine/thirdparty/stb/tests/test_cpp_compilation.cpp b/source/engine/thirdparty/stb/tests/test_cpp_compilation.cpp deleted file mode 100644 index d1d10b8..0000000 --- a/source/engine/thirdparty/stb/tests/test_cpp_compilation.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#define STB_IMAGE_WRITE_STATIC -#define STBIWDEF static inline - -#include "stb_image.h" -#include "stb_rect_pack.h" -#include "stb_truetype.h" -#include "stb_image_write.h" -#include "stb_c_lexer.h" -#include "stb_perlin.h" -#include "stb_dxt.h" -#include "stb_divide.h" -#include "stb_herringbone_wang_tile.h" -#include "stb_ds.h" -#include "stb_hexwave.h" - -#include "stb_sprintf.h" -#define STB_SPRINTF_IMPLEMENTATION -#include "stb_sprintf.h" - - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#define STB_TRUETYPE_IMPLEMENTATION -#define STB_PERLIN_IMPLEMENTATION -#define STB_DXT_IMPLEMENATION -#define STB_C_LEXER_IMPLEMENTATIOn -#define STB_DIVIDE_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION -#define STB_RECT_PACK_IMPLEMENTATION -#define STB_VOXEL_RENDER_IMPLEMENTATION -#define STB_CONNECTED_COMPONENTS_IMPLEMENTATION -#define STB_HEXWAVE_IMPLEMENTATION -#define STB_DS_IMPLEMENTATION -#define STBDS_UNIT_TESTS - -#define STBI_MALLOC my_malloc -#define STBI_FREE my_free -#define STBI_REALLOC my_realloc - -void *my_malloc(size_t) { return 0; } -void *my_realloc(void *, size_t) { return 0; } -void my_free(void *) { } - -#include "stb_image.h" -#include "stb_rect_pack.h" -#include "stb_truetype.h" -#include "stb_image_write.h" -#include "stb_perlin.h" -#include "stb_dxt.h" -#include "stb_divide.h" -#include "stb_herringbone_wang_tile.h" -#include "stb_ds.h" -#include "stb_hexwave.h" - -#define STBCC_GRID_COUNT_X_LOG2 10 -#define STBCC_GRID_COUNT_Y_LOG2 10 -#include "stb_connected_components.h" - -#define STBVOX_CONFIG_MODE 1 -#include "stb_voxel_render.h" - -#define STBTE_DRAW_RECT(x0,y0,x1,y1,color) do ; while(0) -#define STBTE_DRAW_TILE(x,y,id,highlight,data) do ; while(0) -#define STB_TILEMAP_EDITOR_IMPLEMENTATION -#include "stb_tilemap_editor.h" - -#include "stb_easy_font.h" - -#define STB_LEAKCHECK_IMPLEMENTATION -#include "stb_leakcheck.h" - -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "stb_image_resize2.h" - -//#include "stretchy_buffer.h" // deprecating - - -// avoid unused-function complaints -void dummy2(void) -{ - stb_easy_font_spacing(1.0); - stb_easy_font_print(0,0,NULL,NULL,NULL,0); - stb_easy_font_width(NULL); - stb_easy_font_height(NULL); -} - - -//////////////////////////////////////////////////////////// -// -// text edit - -#include -#include // memmove -#include // isspace - -#define STB_TEXTEDIT_CHARTYPE char -#define STB_TEXTEDIT_STRING text_control - -// get the base type -#include "stb_textedit.h" - -// define our editor structure -typedef struct -{ - char *string; - int stringlen; - STB_TexteditState state; -} text_control; - -// define the functions we need -void layout_func(StbTexteditRow *row, STB_TEXTEDIT_STRING *str, int start_i) -{ - int remaining_chars = str->stringlen - start_i; - row->num_chars = remaining_chars > 20 ? 20 : remaining_chars; // should do real word wrap here - row->x0 = 0; - row->x1 = 20; // need to account for actual size of characters - row->baseline_y_delta = 1.25; - row->ymin = -1; - row->ymax = 0; -} - -int delete_chars(STB_TEXTEDIT_STRING *str, int pos, int num) -{ - memmove(&str->string[pos], &str->string[pos+num], str->stringlen - (pos+num)); - str->stringlen -= num; - return 1; // always succeeds -} - -int insert_chars(STB_TEXTEDIT_STRING *str, int pos, STB_TEXTEDIT_CHARTYPE *newtext, int num) -{ - str->string = (char *) realloc(str->string, str->stringlen + num); - memmove(&str->string[pos+num], &str->string[pos], str->stringlen - pos); - memcpy(&str->string[pos], newtext, num); - str->stringlen += num; - return 1; // always succeeds -} - -// define all the #defines needed - -#define KEYDOWN_BIT 0x40000000 - -#define STB_TEXTEDIT_STRINGLEN(tc) ((tc)->stringlen) -#define STB_TEXTEDIT_LAYOUTROW layout_func -#define STB_TEXTEDIT_GETWIDTH(tc,n,i) (1) // quick hack for monospaced -#define STB_TEXTEDIT_KEYTOTEXT(key) (((key) & KEYDOWN_BIT) ? 0 : (key)) -#define STB_TEXTEDIT_GETCHAR(tc,i) ((tc)->string[i]) -#define STB_TEXTEDIT_NEWLINE '\n' -#define STB_TEXTEDIT_IS_SPACE(ch) isspace(ch) -#define STB_TEXTEDIT_DELETECHARS delete_chars -#define STB_TEXTEDIT_INSERTCHARS insert_chars - -#define STB_TEXTEDIT_K_SHIFT 0x20000000 -#define STB_TEXTEDIT_K_CONTROL 0x10000000 -#define STB_TEXTEDIT_K_LEFT (KEYDOWN_BIT | 1) // actually use VK_LEFT, SDLK_LEFT, etc -#define STB_TEXTEDIT_K_RIGHT (KEYDOWN_BIT | 2) // VK_RIGHT -#define STB_TEXTEDIT_K_UP (KEYDOWN_BIT | 3) // VK_UP -#define STB_TEXTEDIT_K_DOWN (KEYDOWN_BIT | 4) // VK_DOWN -#define STB_TEXTEDIT_K_LINESTART (KEYDOWN_BIT | 5) // VK_HOME -#define STB_TEXTEDIT_K_LINEEND (KEYDOWN_BIT | 6) // VK_END -#define STB_TEXTEDIT_K_TEXTSTART (STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_TEXTEND (STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_DELETE (KEYDOWN_BIT | 7) // VK_DELETE -#define STB_TEXTEDIT_K_BACKSPACE (KEYDOWN_BIT | 8) // VK_BACKSPACE -#define STB_TEXTEDIT_K_UNDO (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'z') -#define STB_TEXTEDIT_K_REDO (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'y') -#define STB_TEXTEDIT_K_INSERT (KEYDOWN_BIT | 9) // VK_INSERT -#define STB_TEXTEDIT_K_WORDLEFT (STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_WORDRIGHT (STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_PGUP (KEYDOWN_BIT | 10) // VK_PGUP -- not implemented -#define STB_TEXTEDIT_K_PGDOWN (KEYDOWN_BIT | 11) // VK_PGDOWN -- not implemented - -#define STB_TEXTEDIT_IMPLEMENTATION -#include "stb_textedit.h" - - -void dummy3(void) -{ - stb_textedit_click(0,0,0,0); - stb_textedit_drag(0,0,0,0); - stb_textedit_cut(0,0); - stb_textedit_key(0,0,0); - stb_textedit_initialize_state(0,0); - stb_textedit_paste(0,0,0,0); -} - -#include "stb_c_lexer.h" diff --git a/source/engine/thirdparty/stb/tests/test_ds.c b/source/engine/thirdparty/stb/tests/test_ds.c deleted file mode 100644 index fffff8d..0000000 --- a/source/engine/thirdparty/stb/tests/test_ds.c +++ /dev/null @@ -1,1034 +0,0 @@ -#ifdef DS_PERF -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NON_CONFORMING_SWPRINTFS - - -//#define STBDS_INTERNAL_SMALL_BUCKET // make 64-bit bucket fit both keys and hash bits -//#define STBDS_SIPHASH_2_4 // performance test 1_3 against 2_4 -//#define STBDS_INTERNAL_BUCKET_START // don't bother offseting differently within bucket for different hash values -//#define STBDS_FLUSH_CACHE (1u<<20) // do this much memory traffic to flush the cache between some benchmarking measurements - -#include - -#define WIN32_LEAN_AND_MEAN -#include -#define STB_DEFINE -#define STB_NO_REGISTRY -#include "../stb.h" -#endif - -#ifdef DS_TEST -#define STBDS_UNIT_TESTS -#define STBDS_SMALL_BUCKET -#endif - -#ifdef DS_STATS -#define STBDS_STATISTICS -#endif - -#ifndef DS_PERF -#define STBDS_ASSERT assert -#include -#endif - -#define STB_DS_IMPLEMENTATION -#include "../stb_ds.h" - -size_t churn_inserts, churn_deletes; - -void churn(int a, int b, int count) -{ - struct { int key,value; } *map=NULL; - int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i,i+1); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - assert(k != 0); - } - assert(hmlen(map) == a); - } - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; -} - -#ifdef DS_TEST -#include -int main(int argc, char **argv) -{ - char *temp=NULL; - stbds_unit_tests(); - arrins(temp, 0, 'a'); - arrins(temp, arrlen(temp), 'b'); - churn(0,100,1); - churn(3,7,50000); - churn(3,15,50000); - churn(16, 48, 25000); - churn(10, 15, 25000); - churn(200,500, 5000); - churn(2000,5000, 500); - churn(20000,50000, 50); - printf("Ok!"); - return 0; -} -#endif - -#ifdef DS_STATS -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -size_t max_hit_probes, max_miss_probes, total_put_probes, total_miss_probes, churn_misses; -void churn_stats(int a, int b, int count) -{ - struct { int key,value; } *map=NULL; - int i,j,n,k; - churn_misses = 0; - for (i=0; i < a; ++i) { - hmput(map,i,i+1); - max_hit_probes = MAX(max_hit_probes, stbds_hash_probes); - total_put_probes += stbds_hash_probes; - stbds_hash_probes = 0; - } - - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - max_hit_probes = MAX(max_hit_probes, stbds_hash_probes); - total_put_probes += stbds_hash_probes; - stbds_hash_probes = 0; - } - for (j=0; j < (b-a)*10; ++j) { - k=i+j; - (void) hmgeti(map,k); // miss - max_miss_probes = MAX(max_miss_probes, stbds_hash_probes); - total_miss_probes += stbds_hash_probes; - stbds_hash_probes = 0; - ++churn_misses; - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - stbds_hash_probes = 0; - assert(k); - } - assert(hmlen(map) == a); - } - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; -} - -void reset_stats(void) -{ - stbds_array_grow=0, - stbds_hash_grow=0; - stbds_hash_shrink=0; - stbds_hash_rebuild=0; - stbds_hash_probes=0; - stbds_hash_alloc=0; - stbds_rehash_probes=0; - stbds_rehash_items=0; - max_hit_probes = 0; - max_miss_probes = 0; - total_put_probes = 0; - total_miss_probes = 0; -} - -void print_churn_probe_stats(char *str) -{ - printf("Probes: %3d max hit, %3d max miss, %4.2f avg hit, %4.2f avg miss: %s\n", - (int) max_hit_probes, (int) max_miss_probes, (float) total_put_probes / churn_inserts, (float) total_miss_probes / churn_misses, str); - reset_stats(); -} - -int main(int arg, char **argv) -{ - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - return 0; -} -#endif - - -#ifdef DS_PERF -//char *strdup(const char *foo) { return 0; } -//int stricmp(const char *a, const char *b) { return 0; } -//int strnicmp(const char *a, const char *b, size_t n) { return 0; } - -unsigned __int64 t0, xsum, mn,mx,count; -void begin(void) -{ - LARGE_INTEGER m; - QueryPerformanceCounter(&m); - t0 = m.QuadPart; - xsum = 0; - count = 0; - mx = 0; - mn = ~(unsigned __int64) 0; -} - -void measure(void) -{ - unsigned __int64 t1, t; - LARGE_INTEGER m; - QueryPerformanceCounter(&m); - t1 = m.QuadPart; - t = t1-t0; - if (t1 < t0) - printf("ALERT: QueryPerformanceCounter was unordered!\n"); - if (t < mn) mn = t; - if (t > mx) mx = t; - xsum += t; - ++count; - t0 = t1; -} - -void dont_measure(void) -{ - LARGE_INTEGER m; - QueryPerformanceCounter(&m); - t0 = m.QuadPart; -} - -double timer; -double end(void) -{ - LARGE_INTEGER m; - QueryPerformanceFrequency(&m); - - if (count > 3) { - // discard the highest and lowest - xsum -= mn; - xsum -= mx; - count -= 2; - } - timer = (double) (xsum) / count / m.QuadPart * 1000; - return timer; -} - -void build(int a, int b, int count, int step) -{ - struct { int key,value; } *map=NULL; - int i,n; - for (i=0; i < a; ++i) { - n = i*step; - hmput(map,n,i+1); - } - measure(); - churn_inserts = i; - hmfree(map); - dont_measure(); -} - -#ifdef STB__INCLUDE_STB_H -void build_stb(int a, int b, int count, int step) -{ - stb_idict *d = stb_idict_new_size(8); - int i; - for (i=0; i < a; ++i) - stb_idict_add(d, i*step, i+1); - measure(); - churn_inserts = i; - stb_idict_destroy(d); - dont_measure(); -} - -void multibuild_stb(int a, int b, int count, int step, int tables) -{ - stb_idict *d[50000]; - int i,q; - for (q=0; q < tables; ++q) - d[q] = stb_idict_new_size(8); - dont_measure(); - for (i=0; i < a; ++i) - for (q=0; q < tables; ++q) - stb_idict_add(d[q], i*step+q*771, i+1); - measure(); - churn_inserts = i; - for (q=0; q < tables; ++q) - stb_idict_destroy(d[q]); - dont_measure(); -} - -int multisearch_stb(int a, int start, int end, int step, int tables) -{ - stb_idict *d[50000]; - int i,q,total=0,v; - for (q=0; q < tables; ++q) - d[q] = stb_idict_new_size(8); - for (q=0; q < tables; ++q) - for (i=0; i < a; ++i) - stb_idict_add(d[q], i*step+q*771, i+1); - dont_measure(); - for (i=start; i < end; ++i) - for (q=0; q < tables; ++q) - if (stb_idict_get_flag(d[q], i*step+q*771, &v)) - total += v; - measure(); - churn_inserts = i; - for (q=0; q < tables; ++q) - stb_idict_destroy(d[q]); - dont_measure(); - return total; -} -#endif - -int multisearch(int a, int start, int end, int step, int tables) -{ - struct { int key,value; } *hash[50000]; - int i,q,total=0; - for (q=0; q < tables; ++q) - hash[q] = NULL; - for (q=0; q < tables; ++q) - for (i=0; i < a; ++i) - hmput(hash[q], i*step+q*771, i+1); - dont_measure(); - for (i=start; i < end; ++i) - for (q=0; q < tables; ++q) - total += hmget(hash[q], i*step+q*771); - measure(); - churn_inserts = i; - for (q=0; q < tables; ++q) - hmfree(hash[q]); - dont_measure(); - return total; -} - -void churn_skip(unsigned int a, unsigned int b, int count) -{ - struct { unsigned int key,value; } *map=NULL; - unsigned int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i,i+1); - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - assert(k != 0); - } - assert(hmlen(map) == a); - } - measure(); - churn_inserts = i; - churn_deletes = (b-a) * n; - hmfree(map); - dont_measure(); -} - -typedef struct { int n[8]; } str32; -void churn32(int a, int b, int count, int include_startup) -{ - struct { str32 key; int value; } *map=NULL; - int i,j,n; - str32 key = { 0 }; - for (i=0; i < a; ++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - key.n[0] = i-j-1; - hmdel(map,key); - } - assert(hmlen(map) == a); - } - measure(); - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; - dont_measure(); -} - -typedef struct { int n[32]; } str256; -void churn256(int a, int b, int count, int include_startup) -{ - struct { str256 key; int value; } *map=NULL; - int i,j,n; - str256 key = { 0 }; - for (i=0; i < a; ++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - key.n[0] = i-j-1; - hmdel(map,key); - } - assert(hmlen(map) == a); - } - measure(); - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; - dont_measure(); -} - -void churn8(int a, int b, int count, int include_startup) -{ - struct { size_t key,value; } *map=NULL; - int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i,i+1); - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - assert(k != 0); - } - assert(hmlen(map) == a); - } - measure(); - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; - dont_measure(); -} - -void multichurn4(int a, int b, int count, int include_startup, int tables) -{ - struct { int key,value; } *map[50000]; - int i,j,n,k,q; - for (q=0; q < tables; ++q) - map[q] = NULL; - dont_measure(); - - for (i=0; i < a; ++i) - for (q=0; q < tables; ++q) - hmput(map[q],i,i+1); - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - for (q=0; q < tables; ++q) - hmput(map[q],i,i+1); - } - assert(hmlen(map[0]) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - for (q=0; q < tables; ++q) - k = hmdel(map[q],k); - assert(k != 0); - } - assert(hmlen(map[0]) == a); - } - measure(); - for (q=0; q < tables; ++q) - hmfree(map[q]); - churn_inserts = i * tables; - churn_deletes = (b-a) * n * tables; - dont_measure(); -} - -struct { - unsigned __int64 start; - unsigned __int64 end; - int table_size; -} mstats[32][4000]; - -const int first_step = 64; -const int last_step = 384-48; // 32M - -void measure_build4(int step_log2) -{ - double length; - int i,j,k=0; - int step = 1 << step_log2; - unsigned __int64 t0,t1; - struct { int key,value; } *map=NULL; - double rdtsc_scale; - begin(); - t0 = __rdtsc(); - - mstats[0][0].start = __rdtsc(); - for (i=0; i < 256; ++i) { - hmput(map,k,k+1); - k += step; - } - mstats[0][first_step-1].end = __rdtsc(); - mstats[0][first_step-1].table_size = k >> step_log2; - for (j=first_step; j < last_step; ++j) { - for (i=0; i < (1<<(j>>4)); ++i) { - hmput(map, k,k+1); - k += step; - } - mstats[0][j].end = __rdtsc(); - mstats[0][j].table_size = k >> step_log2; - } - t1 = __rdtsc(); - measure(); - hmfree(map); - length = end(); - rdtsc_scale = length / (t1-t0) * 1000; - - for (j=1; j < last_step; ++j) - mstats[0][j].start = mstats[0][0].start; - for (j=first_step-1; j < last_step; ++j) { - printf("%12.4f,%12d,%12d,0,0,0\n", (mstats[0][j].end - mstats[0][j].start) * rdtsc_scale, mstats[0][j].table_size, mstats[0][j].table_size); - } -} - -#ifdef STBDS_FLUSH_CACHE -static int cache_index; -char dummy[8][STBDS_FLUSH_CACHE]; - -int flush_cache(void) -{ - memmove(dummy[cache_index],dummy[cache_index]+1, sizeof(dummy[cache_index])-1); - cache_index = (cache_index+1)%8; - return dummy[cache_index][0]; -} -#else -int flush_cache(void) { return 0; } -#endif - -int measure_average_lookup4(int step_log2) -{ - int total; - double length; - int i,j,k=0,q; - int step = 1 << step_log2; - unsigned __int64 t0,t1; - struct { int key,value; } *map=NULL; - double rdtsc_scale; - begin(); - t0 = __rdtsc(); - - for (i=0; i < 128; ++i) { - hmput(map,k,k+1); - k += step; - } - for (j=first_step; j <= last_step; ++j) { - total += flush_cache(); - mstats[0][j].start = __rdtsc(); - for (q=i=0; i < 50000; ++i) { - total += hmget(map, q); // hit - if (++q == k) q = 0; - } - mstats[0][j].end = __rdtsc(); - mstats[0][j].table_size = k; - total += flush_cache(); - mstats[1][j].start = __rdtsc(); - for (i=0; i < 50000; ++i) { - total += hmget(map, i+k); // miss - } - mstats[1][j].end = __rdtsc(); - mstats[1][j].table_size = k; - - // expand table - for (i=0; i < (1<<(j>>4)); ++i) { - hmput(map, k,k+1); - k += step; - } - } - - t1 = __rdtsc(); - measure(); - hmfree(map); - length = end(); - rdtsc_scale = length / (t1-t0) * 1000; - - for (j=first_step; j <= last_step; ++j) { - // time,table_size,numins,numhit,nummiss,numperflush - printf("%12.4f,%12d,0,50000,0,0\n", (mstats[0][j].end - mstats[0][j].start) * rdtsc_scale, mstats[0][j].table_size); - } - for (j=first_step; j <= last_step; ++j) { - printf("%12.4f,%12d,0,0,50000,0\n", (mstats[1][j].end - mstats[1][j].start) * rdtsc_scale, mstats[1][j].table_size); - } - return total; -} - -int measure_worst_lookup4_a(int step_log2) -{ - int total; - double length; - int i,j,k=0,q,worst_q,n,z,attempts; - int step = 1 << step_log2; - unsigned __int64 t0,t1; - unsigned __int64 m0,m1,worst; - struct { int key,value; } *map=NULL; - double rdtsc_scale; - begin(); - t0 = __rdtsc(); - - memset(mstats, 0, sizeof(mstats)); - for (j=first_step; j <= last_step; ++j) - mstats[0][j].end = mstats[1][j].end = ~(unsigned __int64) 0; - - for(attempts=0; attempts < 2; ++attempts) { - k = 0; - stbds_rand_seed(0); // force us to get the same table every time - for (i=0; i < 128; ++i) { - hmput(map,k,k+1); - k += step; - } - for (j=first_step; j <= last_step; ++j) { - unsigned __int64 times[32]; - - // find the worst hit time - for (z=0; z < 2; ++z) { // try the bisectioning measurement 4 times - worst = 0; - for (n=0; n < 10; ++n) { // test 400 keys total - // find the worst time to hit 20 keys - q=0; - worst_q = 0; - total += flush_cache(); - m0 = __rdtsc(); - for (i=0; i < 20; ++i) { - total += hmget(map, q); // hit - if (++q == k) q = 0; - } - m1 = __rdtsc(); - // for each n, check if this is the worst lookup we've seen - if (m1 - m0 > worst) { - worst = m1-m0; - worst_q = q - i; - if (worst_q < 0) q += k; - } - } - // after 400 keys, take the worst 20 keys, and try each one - worst = 0; - q = worst_q; - for (i=0; i < 20; ++i) { - total += flush_cache(); - m0 = __rdtsc(); - total += hmget(map, q); // hit - m1 = __rdtsc(); - if (m1 - m0 > worst) - worst = m1-m0; - if (++q == k) q = 0; - } - times[z] = worst; - } - // find the worst time in the bunch - worst = 0; - for (i=0; i < z; ++i) - if (times[i] > worst) - worst = times[i]; - // take the best of 'attempts', to discard outliers - if (worst < mstats[0][j].end) - mstats[0][j].end = worst; - mstats[0][j].start = 0; - mstats[0][j].table_size = k >> step_log2; - - // find the worst miss time - for (z=0; z < 8; ++z) { // try the bisectioning measurement 8 times - worst = 0; - for (n=0; n < 20; ++n) { // test 400 keys total - // find the worst time to hit 20 keys - q=k; - worst_q = 0; - total += flush_cache(); - m0 = __rdtsc(); - for (i=0; i < 20; ++i) { - total += hmget(map, q); // hit - } - m1 = __rdtsc(); - // for each n, check if this is the worst lookup we've seen - if (m1 - m0 > worst) { - worst = m1-m0; - worst_q = q - i; - } - } - // after 400 keys, take the worst 20 keys, and try each one - worst = 0; - q = worst_q; - for (i=0; i < 20; ++i) { - total += flush_cache(); - m0 = __rdtsc(); - total += hmget(map, q); // hit - m1 = __rdtsc(); - if (m1 - m0 > worst) - worst = m1-m0; - } - times[z] = worst; - } - // find the worst time in the bunch - worst = 0; - for (i=0; i < z; ++i) - if (times[i] > worst) - worst = times[i]; - if (worst < mstats[1][j].end) - mstats[1][j].end = worst; - mstats[1][j].start = 0; - mstats[1][j].table_size = k >> step_log2; - - // expand table - for (i=0; i < (1<<(j>>4)); ++i) { - hmput(map, k,k+1); - k += step; - } - } - hmfree(map); - } - - t1 = __rdtsc(); - measure(); - length = end(); - rdtsc_scale = length / (t1-t0) * 1000; - - for (j=first_step; j <= last_step; ++j) { - printf("%12.4f,%12d,0,1,0,1\n", (mstats[0][j].end - mstats[0][j].start) * rdtsc_scale, mstats[0][j].table_size); - } - for (j=first_step; j <= last_step; ++j) { - printf("%12.4f,%12d,0,0,1,1\n", (mstats[1][j].end - mstats[1][j].start) * rdtsc_scale, mstats[1][j].table_size); - } - return total; -} - -int measure_worst_lookup4_b(int step_log2) -{ - int total; - double length; - int i,j,k=0,q,worst_q,n,z,attempts; - int step = 1 << step_log2; - unsigned __int64 t0,t1; - unsigned __int64 m0,m1,worst; - struct { int key,value; } *map=NULL; - double rdtsc_scale; - begin(); - t0 = __rdtsc(); - - memset(mstats, 0, sizeof(mstats)); - for (j=first_step; j <= last_step; ++j) - mstats[0][j].end = mstats[1][j].end = ~(unsigned __int64) 0; - - k = 0; - stbds_rand_seed(0); // force us to get the same table every time - for (i=0; i < 128; ++i) { - hmput(map,k,k+1); - k += step; - } - for (j=first_step; j <= last_step; ++j) { - unsigned __int64 times[32]; - - // find the worst hit time - for (z=0; z < 8; ++z) { // try this 8 times - worst = 0; - q=0; - for (i=0; i < 5000; ++i) { - total += hmget(map, q); - m0 = __rdtsc(); - total += hmget(map, q); - m1 = __rdtsc(); - if (m1 - m0 > worst) { - worst = m1-m0; - worst_q = q - i; - } - if (++q == k) q = 0; - } - // now retry with the worst one, but find the shortest time for it - worst = ~(unsigned __int64) 0; - for (i=0; i < 4; ++i) { - total += flush_cache(); - m0 = __rdtsc(); - total += hmget(map,worst_q); - m1 = __rdtsc(); - if (m1-m0 < worst) - worst = m1-m0; - } - times[z] = worst; - } - - // find the worst of those - worst = 0; - for (i=0; i < z; ++i) - if (times[i] > worst) - worst = times[i]; - mstats[0][j].start = 0; - mstats[0][j].end = worst; - mstats[0][j].table_size = k; - - // find the worst miss time - for (z=0; z < 8; ++z) { // try this 8 times - worst = 0; - q=k; - for (i=0; i < 5000; ++i) { - total += hmget(map, q); - m0 = __rdtsc(); - total += hmget(map, q); - m1 = __rdtsc(); - if (m1 - m0 > worst) { - worst = m1-m0; - worst_q = q - i; - } - //printf("%6llu ", m1-m0); - } - // now retry with the worst one, but find the shortest time for it - worst = ~(unsigned __int64) 0; - for (i=0; i < 4; ++i) { - total += flush_cache(); - m0 = __rdtsc(); - total += hmget(map,worst_q); - m1 = __rdtsc(); - if (m1-m0 < worst) - worst = m1-m0; - } - times[z] = worst; - } - - // find the worst of those - worst = 0; - for (i=0; i < z; ++i) - if (times[i] > worst) - worst = times[i]; - mstats[1][j].start = 0; - mstats[1][j].end = worst; - mstats[1][j].table_size = k; - - // expand table - for (i=0; i < (1<<(j>>4)); ++i) { - hmput(map, k,k+1); - k += step; - } - } - hmfree(map); - - t1 = __rdtsc(); - measure(); - length = end(); - rdtsc_scale = length / (t1-t0) * 1000; - - for (j=first_step+1; j <= last_step; ++j) { - printf("%12.4f,%12d,0,1,0,1\n", (mstats[0][j].end - mstats[0][j].start) * rdtsc_scale, mstats[0][j].table_size); - } - for (j=first_step+1; j <= last_step; ++j) { - printf("%12.4f,%12d,0,0,1,1\n", (mstats[1][j].end - mstats[1][j].start) * rdtsc_scale, mstats[1][j].table_size); - } - return total; -} - -int measure_uncached_lookup4(int step_log2) -{ - int total; - double length; - int i,j,k=0,q; - int step = 1 << step_log2; - unsigned __int64 t0,t1; - struct { int key,value; } *map=NULL; - double rdtsc_scale; - begin(); - t0 = __rdtsc(); - - map = NULL; - for (i=0; i < 128; ++i) { - hmput(map,k,k+1); - k += step; - } - for (j=first_step; j <= last_step; ++j) { - mstats[0][j].start = __rdtsc(); - mstats[0][j].end = 0; - for (q=i=0; i < 512; ++i) { - if ((i & 3) == 0) { - mstats[0][j].end += __rdtsc(); - total += flush_cache(); - mstats[0][j].start += __rdtsc(); - } - total += hmget(map, q); // hit - if (++q == k) q = 0; - } - mstats[0][j].end += __rdtsc(); - mstats[0][j].table_size = k; - total += flush_cache(); - mstats[1][j].end = 0; - mstats[1][j].start = __rdtsc(); - for (i=0; i < 512; ++i) { - if ((i & 3) == 0) { - mstats[1][j].end += __rdtsc(); - total += flush_cache(); - mstats[1][j].start += __rdtsc(); - } - total += hmget(map, i+k); // miss - } - mstats[1][j].end += __rdtsc(); - mstats[1][j].table_size = k; - - // expand table - for (i=0; i < (1<<(j>>4)); ++i) { - hmput(map, k,k+1); - k += step; - } - } - hmfree(map); - - t1 = __rdtsc(); - measure(); - length = end(); - rdtsc_scale = length / (t1-t0) * 1000; - - for (j=first_step; j <= last_step; ++j) { - printf("%12.4f,%12d,0,512,0,4\n", (mstats[0][j].end - mstats[0][j].start) * rdtsc_scale, mstats[0][j].table_size); - } - for (j=first_step; j <= last_step; ++j) { - printf("%12.4f,%12d,0,0,512,4\n", (mstats[1][j].end - mstats[1][j].start) * rdtsc_scale, mstats[1][j].table_size); - } - return total; -} - - - - -int main(int arg, char **argv) -{ - int n,s,w; - double worst = 0; - - printf("# size_t=%d,", (int) sizeof(size_t)); - -// number of cache-lines -#ifdef STBDS_SMALL_BUCKET - printf("cacheline=%d,", 1); -#else - printf("cacheline=%d,", sizeof(size_t)==8 ? 2 : 1); -#endif -#ifdef STBDS_FLUSH_CACHE - printf("%d,", (int) stbds_log2(STBDS_FLUSH_CACHE)); -#else - printf("0,"); -#endif -#ifdef STBDS_BUCKET_START // don't bother offseting differently within bucket for different hash values - printf("STBDS_BUCKET_START,"); -#else - printf(","); -#endif -#ifdef STBDS_SIPHASH_2_4 - printf("STBDS_SIPHASH_2_4,"); -#else - printf(","); -#endif - printf("\n"); - - measure_worst_lookup4_b(0); - //measure_worst_lookup4_a(0); - measure_average_lookup4(0); - measure_uncached_lookup4(0); - measure_build4(0); - return 0; - -#if 0 - begin(); for (n=0; n < 2000; ++n) { build_stb(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table\n", timer); - begin(); for (n=0; n < 500; ++n) { build_stb(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table\n", timer); - begin(); for (n=0; n < 100; ++n) { build_stb(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table\n", timer); - begin(); for (n=0; n < 10; ++n) { build_stb(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table\n", timer); - begin(); for (n=0; n < 5; ++n) { build_stb(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table\n", timer); -#endif - -#if 0 - begin(); for (n=0; n < 2000; ++n) { churn32(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { churn32(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { churn32(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { churn32(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { churn32(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 32-byte key\n", timer); - - begin(); for (n=0; n < 2000; ++n) { churn256(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { churn256(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { churn256(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { churn256(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { churn256(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 256-byte key\n", timer); -#endif - - begin(); for (n=0; n < 20; ++n) { multisearch_stb(2000,0,2000,1,1000); } end(); printf(" // %7.2fms : 2,000,000 hits on 1,000 2K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { multisearch_stb(20000,0,2000,1,1000); } end(); printf(" // %7.2fms : 2,000,000 hits on 1,000 20K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 6; ++n) { multisearch_stb(200000,0,2000,1,1000); } end(); printf(" // %7.2fms : 2,000,000 hits on 1,000 200K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multisearch_stb(2000000,0,20000,1,100); } end(); printf(" // %7.2fms : 2,000,000 hits on 100 2M table w/ 4-byte key\n", timer); - - begin(); for (n=0; n < 20; ++n) { multisearch (2000,0,2000,1,1000); } end(); printf(" // %7.2fms : 2,000,000 hits on 1,000 2K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { multisearch (20000,0,2000,1,1000); } end(); printf(" // %7.2fms : 2,000,000 hits on 1,000 20K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 6; ++n) { multisearch (200000,0,2000,1,1000); } end(); printf(" // %7.2fms : 2,000,000 hits on 1,000 200K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multisearch (2000000,0,20000,1,100); } end(); printf(" // %7.2fms : 2,000,000 hits on 100 2M table w/ 4-byte key\n", timer); - - -#if 1 - begin(); for (n=0; n < 2; ++n) { multibuild_stb(2000,0,0,1,10000); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 10,000 2K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multibuild_stb(20000,0,0,1,1000); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 1,000 20K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multibuild_stb(200000,0,0,1,100); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 100 200K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multibuild_stb(2000000,0,0,1,10); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 10 2M table w/ 4-byte key\n", timer); - - begin(); for (n=0; n < 2; ++n) { multichurn4(2000,0,0,1,10000); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 10,000 2K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multichurn4(20000,0,0,1,1000); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 1,000 20K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multichurn4(200000,0,0,1,100); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 100 200K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 2; ++n) { multichurn4(2000000,0,0,1,10); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 10 2M table w/ 4-byte key\n", timer); -#endif - - begin(); for (n=0; n < 2000; ++n) { build(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { build(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { build(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { build(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { build(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 4-byte key\n", timer); - - begin(); for (n=0; n < 2000; ++n) { churn8(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { churn8(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { churn8(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { churn8(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { churn8(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 8-byte key\n", timer); - - begin(); for (n=0; n < 60; ++n) { churn_skip(2000,2100,5000); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2K table\n", timer); - begin(); for (n=0; n < 30; ++n) { churn_skip(20000,21000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20K table\n", timer); - begin(); for (n=0; n < 15; ++n) { churn_skip(200000,201000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 200K table\n", timer); - begin(); for (n=0; n < 8; ++n) { churn_skip(2000000,2001000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2M table\n", timer); - begin(); for (n=0; n < 5; ++n) { churn_skip(20000000,20001000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20M table\n", timer); - begin(); for (n=0; n < 1; ++n) { churn_skip(200000000u,200001000u,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 200M table\n", timer); - // even though the above measures a roughly fixed amount of work, we still have to build the table n times, hence the fewer measurements each time - - begin(); for (n=0; n < 60; ++n) { churn_skip(1000,3000,250); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2K table\n", timer); - begin(); for (n=0; n < 15; ++n) { churn_skip(10000,30000,25); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20K table\n", timer); - begin(); for (n=0; n < 7; ++n) { churn_skip(100000,300000,10); } end(); printf(" // %7.2fms : 2,000,000 inserts & deletes in 200K table\n", timer); - begin(); for (n=0; n < 2; ++n) { churn_skip(1000000,3000000,10); } end(); printf(" // %7.2fms : 20,000,000 inserts & deletes in 2M table\n", timer); - - // search for bad intervals.. in practice this just seems to measure execution variance - for (s = 2; s < 64; ++s) { - begin(); for (n=0; n < 50; ++n) { build(200000,0,0,s); } end(); - if (timer > worst) { - worst = timer; - w = s; - } - } - for (; s <= 1024; s *= 2) { - begin(); for (n=0; n < 50; ++n) { build(200000,0,0,s); } end(); - if (timer > worst) { - worst = timer; - w = s; - } - } - printf(" // %7.2fms(%d) : Worst time from inserting 200,000 items with spacing %d.\n", worst, w, w); - - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/test_ds_cpp.cpp b/source/engine/thirdparty/stb/tests/test_ds_cpp.cpp deleted file mode 100644 index fce99df..0000000 --- a/source/engine/thirdparty/stb/tests/test_ds_cpp.cpp +++ /dev/null @@ -1,418 +0,0 @@ -#include - -#ifdef DS_TEST -#define STBDS_UNIT_TESTS -#endif - -#ifdef DS_STATS -#define STBDS_STATISTICS -#endif - -#ifndef DS_PERF -#define STBDS_ASSERT assert -#include -#endif - -//#define STBDS_SIPHASH_2_4 -#define STB_DS_IMPLEMENTATION -#include "../stb_ds.h" - -size_t churn_inserts, churn_deletes; - -void churn(int a, int b, int count) -{ - struct { int key,value; } *map=NULL; - int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i,i+1); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - assert(k != 0); - } - assert(hmlen(map) == a); - } - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; -} - -#ifdef DS_TEST -#include -int main(int argc, char **argv) -{ - stbds_unit_tests(); - churn(0,100,1); - churn(3,7,50000); - churn(3,15,50000); - churn(16, 48, 25000); - churn(10, 15, 25000); - churn(200,500, 5000); - churn(2000,5000, 500); - churn(20000,50000, 50); - printf("Ok!"); - return 0; -} -#endif - -#ifdef DS_STATS -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -size_t max_hit_probes, max_miss_probes, total_put_probes, total_miss_probes, churn_misses; -void churn_stats(int a, int b, int count) -{ - struct { int key,value; } *map=NULL; - int i,j,n,k; - churn_misses = 0; - for (i=0; i < a; ++i) { - hmput(map,i,i+1); - max_hit_probes = MAX(max_hit_probes, stbds_hash_probes); - total_put_probes += stbds_hash_probes; - stbds_hash_probes = 0; - } - - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - max_hit_probes = MAX(max_hit_probes, stbds_hash_probes); - total_put_probes += stbds_hash_probes; - stbds_hash_probes = 0; - } - for (j=0; j < (b-a)*10; ++j) { - k=i+j; - (void) hmgeti(map,k); // miss - max_miss_probes = MAX(max_miss_probes, stbds_hash_probes); - total_miss_probes += stbds_hash_probes; - stbds_hash_probes = 0; - ++churn_misses; - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - stbds_hash_probes = 0; - assert(k); - } - assert(hmlen(map) == a); - } - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; -} - -void reset_stats(void) -{ - stbds_array_grow=0, - stbds_hash_grow=0; - stbds_hash_shrink=0; - stbds_hash_rebuild=0; - stbds_hash_probes=0; - stbds_hash_alloc=0; - stbds_rehash_probes=0; - stbds_rehash_items=0; - max_hit_probes = 0; - max_miss_probes = 0; - total_put_probes = 0; - total_miss_probes = 0; -} - -void print_churn_probe_stats(char *str) -{ - printf("Probes: %3d max hit, %3d max miss, %4.2f avg hit, %4.2f avg miss: %s\n", - (int) max_hit_probes, (int) max_miss_probes, (float) total_put_probes / churn_inserts, (float) total_miss_probes / churn_misses, str); - reset_stats(); -} - -int main(int arg, char **argv) -{ - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items"); - return 0; -} -#endif - -#ifdef DS_PERF -#define WIN32_LEAN_AND_MEAN -#include -#define STB_DEFINE -#define STB_NO_REGISTRY -//#include "../stb.h" - - -size_t t0, sum, mn,mx,count; -void begin(void) -{ - size_t t0; - LARGE_INTEGER m; - QueryPerformanceCounter(&m); - t0 = m.QuadPart; - sum = 0; - count = 0; - mx = 0; - mn = ~(size_t) 0; -} - -void measure(void) -{ - size_t t1, t; - LARGE_INTEGER m; - QueryPerformanceCounter(&m); - t1 = m.QuadPart; - t = t1-t0; - if (t1 < t0) - printf("ALERT: QueryPerformanceCounter was unordered!\n"); - if (t < mn) mn = t; - if (t > mx) mx = t; - sum += t; - ++count; - t0 = t1; -} - -void dont_measure(void) -{ - size_t t1, t; - LARGE_INTEGER m; - QueryPerformanceCounter(&m); - t0 = m.QuadPart; -} - -double timer; -void end(void) -{ - LARGE_INTEGER m; - QueryPerformanceFrequency(&m); - - if (count > 3) { - // discard the highest and lowest - sum -= mn; - sum -= mx; - count -= 2; - } - timer = (double) (sum) / count / m.QuadPart * 1000; -} - -void build(int a, int b, int count, int step) -{ - struct { int key,value; } *map=NULL; - int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i*step,i+1); - measure(); - churn_inserts = i; - hmfree(map); - dont_measure(); -} - -#ifdef STB__INCLUDE_STB_H -void build_stb(int a, int b, int count, int step) -{ - stb_idict *d = stb_idict_new_size(8); - struct { int key,value; } *map=NULL; - int i,j,n,k; - for (i=0; i < a; ++i) - stb_idict_add(d, i*step, i+1); - measure(); - churn_inserts = i; - stb_idict_destroy(d); - dont_measure(); -} -#endif - -void churn_skip(unsigned int a, unsigned int b, int count) -{ - struct { unsigned int key,value; } *map=NULL; - unsigned int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i,i+1); - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - assert(k != 0); - } - assert(hmlen(map) == a); - } - measure(); - churn_inserts = i; - churn_deletes = (b-a) * n; - hmfree(map); - dont_measure(); -} - -typedef struct { int n[8]; } str32; -void churn32(int a, int b, int count, int include_startup) -{ - struct { str32 key; int value; } *map=NULL; - int i,j,n; - str32 key = { 0 }; - for (i=0; i < a; ++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - key.n[0] = i-j-1; - hmdel(map,key); - } - assert(hmlen(map) == a); - } - measure(); - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; - dont_measure(); -} - -typedef struct { int n[32]; } str256; -void churn256(int a, int b, int count, int include_startup) -{ - struct { str256 key; int value; } *map=NULL; - int i,j,n; - str256 key = { 0 }; - for (i=0; i < a; ++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - key.n[0] = i; - hmput(map,key,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - key.n[0] = i-j-1; - hmdel(map,key); - } - assert(hmlen(map) == a); - } - measure(); - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; - dont_measure(); -} - -void churn8(int a, int b, int count, int include_startup) -{ - struct { size_t key,value; } *map=NULL; - int i,j,n,k; - for (i=0; i < a; ++i) - hmput(map,i,i+1); - if (!include_startup) - dont_measure(); - for (n=0; n < count; ++n) { - for (j=a; j < b; ++j,++i) { - hmput(map,i,i+1); - } - assert(hmlen(map) == b); - for (j=a; j < b; ++j) { - k=i-j-1; - k = hmdel(map,k); - assert(k != 0); - } - assert(hmlen(map) == a); - } - measure(); - hmfree(map); - churn_inserts = i; - churn_deletes = (b-a) * n; - dont_measure(); -} - - -int main(int arg, char **argv) -{ - int n,s,w; - double worst = 0; - -#if 0 - begin(); for (n=0; n < 2000; ++n) { build_stb(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table\n", timer); - begin(); for (n=0; n < 500; ++n) { build_stb(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table\n", timer); - begin(); for (n=0; n < 100; ++n) { build_stb(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table\n", timer); - begin(); for (n=0; n < 10; ++n) { build_stb(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table\n", timer); - begin(); for (n=0; n < 5; ++n) { build_stb(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table\n", timer); -#endif - - begin(); for (n=0; n < 2000; ++n) { churn8(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { churn8(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { churn8(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { churn8(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 8-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { churn8(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 8-byte key\n", timer); - -#if 0 - begin(); for (n=0; n < 2000; ++n) { churn32(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { churn32(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { churn32(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { churn32(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 32-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { churn32(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 32-byte key\n", timer); - - begin(); for (n=0; n < 2000; ++n) { churn256(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { churn256(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { churn256(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { churn256(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 256-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { churn256(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 256-byte key\n", timer); -#endif - - begin(); for (n=0; n < 2000; ++n) { build(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 500; ++n) { build(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 100; ++n) { build(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 10; ++n) { build(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 4-byte key\n", timer); - begin(); for (n=0; n < 5; ++n) { build(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 4-byte key\n", timer); - - begin(); for (n=0; n < 60; ++n) { churn_skip(2000,2100,5000); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2K table\n", timer); - begin(); for (n=0; n < 30; ++n) { churn_skip(20000,21000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20K table\n", timer); - begin(); for (n=0; n < 15; ++n) { churn_skip(200000,201000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 200K table\n", timer); - begin(); for (n=0; n < 8; ++n) { churn_skip(2000000,2001000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2M table\n", timer); - begin(); for (n=0; n < 5; ++n) { churn_skip(20000000,20001000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20M table\n", timer); - begin(); for (n=0; n < 1; ++n) { churn_skip(200000000u,200001000u,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 200M table\n", timer); - // even though the above measures a roughly fixed amount of work, we still have to build the table n times, hence the fewer measurements each time - - begin(); for (n=0; n < 60; ++n) { churn_skip(1000,3000,250); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2K table\n", timer); - begin(); for (n=0; n < 15; ++n) { churn_skip(10000,30000,25); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20K table\n", timer); - begin(); for (n=0; n < 7; ++n) { churn_skip(100000,300000,10); } end(); printf(" // %7.2fms : 2,000,000 inserts & deletes in 200K table\n", timer); - begin(); for (n=0; n < 2; ++n) { churn_skip(1000000,3000000,10); } end(); printf(" // %7.2fms : 20,000,000 inserts & deletes in 2M table\n", timer); - - // search for bad intervals.. in practice this just seems to measure execution variance - for (s = 2; s < 64; ++s) { - begin(); for (n=0; n < 50; ++n) { build(200000,0,0,s); } end(); - if (timer > worst) { - worst = timer; - w = s; - } - } - for (; s <= 1024; s *= 2) { - begin(); for (n=0; n < 50; ++n) { build(200000,0,0,s); } end(); - if (timer > worst) { - worst = timer; - w = s; - } - } - printf(" // %7.2fms(%d) : Worst time from inserting 200,000 items with spacing %d.\n", worst, w, w); - - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/test_dxt.c b/source/engine/thirdparty/stb/tests/test_dxt.c deleted file mode 100644 index a1ef29d..0000000 --- a/source/engine/thirdparty/stb/tests/test_dxt.c +++ /dev/null @@ -1 +0,0 @@ -#include "stb_dxt.h" diff --git a/source/engine/thirdparty/stb/tests/test_easyfont.c b/source/engine/thirdparty/stb/tests/test_easyfont.c deleted file mode 100644 index 25d54ff..0000000 --- a/source/engine/thirdparty/stb/tests/test_easyfont.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "stb_easy_font.h" - -void ef_dummy(void) -{ - // suppress unsused-function warning - stb_easy_font_spacing(0); - stb_easy_font_print(0,0,0,0,0,0); - stb_easy_font_width(0); - stb_easy_font_height(0); -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/test_image.c b/source/engine/thirdparty/stb/tests/test_image.c deleted file mode 100644 index de2c8b0..0000000 --- a/source/engine/thirdparty/stb/tests/test_image.c +++ /dev/null @@ -1,7 +0,0 @@ -#ifdef __clang__ -#define STBIDEF static inline -#endif - -#define STB_IMAGE_STATIC -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/test_image_write.c b/source/engine/thirdparty/stb/tests/test_image_write.c deleted file mode 100644 index 8c4c35c..0000000 --- a/source/engine/thirdparty/stb/tests/test_image_write.c +++ /dev/null @@ -1,7 +0,0 @@ -#ifdef __clang__ -#define STBIWDEF static inline -#endif - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#define STB_IMAGE_WRITE_STATIC -#include "stb_image_write.h" \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/test_perlin.c b/source/engine/thirdparty/stb/tests/test_perlin.c deleted file mode 100644 index de702c9..0000000 --- a/source/engine/thirdparty/stb/tests/test_perlin.c +++ /dev/null @@ -1 +0,0 @@ -#include "stb_perlin.h" \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/test_png_paeth.c b/source/engine/thirdparty/stb/tests/test_png_paeth.c deleted file mode 100644 index 69ba37f..0000000 --- a/source/engine/thirdparty/stb/tests/test_png_paeth.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -// Reference Paeth filter as per PNG spec -static int ref_paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -// Optimized Paeth filter -static int opt_paeth(int a, int b, int c) -{ - int thresh = c*3 - (a + b); - int lo = a < b ? a : b; - int hi = a < b ? b : a; - int t0 = (hi <= thresh) ? lo : c; - int t1 = (thresh <= lo) ? hi : t0; - return t1; -} - -int main() -{ - // Exhaustively test the functions match for all byte inputs a, b,c in [0,255] - for (int i = 0; i < (1 << 24); ++i) { - int a = i & 0xff; - int b = (i >> 8) & 0xff; - int c = (i >> 16) & 0xff; - - int ref = ref_paeth(a, b, c); - int opt = opt_paeth(a, b, c); - if (ref != opt) { - fprintf(stderr, "mismatch at a=%3d b=%3d c=%3d: ref=%3d opt=%3d\n", a, b, c, ref, opt); - return 1; - } - } - - printf("all ok!\n"); - return 0; -} - -// vim:sw=3:sts=3:et diff --git a/source/engine/thirdparty/stb/tests/test_png_regress.c b/source/engine/thirdparty/stb/tests/test_png_regress.c deleted file mode 100644 index 5ba6796..0000000 --- a/source/engine/thirdparty/stb/tests/test_png_regress.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include - -#define STBI_WINDOWS_UTF8 - -#ifdef _WIN32 -#define WIN32 // what stb.h checks -#pragma comment(lib, "advapi32.lib") -#endif - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#define STB_DEFINE -#include "deprecated/stb.h" - -static unsigned int fnv1a_hash32(const stbi_uc *bytes, size_t len) -{ - unsigned int hash = 0x811c9dc5; - unsigned int mul = 0x01000193; - size_t i; - - for (i = 0; i < len; ++i) - hash = (hash ^ bytes[i]) * mul; - - return hash; -} - -// The idea for this test is to leave pngsuite/ref_results.csv checked in, -// and then you can run this test after making PNG loader changes. If the -// ref results change (as per git diff), confirm that the change was -// intentional. If so, commit them as well; if not, undo. -int main() -{ - char **files; - FILE *csv_file; - int i; - - files = stb_readdir_recursive("pngsuite", "*.png"); - if (!files) { - fprintf(stderr, "pngsuite files not found!\n"); - return 1; - } - - // sort files by name - qsort(files, stb_arr_len(files), sizeof(char*), stb_qsort_strcmp(0)); - - csv_file = fopen("pngsuite/ref_results.csv", "w"); - if (!csv_file) { - fprintf(stderr, "error opening ref results for writing!\n"); - stb_readdir_free(files); - return 1; - } - - fprintf(csv_file, "filename,width,height,ncomp,error,hash\n"); - for (i = 0; i < stb_arr_len(files); ++i) { - char *filename = files[i]; - int width, height, ncomp; - stbi_uc *pixels = stbi_load(filename, &width, &height, &ncomp, 0); - const char *error = ""; - unsigned int hash = 0; - - if (!pixels) - error = stbi_failure_reason(); - else { - hash = fnv1a_hash32(pixels, width * height * ncomp); - stbi_image_free(pixels); - } - - fprintf(csv_file, "%s,%d,%d,%d,%s,0x%08x\n", filename, width, height, ncomp, error, hash); - } - - fclose(csv_file); - stb_readdir_free(files); -} diff --git a/source/engine/thirdparty/stb/tests/test_siphash.c b/source/engine/thirdparty/stb/tests/test_siphash.c deleted file mode 100644 index 643f549..0000000 --- a/source/engine/thirdparty/stb/tests/test_siphash.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#define STB_DS_IMPLEMENTATION -#define STBDS_SIPHASH_2_4 -#define STBDS_TEST_SIPHASH_2_4 -#include "../stb_ds.h" - -int main(int argc, char **argv) -{ - unsigned char mem[64]; - int i,j; - for (i=0; i < 64; ++i) mem[i] = i; - for (i=0; i < 64; ++i) { - size_t hash = stbds_hash_bytes(mem, i, 0); - printf(" { "); - for (j=0; j < 8; ++j) - printf("0x%02x, ", (unsigned char) ((hash >> (j*8)) & 255)); - printf(" },\n"); - } - return 0; -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/test_sprintf.c b/source/engine/thirdparty/stb/tests/test_sprintf.c deleted file mode 100644 index 60ef40b..0000000 --- a/source/engine/thirdparty/stb/tests/test_sprintf.c +++ /dev/null @@ -1,202 +0,0 @@ - -#define USE_STB 1 - -#if USE_STB -# include "stb_sprintf.h" -# define SPRINTF stbsp_sprintf -# define SNPRINTF stbsp_snprintf -#else -# include -# define SPRINTF sprintf -# define SNPRINTF snprintf -#endif - -#include -#include // for INFINITY, NAN -#include // for ptrdiff_t -#include // for printf -#include // for strcmp, strncmp, strlen - -#if _MSC_VER && _MSC_VER <= 1600 -typedef int intmax_t; -typedef ptrdiff_t ssize_t; -#else -#include // for intmax_t, ssize_t -#endif - -// stbsp_sprintf -#define CHECK_END(str) \ - if (strcmp(buf, str) != 0 || (unsigned) ret != strlen(str)) { \ - printf("< '%s'\n> '%s'\n", str, buf); \ - assert(!"Fail"); \ - } - -#define CHECK9(str, v1, v2, v3, v4, v5, v6, v7, v8, v9) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6, v7, v8, v9); CHECK_END(str); } -#define CHECK8(str, v1, v2, v3, v4, v5, v6, v7, v8 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6, v7, v8 ); CHECK_END(str); } -#define CHECK7(str, v1, v2, v3, v4, v5, v6, v7 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6, v7 ); CHECK_END(str); } -#define CHECK6(str, v1, v2, v3, v4, v5, v6 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6 ); CHECK_END(str); } -#define CHECK5(str, v1, v2, v3, v4, v5 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5 ); CHECK_END(str); } -#define CHECK4(str, v1, v2, v3, v4 ) { int ret = SPRINTF(buf, v1, v2, v3, v4 ); CHECK_END(str); } -#define CHECK3(str, v1, v2, v3 ) { int ret = SPRINTF(buf, v1, v2, v3 ); CHECK_END(str); } -#define CHECK2(str, v1, v2 ) { int ret = SPRINTF(buf, v1, v2 ); CHECK_END(str); } -#define CHECK1(str, v1 ) { int ret = SPRINTF(buf, v1 ); CHECK_END(str); } - -#ifdef TEST_SPRINTF -int main() -{ - char buf[1024]; - int n = 0; - const double pow_2_75 = 37778931862957161709568.0; - const double pow_2_85 = 38685626227668133590597632.0; - - // integers - CHECK4("a b 1", "%c %s %d", 'a', "b", 1); - CHECK2("abc ", "%-8.3s", "abcdefgh"); - CHECK2("+5", "%+2d", 5); - CHECK2(" 6", "% 3i", 6); - CHECK2("-7 ", "%-4d", -7); - CHECK2("+0", "%+d", 0); - CHECK3(" 00003: 00004", "%10.5d:%10.5d", 3, 4); - CHECK2("-100006789", "%d", -100006789); - CHECK3("20 0020", "%u %04u", 20u, 20u); - CHECK4("12 1e 3C", "%o %x %X", 10u, 30u, 60u); - CHECK4(" 12 1e 3C ", "%3o %2x %-3X", 10u, 30u, 60u); - CHECK4("012 0x1e 0X3C", "%#o %#x %#X", 10u, 30u, 60u); - CHECK2("", "%.0x", 0); -#if USE_STB - CHECK2("0", "%.0d", 0); // stb_sprintf gives "0" -#else - CHECK2("", "%.0d", 0); // glibc gives "" as specified by C99(?) -#endif - CHECK3("33 555", "%hi %ld", (short)33, 555l); -#if !defined(_MSC_VER) || _MSC_VER >= 1600 - CHECK2("9888777666", "%llu", 9888777666llu); -#endif - CHECK4("-1 2 -3", "%ji %zi %ti", (intmax_t)-1, (ssize_t)2, (ptrdiff_t)-3); - - // floating-point numbers - CHECK2("-3.000000", "%f", -3.0); - CHECK2("-8.8888888800", "%.10f", -8.88888888); - CHECK2("880.0888888800", "%.10f", 880.08888888); - CHECK2("4.1", "%.1f", 4.1); - CHECK2(" 0", "% .0f", 0.1); - CHECK2("0.00", "%.2f", 1e-4); - CHECK2("-5.20", "%+4.2f", -5.2); - CHECK2("0.0 ", "%-10.1f", 0.); - CHECK2("-0.000000", "%f", -0.); - CHECK2("0.000001", "%f", 9.09834e-07); -#if USE_STB // rounding differences - CHECK2("38685626227668133600000000.0", "%.1f", pow_2_85); - CHECK2("0.000000499999999999999978", "%.24f", 5e-7); -#else - CHECK2("38685626227668133590597632.0", "%.1f", pow_2_85); // exact - CHECK2("0.000000499999999999999977", "%.24f", 5e-7); -#endif - CHECK2("0.000000000000000020000000", "%.24f", 2e-17); - CHECK3("0.0000000100 100000000", "%.10f %.0f", 1e-8, 1e+8); - CHECK2("100056789.0", "%.1f", 100056789.0); - CHECK4(" 1.23 %", "%*.*f %%", 5, 2, 1.23); - CHECK2("-3.000000e+00", "%e", -3.0); - CHECK2("4.1E+00", "%.1E", 4.1); - CHECK2("-5.20e+00", "%+4.2e", -5.2); - CHECK3("+0.3 -3", "%+g %+g", 0.3, -3.0); - CHECK2("4", "%.1G", 4.1); - CHECK2("-5.2", "%+4.2g", -5.2); - CHECK2("3e-300", "%g", 3e-300); - CHECK2("1", "%.0g", 1.2); - CHECK3(" 3.7 3.71", "% .3g %.3g", 3.704, 3.706); - CHECK3("2e-315:1e+308", "%g:%g", 2e-315, 1e+308); - -#if __STDC_VERSION__ >= 199901L -#if USE_STB - CHECK4("Inf Inf NaN", "%g %G %f", INFINITY, INFINITY, NAN); - CHECK2("N", "%.1g", NAN); -#else - CHECK4("inf INF nan", "%g %G %f", INFINITY, INFINITY, NAN); - CHECK2("nan", "%.1g", NAN); -#endif -#endif - - // %n - CHECK3("aaa ", "%.3s %n", "aaaaaaaaaaaaa", &n); - assert(n == 4); - -#if __STDC_VERSION__ >= 199901L - // hex floats - CHECK2("0x1.fedcbap+98", "%a", 0x1.fedcbap+98); - CHECK2("0x1.999999999999a0p-4", "%.14a", 0.1); - CHECK2("0x1.0p-1022", "%.1a", 0x1.ffp-1023); -#if USE_STB // difference in default precision and x vs X for %A - CHECK2("0x1.009117p-1022", "%a", 2.23e-308); - CHECK2("-0x1.AB0P-5", "%.3A", -0x1.abp-5); -#else - CHECK2("0x1.0091177587f83p-1022", "%a", 2.23e-308); - CHECK2("-0X1.AB0P-5", "%.3A", -0X1.abp-5); -#endif -#endif - - // %p -#if USE_STB - CHECK2("0000000000000000", "%p", (void*) NULL); -#else - CHECK2("(nil)", "%p", (void*) NULL); -#endif - - // snprintf - assert(SNPRINTF(buf, 100, " %s %d", "b", 123) == 10); - assert(strcmp(buf, " b 123") == 0); - assert(SNPRINTF(buf, 100, "%f", pow_2_75) == 30); - assert(strncmp(buf, "37778931862957161709568.000000", 17) == 0); - n = SNPRINTF(buf, 10, "number %f", 123.456789); - assert(strcmp(buf, "number 12") == 0); - assert(n == 17); // written vs would-be written bytes - n = SNPRINTF(buf, 0, "7 chars"); - assert(n == 7); - // stb_sprintf uses internal buffer of 512 chars - test longer string - assert(SPRINTF(buf, "%d %600s", 3, "abc") == 603); - assert(strlen(buf) == 603); - SNPRINTF(buf, 550, "%d %600s", 3, "abc"); - assert(strlen(buf) == 549); - assert(SNPRINTF(buf, 600, "%510s %c", "a", 'b') == 516); - - // length check - assert(SNPRINTF(NULL, 0, " %s %d", "b", 123) == 10); - - // ' modifier. Non-standard, but supported by glibc. -#if !USE_STB - setlocale(LC_NUMERIC, ""); // C locale does not group digits -#endif - CHECK2("1,200,000", "%'d", 1200000); - CHECK2("-100,006,789", "%'d", -100006789); -#if !defined(_MSC_VER) || _MSC_VER >= 1600 - CHECK2("9,888,777,666", "%'lld", 9888777666ll); -#endif - CHECK2("200,000,000.000000", "%'18f", 2e8); - CHECK2("100,056,789", "%'.0f", 100056789.0); - CHECK2("100,056,789.0", "%'.1f", 100056789.0); -#if USE_STB // difference in leading zeros - CHECK2("000,001,200,000", "%'015d", 1200000); -#else - CHECK2("0000001,200,000", "%'015d", 1200000); -#endif - - // things not supported by glibc -#if USE_STB - CHECK2("null", "%s", (char*) NULL); - CHECK2("123,4abc:", "%'x:", 0x1234ABC); - CHECK2("100000000", "%b", 256); - CHECK3("0b10 0B11", "%#b %#B", 2, 3); -#if !defined(_MSC_VER) || _MSC_VER >= 1600 - CHECK4("2 3 4", "%I64d %I32d %Id", 2ll, 3, 4ll); -#endif - CHECK3("1k 2.54 M", "%$_d %$.2d", 1000, 2536000); - CHECK3("2.42 Mi 2.4 M", "%$$.2d %$$$d", 2536000, 2536000); - - // different separators - stbsp_set_separators(' ', ','); - CHECK2("12 345,678900", "%'f", 12345.6789); -#endif - - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/test_truetype.c b/source/engine/thirdparty/stb/tests/test_truetype.c deleted file mode 100644 index cb9b35f..0000000 --- a/source/engine/thirdparty/stb/tests/test_truetype.c +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _CRT_SECURE_NO_WARNINGS -// Fixes Compile Errors for Visual Studio 2005 or newer - #define _CRT_SECURE_NO_WARNINGS -#endif - -#include - -// this isn't meant to compile standalone; link with test_c_compilation.c as well -#include "stb_rect_pack.h" -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" -#include "stb_image_write.h" - -#ifdef TT_TEST - -#include - -unsigned char ttf_buffer[1 << 25]; -unsigned char output[512*100]; - -void debug(void) -{ - stbtt_fontinfo font; - fread(ttf_buffer, 1, 1<<25, fopen("c:/x/lm/LiberationMono-Regular.ttf", "rb")); - stbtt_InitFont(&font, ttf_buffer, 0); - - stbtt_MakeGlyphBitmap(&font, output, 6, 9, 512, 5.172414E-03f, 5.172414E-03f, 54); -} - -#define BITMAP_W 256 -#define BITMAP_H 512 -unsigned char temp_bitmap[BITMAP_H][BITMAP_W]; -stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs -stbtt_packedchar pdata[256*2]; - -int main(int argc, char **argv) -{ - stbtt_fontinfo font; - unsigned char *bitmap; - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : '@'), s = (argc > 2 ? atoi(argv[2]) : 32); - - //debug(); - - // @TODO: why is minglui.ttc failing? - //fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb")); - - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/DejaVuSans.ttf", "rb")); - - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); - -#if 0 - { - stbtt__bitmap b; - stbtt__point p[2]; - int wcount[2] = { 2,0 }; - p[0].x = 0.2f; - p[0].y = 0.3f; - p[1].x = 3.8f; - p[1].y = 0.8f; - b.w = 16; - b.h = 2; - b.stride = 16; - b.pixels = malloc(b.w*b.h); - stbtt__rasterize(&b, p, wcount, 1, 1, 1, 0, 0, 0, 0, 0, NULL); - for (i=0; i < 8; ++i) - printf("%f\n", b.pixels[i]/255.0); - } -#endif - -#if 1 - { - static stbtt_pack_context pc; - static stbtt_packedchar cd[256]; - static unsigned char atlas[1024*1024]; - - stbtt_PackBegin(&pc, atlas, 1024,1024,1024,1,NULL); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 32.0, 0, 256, cd); - stbtt_PackEnd(&pc); - } -#endif - - -#if 1 - { - static stbtt_pack_context pc; - static stbtt_packedchar cd[256]; - static unsigned char atlas[1024*1024]; - unsigned char *data; - - data = stbtt_GetCodepointSDF(&font, stbtt_ScaleForPixelHeight(&font,32.0), 'u', 4, 128, 128/4, &w,&h,&i,&j); - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - putchar(" .:ioVM@"[data[j*w+i]>>5]); - } - putchar('\n'); - } - } -#endif - -#if 0 - stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! - stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); - - { - stbtt_pack_context pc; - stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 32, 95, pdata); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 0xa0, 0x100-0xa0, pdata); - stbtt_PackEnd(&pc); - stbi_write_png("fonttest2.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); - } - - { - stbtt_pack_context pc; - stbtt_pack_range pr[2]; - stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); - - pr[0].chardata_for_range = pdata; - pr[0].array_of_unicode_codepoints = NULL; - pr[0].first_unicode_codepoint_in_range = 32; - pr[0].num_chars = 95; - pr[0].font_size = 20.0f; - pr[1].chardata_for_range = pdata+256; - pr[1].array_of_unicode_codepoints = NULL; - pr[1].first_unicode_codepoint_in_range = 0xa0; - pr[1].num_chars = 0x100 - 0xa0; - pr[1].font_size = 20.0f; - - stbtt_PackSetOversampling(&pc, 2, 2); - stbtt_PackFontRanges(&pc, ttf_buffer, 0, pr, 2); - stbtt_PackEnd(&pc); - stbi_write_png("fonttest3.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); - } - return 0; -#endif - - (void)stbtt_GetCodepointBitmapSubpixel(&font, - 0.4972374737262726f, - 0.4986416995525360f, - 0.2391788959503174f, - 0.1752119064331055f, - 'd', - &w, &h, - 0,0); - - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, (float)s), c, &w, &h, 0,0); - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); - putchar('\n'); - } - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/test_vorbis.c b/source/engine/thirdparty/stb/tests/test_vorbis.c deleted file mode 100644 index d54ed23..0000000 --- a/source/engine/thirdparty/stb/tests/test_vorbis.c +++ /dev/null @@ -1,18 +0,0 @@ -#define STB_VORBIS_HEADER_ONLY -#include "stb_vorbis.c" -#include "stb.h" - -extern void stb_vorbis_dumpmem(void); - -#ifdef VORBIS_TEST -int main(int argc, char **argv) -{ - size_t memlen; - unsigned char *mem = stb_fileu("c:/x/sketch008.ogg", &memlen); - int chan, samplerate; - short *output; - int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output); - stb_filewrite("c:/x/sketch008.raw", output, samples*4); - return 0; -} -#endif diff --git a/source/engine/thirdparty/stb/tests/test_voxel.c b/source/engine/thirdparty/stb/tests/test_voxel.c deleted file mode 100644 index e177b6f..0000000 --- a/source/engine/thirdparty/stb/tests/test_voxel.c +++ /dev/null @@ -1 +0,0 @@ -#include "stb_voxel_render.h" \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/textedit_sample.c b/source/engine/thirdparty/stb/tests/textedit_sample.c deleted file mode 100644 index 57250f3..0000000 --- a/source/engine/thirdparty/stb/tests/textedit_sample.c +++ /dev/null @@ -1,94 +0,0 @@ -// I haven't actually tested this yet, this is just to make sure it compiles - -#include -#include // memmove -#include // isspace - -#define STB_TEXTEDIT_CHARTYPE char -#define STB_TEXTEDIT_STRING text_control - -// get the base type -#include "stb_textedit.h" - -// define our editor structure -typedef struct -{ - char *string; - int stringlen; - STB_TexteditState state; -} text_control; - -// define the functions we need -void layout_func(StbTexteditRow *row, STB_TEXTEDIT_STRING *str, int start_i) -{ - int remaining_chars = str->stringlen - start_i; - row->num_chars = remaining_chars > 20 ? 20 : remaining_chars; // should do real word wrap here - row->x0 = 0; - row->x1 = 20; // need to account for actual size of characters - row->baseline_y_delta = 1.25; - row->ymin = -1; - row->ymax = 0; -} - -int delete_chars(STB_TEXTEDIT_STRING *str, int pos, int num) -{ - memmove(&str->string[pos], &str->string[pos+num], str->stringlen - (pos+num)); - str->stringlen -= num; - return 1; // always succeeds -} - -int insert_chars(STB_TEXTEDIT_STRING *str, int pos, STB_TEXTEDIT_CHARTYPE *newtext, int num) -{ - str->string = realloc(str->string, str->stringlen + num); - memmove(&str->string[pos+num], &str->string[pos], str->stringlen - pos); - memcpy(&str->string[pos], newtext, num); - str->stringlen += num; - return 1; // always succeeds -} - -// define all the #defines needed - -#define KEYDOWN_BIT 0x80000000 - -#define STB_TEXTEDIT_STRINGLEN(tc) ((tc)->stringlen) -#define STB_TEXTEDIT_LAYOUTROW layout_func -#define STB_TEXTEDIT_GETWIDTH(tc,n,i) (1) // quick hack for monospaced -#define STB_TEXTEDIT_KEYTOTEXT(key) (((key) & KEYDOWN_BIT) ? 0 : (key)) -#define STB_TEXTEDIT_GETCHAR(tc,i) ((tc)->string[i]) -#define STB_TEXTEDIT_NEWLINE '\n' -#define STB_TEXTEDIT_IS_SPACE(ch) isspace(ch) -#define STB_TEXTEDIT_DELETECHARS delete_chars -#define STB_TEXTEDIT_INSERTCHARS insert_chars - -#define STB_TEXTEDIT_K_SHIFT 0x40000000 -#define STB_TEXTEDIT_K_CONTROL 0x20000000 -#define STB_TEXTEDIT_K_LEFT (KEYDOWN_BIT | 1) // actually use VK_LEFT, SDLK_LEFT, etc -#define STB_TEXTEDIT_K_RIGHT (KEYDOWN_BIT | 2) // VK_RIGHT -#define STB_TEXTEDIT_K_UP (KEYDOWN_BIT | 3) // VK_UP -#define STB_TEXTEDIT_K_DOWN (KEYDOWN_BIT | 4) // VK_DOWN -#define STB_TEXTEDIT_K_LINESTART (KEYDOWN_BIT | 5) // VK_HOME -#define STB_TEXTEDIT_K_LINEEND (KEYDOWN_BIT | 6) // VK_END -#define STB_TEXTEDIT_K_TEXTSTART (STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_TEXTEND (STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_DELETE (KEYDOWN_BIT | 7) // VK_DELETE -#define STB_TEXTEDIT_K_BACKSPACE (KEYDOWN_BIT | 8) // VK_BACKSPACE -#define STB_TEXTEDIT_K_UNDO (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'z') -#define STB_TEXTEDIT_K_REDO (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'y') -#define STB_TEXTEDIT_K_INSERT (KEYDOWN_BIT | 9) // VK_INSERT -#define STB_TEXTEDIT_K_WORDLEFT (STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_WORDRIGHT (STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_CONTROL) -#define STB_TEXTEDIT_K_PGUP (KEYDOWN_BIT | 10) // VK_PGUP -- not implemented -#define STB_TEXTEDIT_K_PGDOWN (KEYDOWN_BIT | 11) // VK_PGDOWN -- not implemented - -#define STB_TEXTEDIT_IMPLEMENTATION -#include "stb_textedit.h" - -void dummy3(void) -{ - stb_textedit_click(0,0,0,0); - stb_textedit_drag(0,0,0,0); - stb_textedit_cut(0,0); - stb_textedit_key(0,0,0); - stb_textedit_initialize_state(0,0); - stb_textedit_paste(0,0,0,0); -} diff --git a/source/engine/thirdparty/stb/tests/tilemap_editor_integration_example.c b/source/engine/thirdparty/stb/tests/tilemap_editor_integration_example.c deleted file mode 100644 index ea5dee7..0000000 --- a/source/engine/thirdparty/stb/tests/tilemap_editor_integration_example.c +++ /dev/null @@ -1,193 +0,0 @@ -// This isn't compilable as-is, as it was extracted from a working -// integration-in-a-game and makes reference to symbols from that game. - -#include -#include -#include "game.h" -#include "SDL.h" -#include "stb_tilemap_editor.h" - -extern void editor_draw_tile(int x, int y, unsigned short tile, int mode, float *props); -extern void editor_draw_rect(int x0, int y0, int x1, int y1, unsigned char r, unsigned char g, unsigned char b); - -static int is_platform(short *tiles); -static unsigned int prop_type(int n, short *tiles); -static char *prop_name(int n, short *tiles); -static float prop_range(int n, short *tiles, int is_max); -static int allow_link(short *src, short *dest); - -#define STBTE_MAX_PROPERTIES 8 - -#define STBTE_PROP_TYPE(n, tiledata, p) prop_type(n,tiledata) -#define STBTE_PROP_NAME(n, tiledata, p) prop_name(n,tiledata) -#define STBTE_PROP_MIN(n, tiledata, p) prop_range(n,tiledata,0) -#define STBTE_PROP_MAX(n, tiledata, p) prop_range(n,tiledata,1) -#define STBTE_PROP_FLOAT_SCALE(n,td,p) (0.1) - -#define STBTE_ALLOW_LINK(srctile, srcprop, desttile, destprop) \ - allow_link(srctile, desttile) - -#define STBTE_LINK_COLOR(srctile, srcprop, desttile, destprop) \ - (is_platform(srctile) ? 0xff80ff : 0x808040) - -#define STBTE_DRAW_RECT(x0,y0,x1,y1,c) \ - editor_draw_rect(x0,y0,x1,y1,(c)>>16,((c)>>8)&255,(c)&255) - -#define STBTE_DRAW_TILE(x,y,id,highlight,props) \ - editor_draw_tile(x,y,id,highlight,props) - - - -#define STB_TILEMAP_EDITOR_IMPLEMENTATION -#include "stb_tilemap_editor.h" - -stbte_tilemap *edit_map; - -void editor_key(enum stbte_action act) -{ - stbte_action(edit_map, act); -} - -void editor_process_sdl_event(SDL_Event *e) -{ - switch (e->type) { - case SDL_MOUSEMOTION: - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - case SDL_MOUSEWHEEL: - stbte_mouse_sdl(edit_map, e, 1.0f/editor_scale,1.0f/editor_scale,0,0); - break; - - case SDL_KEYDOWN: - if (in_editor) { - switch (e->key.keysym.sym) { - case SDLK_RIGHT: editor_key(STBTE_scroll_right); break; - case SDLK_LEFT : editor_key(STBTE_scroll_left ); break; - case SDLK_UP : editor_key(STBTE_scroll_up ); break; - case SDLK_DOWN : editor_key(STBTE_scroll_down ); break; - } - switch (e->key.keysym.scancode) { - case SDL_SCANCODE_S: editor_key(STBTE_tool_select); break; - case SDL_SCANCODE_B: editor_key(STBTE_tool_brush ); break; - case SDL_SCANCODE_E: editor_key(STBTE_tool_erase ); break; - case SDL_SCANCODE_R: editor_key(STBTE_tool_rectangle ); break; - case SDL_SCANCODE_I: editor_key(STBTE_tool_eyedropper); break; - case SDL_SCANCODE_L: editor_key(STBTE_tool_link); break; - case SDL_SCANCODE_G: editor_key(STBTE_act_toggle_grid); break; - } - if ((e->key.keysym.mod & KMOD_CTRL) && !(e->key.keysym.mod & ~KMOD_CTRL)) { - switch (e->key.keysym.scancode) { - case SDL_SCANCODE_X: editor_key(STBTE_act_cut ); break; - case SDL_SCANCODE_C: editor_key(STBTE_act_copy ); break; - case SDL_SCANCODE_V: editor_key(STBTE_act_paste); break; - case SDL_SCANCODE_Z: editor_key(STBTE_act_undo ); break; - case SDL_SCANCODE_Y: editor_key(STBTE_act_redo ); break; - } - } - } - break; - } -} - -void editor_init(void) -{ - int i; - edit_map = stbte_create_map(20,14, 8, 16,16, 100); - - stbte_set_background_tile(edit_map, T_empty); - - for (i=0; i < T__num_types; ++i) { - if (i != T_reserved1 && i != T_entry && i != T_doorframe) - stbte_define_tile(edit_map, 0+i, 1, "Background"); - } - stbte_define_tile(edit_map, 256+O_player , 8, "Char"); - stbte_define_tile(edit_map, 256+O_robot , 8, "Char"); - for (i=O_lockeddoor; i < O__num_types-2; ++i) - if (i == O_platform || i == O_vplatform) - stbte_define_tile(edit_map, 256+i, 4, "Object"); - else - stbte_define_tile(edit_map, 256+i, 2, "Object"); - - //stbte_set_layername(edit_map, 0, "background"); - //stbte_set_layername(edit_map, 1, "objects"); - //stbte_set_layername(edit_map, 2, "platforms"); - //stbte_set_layername(edit_map, 3, "characters"); -} - -static int is_platform(short *tiles) -{ - // platforms are only on layer #2 - return tiles[2] == 256 + O_platform || tiles[2] == 256 + O_vplatform; -} - -static int is_object(short *tiles) -{ - return (tiles[1] >= 256 || tiles[2] >= 256 || tiles[3] >= 256); -} - -static unsigned int prop_type(int n, short *tiles) -{ - if (is_platform(tiles)) { - static unsigned int platform_types[STBTE_MAX_PROPERTIES] = { - STBTE_PROP_bool, // phantom - STBTE_PROP_int, // x_adjust - STBTE_PROP_int, // y_adjust - STBTE_PROP_float, // width - STBTE_PROP_float, // lspeed - STBTE_PROP_float, // rspeed - STBTE_PROP_bool, // autoreturn - STBTE_PROP_bool, // one-shot - // remainder get 0, means 'no property in this slot' - }; - return platform_types[n]; - } else if (is_object(tiles)) { - if (n == 0) - return STBTE_PROP_bool; - } - return 0; -} - -static char *prop_name(int n, short *tiles) -{ - if (is_platform(tiles)) { - static char *platform_vars[STBTE_MAX_PROPERTIES] = { - "phantom", - "x_adjust", - "y_adjust", - "width", - "lspeed", - "rspeed", - "autoreturn", - "one-shot", - }; - return platform_vars[n]; - } - return "phantom"; -} - -static float prop_range(int n, short *tiles, int is_max) -{ - if (is_platform(tiles)) { - static float ranges[8][2] = { - { 0, 1 }, // phantom-flag, range is ignored - { -15, 15 }, // x_adjust - { -15, 15 }, // y_adjust - { 0, 6 }, // width - { 0, 10 }, // lspeed - { 0, 10 }, // rspeed - { 0, 1 }, // autoreturn, range is ignored - { 0, 1 }, // one-shot, range is ignored - }; - return ranges[n][is_max]; - } - return 0; -} - -static int allow_link(short *src, short *dest) -{ - if (is_platform(src)) - return dest[1] == 256+O_lever; - if (src[1] == 256+O_endpoint) - return is_platform(dest); - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/truetype_test_win32.c b/source/engine/thirdparty/stb/tests/truetype_test_win32.c deleted file mode 100644 index c9aed99..0000000 --- a/source/engine/thirdparty/stb/tests/truetype_test_win32.c +++ /dev/null @@ -1,184 +0,0 @@ -// tested in VC6 (1998) and VS 2019 -#define _CRT_SECURE_NO_WARNINGS -#define WIN32_MEAN_AND_LEAN -#include - -#include -#include - -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" - -#include -#include - -int screen_x=1024, screen_y=768; -GLuint tex; - -unsigned char ttf_buffer[1<<20]; -unsigned char temp_bitmap[1024*1024]; -stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs - -void init(void) -{ - fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); - stbtt_BakeFontBitmap(ttf_buffer,0, 64.0, temp_bitmap,1024,1024, 32,96, cdata); - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 1024,1024,0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -void print(float x, float y, char *text) -{ - // assume orthographic projection with units = screen pixels, origin at top left - glBindTexture(GL_TEXTURE_2D, tex); - glBegin(GL_QUADS); - while (*text) { - if (*text >= 32 && *text < 128) { - stbtt_aligned_quad q; - stbtt_GetBakedQuad(cdata, 1024,1024, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); - } - ++text; - } - glEnd(); -} - -void draw(void) -{ - glViewport(0,0,screen_x,screen_y); - glClearColor(0.45f,0.45f,0.75f,0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0,screen_x,screen_y,0,-1,1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor3f(1,1,1); - - print(100,150, "This is a simple test!"); - - // show font bitmap - glBegin(GL_QUADS); - glTexCoord2f(0,0); glVertex2f(256,200+0); - glTexCoord2f(1,0); glVertex2f(768,200+0); - glTexCoord2f(1,1); glVertex2f(768,200+512); - glTexCoord2f(0,1); glVertex2f(256,200+512); - glEnd(); -} - -/////////////////////////////////////////////////////////////////////// -/// -/// -/// Windows OpenGL setup -/// -/// - -HINSTANCE app; -HWND window; -HGLRC rc; -HDC dc; - -#pragma comment(lib, "opengl32.lib") -#pragma comment(lib, "glu32.lib") -#pragma comment(lib, "winmm.lib") - -int mySetPixelFormat(HWND win) -{ - PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd), 1, PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA }; - int pixel_format; - pfd.dwLayerMask = PFD_MAIN_PLANE; - pfd.cColorBits = 24; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - pixel_format = ChoosePixelFormat(dc, &pfd); - if (!pixel_format) return FALSE; - if (!DescribePixelFormat(dc, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) - return FALSE; - SetPixelFormat(dc, pixel_format, &pfd); - return TRUE; -} - -static int WINAPI WinProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) { - case WM_CREATE: { - LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam; - dc = GetDC(wnd); - if (mySetPixelFormat(wnd)) { - rc = wglCreateContext(dc); - if (rc) { - wglMakeCurrent(dc, rc); - return 0; - } - } - return -1; - } - - case WM_DESTROY: - wglMakeCurrent(NULL, NULL); - if (rc) wglDeleteContext(rc); - PostQuitMessage (0); - return 0; - - default: - return DefWindowProc (wnd, msg, wparam, lparam); - } - - return DefWindowProc (wnd, msg, wparam, lparam); -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - DWORD dwstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - WNDCLASSEX wndclass; - wndclass.cbSize = sizeof(wndclass); - wndclass.style = CS_OWNDC; - wndclass.lpfnWndProc = (WNDPROC) WinProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = hInstance; - wndclass.hIcon = LoadIcon(hInstance, _T("appicon")); - wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); - wndclass.hbrBackground = GetStockObject(NULL_BRUSH); - wndclass.lpszMenuName = _T("truetype-test"); - wndclass.lpszClassName = _T("truetype-test"); - wndclass.hIconSm = NULL; - app = hInstance; - - if (!RegisterClassEx(&wndclass)) - return 0; - - window = CreateWindow(_T("truetype-test"), _T("truetype test"), dwstyle, - CW_USEDEFAULT,0, screen_x, screen_y, - NULL, NULL, app, NULL); - ShowWindow(window, SW_SHOWNORMAL); - init(); - - for(;;) { - MSG msg; - if (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - return 1; // WM_QUIT - } - wglMakeCurrent(dc, rc); - draw(); - SwapBuffers(dc); - } - return 0; -} diff --git a/source/engine/thirdparty/stb/tests/vorbseek/vorbseek.c b/source/engine/thirdparty/stb/tests/vorbseek/vorbseek.c deleted file mode 100644 index f3460ad..0000000 --- a/source/engine/thirdparty/stb/tests/vorbseek/vorbseek.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include - -#define STB_VORBIS_HEADER_ONLY -#include "stb_vorbis.c" - -#define SAMPLES_TO_TEST 3000 - -int test_count [5] = { 5000, 3000, 2000, 50000, 50000 }; -int test_spacing[5] = { 1, 111, 3337, 7779, 72717 }; - -int try_seeking(stb_vorbis *v, unsigned int pos, short *output, unsigned int num_samples) -{ - int count; - short samples[SAMPLES_TO_TEST*2]; - assert(pos <= num_samples); - - if (!stb_vorbis_seek(v, pos)) { - fprintf(stderr, "Seek to %u returned error from stb_vorbis\n", pos); - return 0; - } - - count = stb_vorbis_get_samples_short_interleaved(v, 2, samples, SAMPLES_TO_TEST*2); - - if (count > (int) (num_samples - pos)) { - fprintf(stderr, "Seek to %u allowed decoding %d samples when only %d should have been valid.\n", - pos, count, (int) (num_samples - pos)); - return 0; - } - - if (count < SAMPLES_TO_TEST && count < (int) (num_samples - pos)) { - fprintf(stderr, "Seek to %u only decoded %d samples of %d attempted when at least %d should have been valid.\n", - pos, count, SAMPLES_TO_TEST, num_samples - pos); - return 0; - } - - if (0 != memcmp(samples, output + pos*2, count*2)) { - int k; - for (k=0; k < SAMPLES_TO_TEST*2; ++k) { - if (samples[k] != output[k]) { - fprintf(stderr, "Seek to %u produced incorrect samples starting at sample %u (short #%d in buffer).\n", - pos, pos + (k/2), k); - break; - } - } - assert(k != SAMPLES_TO_TEST*2); - return 0; - } - - return 1; -} - -int main(int argc, char **argv) -{ - int num_chan, samprate; - int i, j, test, phase; - short *output; - - if (argc == 1) { - fprintf(stderr, "Usage: vorbseek {vorbisfile} [{vorbisfile]*]\n"); - fprintf(stderr, "Tests various seek offsets to make sure they're sample exact.\n"); - return 0; - } - - #if 0 - { - // check that outofmem occurs correctly - stb_vorbis_alloc va; - va.alloc_buffer = malloc(1024*1024); - for (i=0; i < 1024*1024; i += 10) { - int error=0; - stb_vorbis *v; - va.alloc_buffer_length_in_bytes = i; - v = stb_vorbis_open_filename(argv[1], &error, &va); - if (v != NULL) - break; - printf("Error %d at %d\n", error, i); - } - } - #endif - - for (j=1; j < argc; ++j) { - unsigned int successes=0, attempts = 0; - unsigned int num_samples = stb_vorbis_decode_filename(argv[j], &num_chan, &samprate, &output); - - break; - - if (num_samples == 0xffffffff) { - fprintf(stderr, "Error: couldn't open file or not vorbis file: %s\n", argv[j]); - goto fail; - } - - if (num_chan != 2) { - fprintf(stderr, "vorbseek testing only works with files with 2 channels, %s has %d\n", argv[j], num_chan); - goto fail; - } - - for (test=0; test < 5; ++test) { - int error; - stb_vorbis *v = stb_vorbis_open_filename(argv[j], &error, NULL); - if (v == NULL) { - fprintf(stderr, "Couldn't re-open %s for test #%d\n", argv[j], test); - goto fail; - } - for (phase=0; phase < 3; ++phase) { - unsigned int base = phase == 0 ? 0 : phase == 1 ? num_samples - test_count[test]*test_spacing[test] : num_samples/3; - for (i=0; i < test_count[test]; ++i) { - unsigned int pos = base + i*test_spacing[test]; - if (pos > num_samples) // this also catches underflows - continue; - successes += try_seeking(v, pos, output, num_samples); - attempts += 1; - } - } - stb_vorbis_close(v); - } - printf("%d of %d seeks failed in %s (%d samples)\n", attempts-successes, attempts, argv[j], num_samples); - free(output); - } - return 0; - fail: - return 1; -} \ No newline at end of file diff --git a/source/engine/thirdparty/stb/tests/vorbseek/vorbseek.dsp b/source/engine/thirdparty/stb/tests/vorbseek/vorbseek.dsp deleted file mode 100644 index 5eaf579..0000000 --- a/source/engine/thirdparty/stb/tests/vorbseek/vorbseek.dsp +++ /dev/null @@ -1,96 +0,0 @@ -# Microsoft Developer Studio Project File - Name="vorbseek" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=vorbseek - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "vorbseek.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "vorbseek.mak" CFG="vorbseek - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "vorbseek - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "vorbseek - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "vorbseek - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /Zd /O2 /I "..\.." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 - -!ELSEIF "$(CFG)" == "vorbseek - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\.." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "vorbseek - Win32 Release" -# Name "vorbseek - Win32 Debug" -# Begin Source File - -SOURCE=..\..\stb_vorbis.c -# End Source File -# Begin Source File - -SOURCE=.\vorbseek.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tools/README.footer.md b/source/engine/thirdparty/stb/tools/README.footer.md deleted file mode 100644 index 3eb8dc0..0000000 --- a/source/engine/thirdparty/stb/tools/README.footer.md +++ /dev/null @@ -1,135 +0,0 @@ - -FAQ ---- - -#### What's the license? - -These libraries are in the public domain. You can do anything you -want with them. You have no legal obligation -to do anything else, although I appreciate attribution. - -They are also licensed under the MIT open source license, if you have lawyers -who are unhappy with public domain. Every source file includes an explicit -dual-license for you to choose from. - -#### How do I use these libraries? - -The idea behind single-header file libraries is that they're easy to distribute and deploy -because all the code is contained in a single file. By default, the .h files in here act as -their own header files, i.e. they declare the functions contained in the file but don't -actually result in any code getting compiled. - -So in addition, you should select _exactly one_ C/C++ source file that actually instantiates -the code, preferably a file you're not editing frequently. This file should define a -specific macro (this is documented per-library) to actually enable the function definitions. -For example, to use stb_image, you should have exactly one C/C++ file that doesn't -include stb_image.h regularly, but instead does - - #define STB_IMAGE_IMPLEMENTATION - #include "stb_image.h" - -The right macro to define is pointed out right at the top of each of these libraries. - -#### Are there other single-file public-domain/open source libraries with minimal dependencies out there? - -[Yes.](https://github.com/nothings/single_file_libs) - -#### If I wrap an stb library in a new library, does the new library have to be public domain/MIT? - -No, because it's public domain you can freely relicense it to whatever license your new -library wants to be. - -#### What's the deal with SSE support in GCC-based compilers? - -stb_image will either use SSE2 (if you compile with -msse2) or -will not use any SIMD at all, rather than trying to detect the -processor at runtime and handle it correctly. As I understand it, -the approved path in GCC for runtime-detection require -you to use multiple source files, one for each CPU configuration. -Because stb_image is a header-file library that compiles in only -one source file, there's no approved way to build both an -SSE-enabled and a non-SSE-enabled variation. - -While we've tried to work around it, we've had multiple issues over -the years due to specific versions of gcc breaking what we're doing, -so we've given up on it. See https://github.com/nothings/stb/issues/280 -and https://github.com/nothings/stb/issues/410 for examples. - -#### Some of these libraries seem redundant to existing open source libraries. Are they better somehow? - -Generally they're only better in that they're easier to integrate, -easier to use, and easier to release (single file; good API; no -attribution requirement). They may be less featureful, slower, -and/or use more memory. If you're already using an equivalent -library, there's probably no good reason to switch. - -#### Can I link directly to the table of stb libraries? - -You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list. - -#### Why do you list "lines of code"? It's a terrible metric. - -Just to give you some idea of the internal complexity of the library, -to help you manage your expectations, or to let you know what you're -getting into. While not all the libraries are written in the same -style, they're certainly similar styles, and so comparisons between -the libraries are probably still meaningful. - -Note though that the lines do include both the implementation, the -part that corresponds to a header file, and the documentation. - -#### Why single-file headers? - -Windows doesn't have standard directories where libraries -live. That makes deploying libraries in Windows a lot more -painful than open source developers on Unix-derivates generally -realize. (It also makes library dependencies a lot worse in Windows.) - -There's also a common problem in Windows where a library was built -against a different version of the runtime library, which causes -link conflicts and confusion. Shipping the libs as headers means -you normally just compile them straight into your project without -making libraries, thus sidestepping that problem. - -Making them a single file makes it very easy to just -drop them into a project that needs them. (Of course you can -still put them in a proper shared library tree if you want.) - -Why not two files, one a header and one an implementation? -The difference between 10 files and 9 files is not a big deal, -but the difference between 2 files and 1 file is a big deal. -You don't need to zip or tar the files up, you don't have to -remember to attach *two* files, etc. - -#### Why "stb"? Is this something to do with Set-Top Boxes? - -No, they are just the initials for my name, Sean T. Barrett. -This was not chosen out of egomania, but as a moderately sane -way of namespacing the filenames and source function names. - -#### Will you add more image types to stb_image.h? - -No. As stb_image use has grown, it has become more important -for us to focus on security of the codebase. Adding new image -formats increases the amount of code we need to secure, so it -is no longer worth adding new formats. - -#### Do you have any advice on how to create my own single-file library? - -Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt - -#### Why public domain? - -I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons. -Some of them are listed here: -https://github.com/nothings/stb/blob/master/docs/why_public_domain.md - -#### Why C? - -Primarily, because I use C, not C++. But it does also make it easier -for other people to use them from other languages. - -#### Why not C99? stdint.h, declare-anywhere, etc. - -I still use MSVC 6 (1998) as my IDE because it has better human factors -for me than later versions of MSVC. diff --git a/source/engine/thirdparty/stb/tools/README.header.md b/source/engine/thirdparty/stb/tools/README.header.md deleted file mode 100644 index 65e0408..0000000 --- a/source/engine/thirdparty/stb/tools/README.header.md +++ /dev/null @@ -1,22 +0,0 @@ -stb -=== - -single-file public domain (or MIT licensed) libraries for C/C++ - -# This project discusses security-relevant bugs in public in Github Issues and Pull Requests, and it may take significant time for security fixes to be implemented or merged. If this poses an unreasonable risk to your project, do not use stb libraries. - -Noteworthy: - -* image loader: [stb_image.h](stb_image.h) -* image writer: [stb_image_write.h](stb_image_write.h) -* image resizer: [stb_image_resize2.h](stb_image_resize2.h) -* font text rasterizer: [stb_truetype.h](stb_truetype.h) -* typesafe containers: [stb_ds.h](stb_ds.h) - -Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, original stb_image_resize -by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 and stb_sprintf by Jeff Roberts. - - - -library | lastest version | category | LoC | description ---------------------- | ---- | -------- | --- | -------------------------------- diff --git a/source/engine/thirdparty/stb/tools/README.list b/source/engine/thirdparty/stb/tools/README.list deleted file mode 100644 index e858783..0000000 --- a/source/engine/thirdparty/stb/tools/README.list +++ /dev/null @@ -1,21 +0,0 @@ -stb_vorbis.c | audio | decode ogg vorbis files from file/memory to float/16-bit signed output -stb_hexwave.h | audio | audio waveform synthesizer -stb_image.h | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC -stb_truetype.h | graphics | parse, decode, and rasterize characters from truetype fonts -stb_image_write.h | graphics | image writing to disk: PNG, TGA, BMP -stb_image_resize2.h | graphics | resize images larger/smaller with good quality -stb_rect_pack.h | graphics | simple 2D rectangle packer with decent quality -stb_perlin.h | graphics | perlin's revised simplex noise w/ different seeds -stb_ds.h | utility | typesafe dynamic array and hash tables for C, will compile in C++ -stb_sprintf.h | utility | fast sprintf, snprintf for C/C++ -stb_textedit.h | user interface | guts of a text editor for games etc implementing them from scratch -stb_voxel_render.h | 3D graphics | Minecraft-esque voxel rendering "engine" with many more features -stb_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor -stb_easy_font.h | 3D graphics | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc -stb_tilemap_editor.h | game dev | embeddable tilemap editor -stb_herringbone_wang_tile.h | game dev | herringbone Wang tile map generator -stb_c_lexer.h | parsing | simplify writing parsers for C-like languages -stb_divide.h | math | more useful 32-bit modulus e.g. "euclidean divide" -stb_connected_components.h | misc | incrementally compute reachability on grids -stb_leakcheck.h | misc | quick-and-dirty malloc/free leak-checking -stb_include.h | misc | implement recursive #include support, particularly for GLSL diff --git a/source/engine/thirdparty/stb/tools/build_matrix.c b/source/engine/thirdparty/stb/tools/build_matrix.c deleted file mode 100644 index 4051020..0000000 --- a/source/engine/thirdparty/stb/tools/build_matrix.c +++ /dev/null @@ -1,137 +0,0 @@ -#define STB_DEFINE -#include "stb.h" - -// true if no error -int run_command(char *batch_file, char *command) -{ - char buffer[4096]; - if (batch_file[0]) { - sprintf(buffer, "%s && %s", batch_file, command); - return system(buffer) == 0; - } else { - return system(command) == 0; - } -} - -typedef struct -{ - char *compiler_name; - char *batchfile; - char *objdir; - char *compiler; - char *args; - char *link; -} compiler_info; - -compiler_info *compilers; -char *shared_args; -char *shared_link; - -typedef struct -{ - char *filelist; -} project_info; - -project_info *projects; - -enum { NONE, IN_COMPILERS, IN_ARGS, IN_PROJECTS, IN_LINK }; - -int main(int argc, char **argv) -{ - int state = NONE; - int i,j,n; - char **line; - if (argc != 2) stb_fatal("Usage: stb_build_matrix {build-file}\n"); - line = stb_stringfile(argv[1], &n); - if (line == 0) stb_fatal("Couldn't open file '%s'\n", argv[1]); - - for (i=0; i < n; ++i) { - char *p = stb_trimwhite(line[i]); - if (p[0] == 0) continue; - else if (p[0] == '#') continue; - else if (0 == stricmp(p, "[compilers]")) { state = IN_COMPILERS; } - else if (0 == stricmp(p, "[args]" )) { state = IN_ARGS ; shared_args = NULL; } - else if (0 == stricmp(p, "[projects]" )) { state = IN_PROJECTS ; } - else if (0 == stricmp(p, "[link]" )) { state = IN_LINK ; shared_link = NULL; } - else { - switch (state) { - case NONE: stb_fatal("Invalid text outside section at line %d.", i+1); - case IN_COMPILERS: { - char buffer[4096]; - int count; - compiler_info ci; - char **tokens = stb_tokens_stripwhite(p, ",", &count), *batch; - if (count > 3) stb_fatal("Expecting name and batch file name at line %d.", i+1); - batch = (count==1 ? tokens[0] : tokens[1]); - if (strlen(batch)) - sprintf(buffer, "c:\\%s.bat", batch); - else - strcpy(buffer, ""); - ci.compiler_name = strdup(tokens[0]); - ci.batchfile = strdup(buffer); - ci.compiler = count==3 ? strdup(tokens[2]) : "cl"; - if (0==strnicmp(batch, "vcvars_", 7)) - ci.objdir = strdup(stb_sprintf("vs_%s_%d", batch+7, i)); - else - ci.objdir = strdup(stb_sprintf("%s_%d", batch, i)); - ci.args = shared_args; - ci.link = shared_link; - stb_arr_push(compilers, ci); - break; - } - case IN_ARGS: { - stb_arr_push(shared_args, ' '); - for (j=0; p[j] != 0; ++j) - stb_arr_push(shared_args, p[j]); - break; - } - case IN_LINK: { - stb_arr_push(shared_link, ' '); - for (j=0; p[j] != 0; ++j) - stb_arr_push(shared_link, p[j]); - break; - } - case IN_PROJECTS: { - project_info pi; - pi.filelist = strdup(p); - stb_arr_push(projects, pi); - break; - } - } - } - } - - _mkdir("obj"); - for (j=0; j < stb_arr_len(compilers); ++j) { - char command[4096]; - for (i=0; i < stb_arr_len(projects); ++i) { - int r; - _mkdir(stb_sprintf("obj/%s", compilers[j].objdir)); - if (stb_suffix(compilers[j].compiler, "cl")) - sprintf(command, "%s %.*s %s /link %.*s", - compilers[j].compiler, - stb_arr_len(compilers[j].args), compilers[j].args, - projects[i].filelist, - stb_arr_len(compilers[j].link), compilers[j].link); - else - sprintf(command, "%s %.*s %s %.*s", - compilers[j].compiler, - stb_arr_len(compilers[j].args), compilers[j].args, - projects[i].filelist, - stb_arr_len(compilers[j].link), compilers[j].link); - r = run_command(compilers[j].batchfile, command); - stbprint("{%c== Compiler %s == Building %s}\n", r ? '$' : '!', compilers[j].compiler_name, projects[i].filelist); - stb_copyfile("a.exe", stb_sprintf("obj/%s/a.exe", compilers[j].objdir)); - //printf("Copy: %s to %s\n", "a.exe", stb_sprintf("obj/%s/a.exe", compilers[j].objdir)); - stb_copyfile("temp.exe", stb_sprintf("obj/%s/temp.exe", compilers[j].objdir)); - system("if EXIST a.exe del /q a.exe"); - system("if EXIST temp.exe del /q temp.exe"); - system("if EXIST *.obj del /q *.obj"); - system("if EXIST *.o del /q *.o"); - if (!r) - return 1; - } - } - - return 0; -} diff --git a/source/engine/thirdparty/stb/tools/easy_font_maker.c b/source/engine/thirdparty/stb/tools/easy_font_maker.c deleted file mode 100644 index f1b4836..0000000 --- a/source/engine/thirdparty/stb/tools/easy_font_maker.c +++ /dev/null @@ -1,211 +0,0 @@ -// This program was used to encode the data for stb_simple_font.h - -#define STB_DEFINE -#include "stb.h" -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -int w,h; -uint8 *data; - -int last_x[2], last_y[2]; -int num_seg[2], non_empty; -#if 0 -typedef struct -{ - unsigned short first_segment; - unsigned char advance; -} chardata; - -typedef struct -{ - unsigned char x:4; - unsigned char y:4; - unsigned char len:3; - unsigned char dir:1; -} segment; - -segment *segments; - -void add_seg(int x, int y, int len, int horizontal) -{ - segment s; - s.x = x; - s.y = y; - s.len = len; - s.dir = horizontal; - assert(s.x == x); - assert(s.y == y); - assert(s.len == len); - stb_arr_push(segments, s); -} -#else -typedef struct -{ - unsigned char first_segment:8; - unsigned char first_v_segment:8; - unsigned char advance:5; - unsigned char voff:1; -} chardata; - -#define X_LIMIT 1 -#define LEN_LIMIT 7 - -typedef struct -{ - unsigned char dx:1; - unsigned char y:4; - unsigned char len:3; -} segment; - -segment *segments; -segment *vsegments; - -void add_seg(int x, int y, int len, int horizontal) -{ - segment s; - - while (x - last_x[horizontal] > X_LIMIT) { - add_seg(last_x[horizontal] + X_LIMIT, 0, 0, horizontal); - } - while (len > LEN_LIMIT) { - add_seg(x, y, LEN_LIMIT, horizontal); - len -= LEN_LIMIT; - x += LEN_LIMIT*horizontal; - y += LEN_LIMIT*!horizontal; - } - - s.dx = x - last_x[horizontal]; - s.y = y; - s.len = len; - non_empty += len != 0; - //assert(s.x == x); - assert(s.y == y); - assert(s.len == len); - ++num_seg[horizontal]; - if (horizontal) - stb_arr_push(segments, s); - else - stb_arr_push(vsegments, s); - last_x[horizontal] = x; -} - -void print_segments(segment *s) -{ - int i, hpos; - printf(" "); - hpos = 4; - for (i=0; i < stb_arr_len(s); ++i) { - // repack for portability - unsigned char seg = s[i].len + s[i].dx*8 + s[i].y*16; - hpos += printf("%d,", seg); - if (hpos > 72 && i+1 < stb_arr_len(s)) { - hpos = 4; - printf("\n "); - } - } - printf("\n"); -} - -#endif - -chardata charinfo[128]; - -int parse_char(int x, chardata *c, int offset) -{ - int start_x = x, end_x, top_y = 0, y; - - c->first_segment = stb_arr_len(segments); - c->first_v_segment = stb_arr_len(vsegments) - offset; - assert(c->first_segment == stb_arr_len(segments)); - assert(c->first_v_segment + offset == stb_arr_len(vsegments)); - - // find advance distance - end_x = x+1; - while (data[end_x*3] == 255) - ++end_x; - c->advance = end_x - start_x + 1; - - last_x[0] = last_x[1] = 0; - last_y[0] = last_y[1] = 0; - - for (y=2; y < h; ++y) { - for (x=start_x; x < end_x; ++x) { - if (data[y*3*w+x*3+1] < 255) { - top_y = y; - break; - } - } - if (top_y) - break; - } - c->voff = top_y > 2; - if (top_y > 2) - top_y = 3; - - for (x=start_x; x < end_x; ++x) { - int y; - for (y=2; y < h; ++y) { - if (data[y*3*w+x*3+1] < 255) { - if (data[y*3*w+x*3+0] == 255) { // red - int len=0; - while (y+len < h && data[(y+len)*3*w+x*3+0] == 255 && data[(y+len)*3*w+x*3+1] == 0) { - data[(y+len)*3*w+x*3+0] = 0; - ++len; - } - add_seg(x-start_x,y-top_y,len,0); - } - if (data[y*3*w+x*3+2] == 255) { // blue - int len=0; - while (x+len < end_x && data[y*3*w+(x+len)*3+2] == 255 && data[y*3*w+(x+len)*3+1] == 0) { - data[y*3*w+(x+len)*3+2] = 0; - ++len; - } - add_seg(x-start_x,y-top_y,len,1); - } - } - } - } - return end_x; -} - - -int main(int argc, char **argv) -{ - int c, x=0; - data = stbi_load("easy_font_raw.png", &w, &h, 0, 3); - for (c=32; c < 127; ++c) { - x = parse_char(x, &charinfo[c], 0); - printf("%3d -- %3d %3d\n", c, charinfo[c].first_segment, charinfo[c].first_v_segment); - } - printf("===\n"); - printf("%d %d %d\n", num_seg[0], num_seg[1], non_empty); - printf("%d\n", sizeof(segments[0]) * stb_arr_len(segments)); - printf("%d\n", sizeof(segments[0]) * stb_arr_len(segments) + sizeof(segments[0]) * stb_arr_len(vsegments) + sizeof(charinfo[32])*95); - - printf("struct {\n" - " unsigned char advance;\n" - " unsigned char h_seg;\n" - " unsigned char v_seg;\n" - "} stb_easy_font_charinfo[96] = {\n"); - charinfo[c].first_segment = stb_arr_len(segments); - charinfo[c].first_v_segment = stb_arr_len(vsegments); - for (c=32; c < 128; ++c) { - if ((c & 3) == 0) printf(" "); - printf("{ %2d,%3d,%3d },", - charinfo[c].advance + 16*charinfo[c].voff, - charinfo[c].first_segment, - charinfo[c].first_v_segment); - if ((c & 3) == 3) printf("\n"); else printf(" "); - } - printf("};\n\n"); - - printf("unsigned char stb_easy_font_hseg[%d] = {\n", stb_arr_len(segments)); - print_segments(segments); - printf("};\n\n"); - - printf("unsigned char stb_easy_font_vseg[%d] = {\n", stb_arr_len(vsegments)); - print_segments(vsegments); - printf("};\n"); - return 0; -} diff --git a/source/engine/thirdparty/stb/tools/make_readme.c b/source/engine/thirdparty/stb/tools/make_readme.c deleted file mode 100644 index bca9d2b..0000000 --- a/source/engine/thirdparty/stb/tools/make_readme.c +++ /dev/null @@ -1,65 +0,0 @@ -#define STB_DEFINE -#include "../stb.h" - -int main(int argc, char **argv) -{ - int i; - int hlen, flen, listlen, total_lines = 0; - char *header = stb_file("README.header.md", &hlen); // stb_file - read file into malloc()ed buffer - char *footer = stb_file("README.footer.md", &flen); // stb_file - read file into malloc()ed buffer - char **list = stb_stringfile("README.list", &listlen); // stb_stringfile - read file lines into malloced array of strings - - FILE *f = fopen("../README.md", "wb"); - - fprintf(f, "\r\n\r\n"); - fwrite(header, 1, hlen, f); - - for (i=0; i < listlen; ++i) { - int num,j; - char **tokens = stb_tokens_stripwhite(list[i], "|", &num); // stb_tokens -- tokenize string into malloced array of strings - int num_lines; - char **lines = stb_stringfile(stb_sprintf("../%s", tokens[0]), &num_lines); - char *s1, *s2,*s3; - if (lines == NULL) stb_fatal("Couldn't open '%s'", tokens[0]); - s1 = strchr(lines[0], '-'); - if (!s1) stb_fatal("Couldn't find '-' before version number in %s", tokens[0]); // stb_fatal -- print error message & exit - s2 = strchr(s1+2, '-'); - if (!s2) stb_fatal("Couldn't find '-' after version number in %s", tokens[0]); // stb_fatal -- print error message & exit - *s2 = 0; - s1 += 1; - s1 = stb_trimwhite(s1); // stb_trimwhite -- advance pointer to after whitespace & delete trailing whitespace - if (*s1 == 'v') ++s1; - s3 = tokens[0]; - stb_trimwhite(s3); - fprintf(f, "**["); - if (strlen(s3) < 21) { - fprintf(f, "%s", tokens[0]); - } else { - char buffer[256]; - strncpy(buffer, s3, 18); - buffer[18] = 0; - strcat(buffer, "..."); - fprintf(f, "%s", buffer); - } - fprintf(f, "](%s)**", tokens[0]); - fprintf(f, " | %s", s1); - s1 = stb_trimwhite(tokens[1]); // stb_trimwhite -- advance pointer to after whitespace & delete trailing whitespace - s2 = stb_dupreplace(s1, " ", " "); // stb_dupreplace -- search & replace string and malloc result - fprintf(f, " | %s", s2); - free(s2); - fprintf(f, " | %d", num_lines); - total_lines += num_lines; - for (j=2; j < num; ++j) - fprintf(f, " | %s", tokens[j]); - fprintf(f, "\r\n"); - } - - fprintf(f, "\r\n"); - fprintf(f, "Total libraries: %d\r\n", listlen); - fprintf(f, "Total lines of C code: %d\r\n\r\n", total_lines); - - fwrite(footer, 1, flen, f); - fclose(f); - - return 0; -} diff --git a/source/engine/thirdparty/stb/tools/make_readme.dsp b/source/engine/thirdparty/stb/tools/make_readme.dsp deleted file mode 100644 index 232dd86..0000000 --- a/source/engine/thirdparty/stb/tools/make_readme.dsp +++ /dev/null @@ -1,97 +0,0 @@ -# Microsoft Developer Studio Project File - Name="make_readme" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=make_readme - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "make_readme.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "make_readme.mak" CFG="make_readme - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "make_readme - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "make_readme - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "make_readme - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "make_readme - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug\make_readme" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "make_readme - Win32 Release" -# Name "make_readme - Win32 Debug" -# Begin Source File - -SOURCE=.\make_readme.c -# End Source File -# Begin Source File - -SOURCE=.\README.header.md -# End Source File -# Begin Source File - -SOURCE=.\README.list -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/stb/tools/mr.bat b/source/engine/thirdparty/stb/tools/mr.bat deleted file mode 100644 index 475bc4f..0000000 --- a/source/engine/thirdparty/stb/tools/mr.bat +++ /dev/null @@ -1 +0,0 @@ -debug\make_readme diff --git a/source/engine/thirdparty/stb/tools/trailing_whitespace.c b/source/engine/thirdparty/stb/tools/trailing_whitespace.c deleted file mode 100644 index 55afc87..0000000 --- a/source/engine/thirdparty/stb/tools/trailing_whitespace.c +++ /dev/null @@ -1,32 +0,0 @@ -#define STB_DEFINE -#include "stb.h" - -int main(int argc, char **argv) -{ - int i; - for (i=1; i < argc; ++i) { - int len; - FILE *f; - char *s = stb_file(argv[i], &len); - char *end, *src, *dest; - if (s == NULL) { - printf("Couldn't read file '%s'.\n", argv[i]); - continue; - } - end = s + len; - src = dest = s; - while (src < end) { - char *start=0; - while (src < end && *src != '\n' && *src != '\r') - *dest++ = *src++; - while (dest-1 > s && (dest[-1] == ' ' || dest[-1] == '\t')) - --dest; - while (src < end && (*src == '\n' || *src == '\r')) - *dest++ = *src++; - } - f = fopen(argv[i], "wb"); - fwrite(s, 1, dest-s, f); - fclose(f); - } - return 0; -} diff --git a/source/engine/thirdparty/stb/tools/unicode.c b/source/engine/thirdparty/stb/tools/unicode.c deleted file mode 100644 index 9536d5d..0000000 --- a/source/engine/thirdparty/stb/tools/unicode.c +++ /dev/null @@ -1,749 +0,0 @@ -#define STB_DEFINE -#include "../stb.h" - -// create unicode mappings -// -// Two kinds of mappings: -// map to a number -// map to a bit -// -// For mapping to a number, we use the following strategy: -// -// User supplies: -// 1. a table of numbers (for now we use uint16, so full Unicode table is 4MB) -// 2. a "don't care" value -// 3. define a 'fallback' value (typically 0) -// 4. define a fast-path range (typically 0..255 or 0..1023) [@TODO: automate detecting this] -// -// Code: -// 1. Determine range of *end* of unicode codepoints (U+10FFFF and down) which -// all have the same value (or don't care). If large enough, emit this as a -// special case in the code. -// 2. Repeat above, limited to at most U+FFFF. -// 3. Cluster the data into intervals of 8,16,32,64,128,256 numeric values. -// 3a. If all the values in an interval are fallback/dont-care, no further processing -// 3b. Find the "trimmed range" outside which all the values are the fallback or don't care -// 3c. Find the "special trimmed range" outside which all the values are some constant or don't care -// 4. Pack the clusters into continuous memory, and find previous instances of -// the cluster. Repeat for trimmed & special-trimmed. In the first case, find -// previous instances of the cluster (allow don't-care to match in either -// direction), both aligned and mis-aligned; in the latter, starting where -// things start or mis-aligned. Build an index table specifying the -// location of each cluster (and its length). Allow an extra indirection here; -// the full-sized index can index a smaller table which has the actual offset -// (and lengths). -// 5. Associate with each packed continuous memory above the amount of memory -// required to store the data w/ smallest datatype (of uint8, uint16, uint32). -// Discard the continuous memory. Recurse on each index table, but avoid the -// smaller packing. -// -// For mapping to a bit, we pack the results for 8 characters into a byte, and then apply -// the above strategy. Note that there may be more optimal approaches with e.g. packing -// 8 different bits into a single structure, though, which we should explore eventually. - - -// currently we limit *indices* to being 2^16, and we pack them as -// index + end_trim*2^16 + start_trim*2^24; specials have to go in a separate table -typedef uint32 uval; -#define UVAL_DONT_CARE_DEFAULT 0xffffffff - -typedef struct -{ - uval *input; - uint32 dont_care; - uint32 fallback; - int fastpath; - int length; - int depth; - int has_sign; - int splittable; - int replace_fallback_with_codepoint; - size_t input_size; - size_t inherited_storage; -} table; - -typedef struct -{ - int split_log2; - table result; // index into not-returned table - int storage; -} output; - -typedef struct -{ - table t; - char **output_name; -} info; - -typedef struct -{ - size_t path; - size_t size; -} result; - -typedef struct -{ - uint8 trim_end; - uint8 trim_start; - uint8 special; - uint8 aligned; - uint8 indirect; - - uint16 overhead; // add some forced overhead for each mode to avoid getting complex encoding when it doesn't save much - -} mode_info; - -mode_info modes[] = -{ - { 0,0,0,0,0, 32, }, - { 0,0,0,0,1, 100, }, - { 0,0,0,1,0, 32, }, - { 0,0,0,1,1, 100, }, - { 0,0,1,0,1, 100, }, - { 0,0,1,1,0, 32, }, - { 0,0,1,1,1, 200, }, - { 1,0,0,0,0, 100, }, - { 1,0,0,0,1, 120, }, - { 1,1,0,0,0, 100, }, - { 1,1,0,0,1, 130, }, - { 1,0,1,0,0, 130, }, - { 1,0,1,0,1, 180, }, - { 1,1,1,0,0, 180, }, - { 1,1,1,0,1, 200, }, -}; - -#define MODECOUNT (sizeof(modes)/sizeof(modes[0])) -#define CLUSTERSIZECOUNT 6 // 8,16, 32,64, 128,256 - -size_t size_for_max_number(uint32 number) -{ - if (number == 0) return 0; - if (number < 256) return 1; - if (number < 256*256) return 2; - if (number < 256*256*256) return 3; - return 4; -} - -size_t size_for_max_number_aligned(uint32 number) -{ - size_t n = size_for_max_number(number); - return n == 3 ? 4 : n; -} - -uval get_data(uval *data, int offset, uval *end) -{ - if (data + offset >= end) - return 0; - else - return data[offset]; -} - -int safe_len(uval *data, int len, uval *end) -{ - if (len > end - data) - return end - data; - return len; -} - -uval tempdata[256]; -int dirty=0; - -size_t find_packed(uval **packed, uval *data, int len, int aligned, int fastpath, uval *end, int offset, int replace) -{ - int packlen = stb_arr_len(*packed); - int i,p; - - if (data+len > end || replace) { - int safelen = safe_len(data, len, end); - memset(tempdata, 0, dirty*sizeof(tempdata[0])); - memcpy(tempdata, data, safelen * sizeof(data[0])); - data = tempdata; - dirty = len; - } - if (replace) { - int i; - int safelen = safe_len(data, len, end); - for (i=0; i < safelen; ++i) - if (data[i] == 0) - data[i] = offset+i; - } - - if (len <= 0) - return 0; - if (!fastpath) { - if (aligned) { - for (i=0; i < packlen; i += len) - if ((*packed)[i] == data[0] && 0==memcmp(&(*packed)[i], data, len * sizeof(uval))) - return i / len; - } else { - for (i=0; i < packlen-len+1; i += 1 ) - if ((*packed)[i] == data[0] && 0==memcmp(&(*packed)[i], data, len * sizeof(uval))) - return i; - } - } - p = stb_arr_len(*packed); - for (i=0; i < len; ++i) - stb_arr_push(*packed, data[i]); - return p; -} - -void output_table(char *name1, char *name2, uval *data, int length, int sign, char **names) -{ - char temp[20]; - uval maxv = 0; - int bytes, numlen, at_newline; - int linelen = 79; // @TODO: make table more readable by choosing a length that's a multiple? - int i,pos, do_split=0; - for (i=0; i < length; ++i) - if (sign) - maxv = stb_max(maxv, (uval)abs((int)data[i])); - else - maxv = stb_max(maxv, data[i]); - bytes = size_for_max_number_aligned(maxv); - sprintf(temp, "%d", maxv); - numlen=strlen(temp); - if (sign) - ++numlen; - - if (bytes == 0) - return; - - printf("uint%d %s%s[%d] = {\n", bytes*8, name1, name2, length); - at_newline = 1; - for (i=0; i < length; ++i) { - if (pos + numlen + 2 > linelen) { - printf("\n"); - at_newline = 1; - pos = 0; - } - if (at_newline) { - printf(" "); - pos = 2; - at_newline = 0; - } else { - printf(" "); - ++pos; - } - printf("%*d,", numlen, data[i]); - pos += numlen+1; - } - if (!at_newline) printf("\n"); - printf("};\n"); -} - -void output_table_with_trims(char *name1, char *name2, uval *data, int length) -{ - uval maxt=0, maxp=0; - int i,d,s,e, count; - // split the table into two pieces - uval *trims = NULL; - - if (length == 0) - return; - - for (i=0; i < stb_arr_len(data); ++i) { - stb_arr_push(trims, data[i] >> 16); - data[i] &= 0xffff; - maxt = stb_max(maxt, trims[i]); - maxp = stb_max(maxp, data[i]); - } - - d=s=e=1; - if (maxt >= 256) { - // need to output start & end values - if (maxp >= 256) { - // can pack into a single table - printf("struct { uint16 val; uint8 start, end; } %s%s[%d] = {\n", name1, name2, length); - } else { - output_table(name1, name2, data, length, 0, 0); - d=0; - printf("struct { uint8 start, end; } %s%s_trim[%d] = {\n", name1, name2, length); - } - } else if (maxt > 0) { - if (maxp >= 256) { - output_table(name1, name2, data, length, 0, 0); - output_table(name1, stb_sprintf("%s_end", name2), trims, length, 0, 0); - return; - } else { - printf("struct { uint8 val, end; } %s%s[%d] = {\n", name1, name2, length); - s=0; - } - } else { - output_table(name1, name2, data, length, 0, 0); - return; - } - // d or s can be zero (but not both), e is always present and last - count = d + s + e; - assert(count >= 2 && count <= 3); - - { - char temp[60]; - uval maxv = 0; - int numlen, at_newline, len; - int linelen = 79; // @TODO: make table more readable by choosing a length that's a multiple? - int i,pos, do_split=0; - numlen = 0; - for (i=0; i < length; ++i) { - if (count == 2) - sprintf(temp, "{%d,%d}", d ? data[i] : (trims[i]>>8), trims[i]&255); - else - sprintf(temp, "{%d,%d,%d}", data[i], trims[i]>>8, trims[i]&255); - len = strlen(temp); - numlen = stb_max(len, numlen); - } - - at_newline = 1; - for (i=0; i < length; ++i) { - if (pos + numlen + 2 > linelen) { - printf("\n"); - at_newline = 1; - pos = 0; - } - if (at_newline) { - printf(" "); - pos = 2; - at_newline = 0; - } else { - printf(" "); - ++pos; - } - if (count == 2) - sprintf(temp, "{%d,%d}", d ? data[i] : (trims[i]>>8), trims[i]&255); - else - sprintf(temp, "{%d,%d,%d}", data[i], trims[i]>>8, trims[i]&255); - printf("%*s,", numlen, temp); - pos += numlen+1; - } - if (!at_newline) printf("\n"); - printf("};\n"); - } -} - -int weight=1; - -table pack_for_mode(table *t, int mode, char *table_name) -{ - size_t extra_size; - int i; - uval maxv; - mode_info mi = modes[mode % MODECOUNT]; - int size = 8 << (mode / MODECOUNT); - table newtab; - uval *packed = NULL; - uval *index = NULL; - uval *indirect = NULL; - uval *specials = NULL; - newtab.dont_care = UVAL_DONT_CARE_DEFAULT; - if (table_name) - printf("// clusters of %d\n", size); - for (i=0; i < t->length; i += size) { - uval newval; - int fastpath = (i < t->fastpath); - if (mi.special) { - int end_trim = size-1; - int start_trim = 0; - uval special; - // @TODO: pick special from start or end instead of only end depending on which is longer - for(;;) { - special = t->input[i + end_trim]; - if (special != t->dont_care || end_trim == 0) - break; - --end_trim; - } - // at this point, special==inp[end_trim], and end_trim >= 0 - if (special == t->dont_care && !fastpath) { - // entire block is don't care, so OUTPUT don't care - stb_arr_push(index, newtab.dont_care); - continue; - } else { - uval pos, trim; - if (mi.trim_end && !fastpath) { - while (end_trim >= 0) { - if (t->input[i + end_trim] == special || t->input[i + end_trim] == t->dont_care) - --end_trim; - else - break; - } - } - - if (mi.trim_start && !fastpath) { - while (start_trim < end_trim) { - if (t->input[i + start_trim] == special || t->input[i + start_trim] == t->dont_care) - ++start_trim; - else - break; - } - } - - // end_trim points to the last character we have to output - - // find the first match, or add it - pos = find_packed(&packed, &t->input[i+start_trim], end_trim-start_trim+1, mi.aligned, fastpath, &t->input[t->length], i+start_trim, t->replace_fallback_with_codepoint); - - // encode as a uval - if (!mi.trim_end) { - if (end_trim == 0) - pos = special; - else - pos = pos | 0x80000000; - } else { - assert(end_trim < size && end_trim >= -1); - if (!fastpath) assert(end_trim < size-1); // special always matches last one - assert(end_trim < size && end_trim+1 >= 0); - if (!fastpath) assert(end_trim+1 < size); - - if (mi.trim_start) - trim = start_trim*256 + (end_trim+1); - else - trim = end_trim+1; - - assert(pos < 65536); // @TODO: if this triggers, just bail on this search path - pos = pos + (trim << 16); - } - - newval = pos; - - stb_arr_push(specials, special); - } - } else if (mi.trim_end) { - int end_trim = size-1; - int start_trim = 0; - uval pos, trim; - - while (end_trim >= 0 && !fastpath) - if (t->input[i + end_trim] == t->fallback || t->input[i + end_trim] == t->dont_care) - --end_trim; - else - break; - - if (mi.trim_start && !fastpath) { - while (start_trim < end_trim) { - if (t->input[i + start_trim] == t->fallback || t->input[i + start_trim] == t->dont_care) - ++start_trim; - else - break; - } - } - - // end_trim points to the last character we have to output, and can be -1 - ++end_trim; // make exclusive at end - - if (end_trim == 0 && size == 256) - start_trim = end_trim = 1; // we can't make encode a length from 0..256 in 8 bits, so restrict end_trim to 1..256 - - // find the first match, or add it - pos = find_packed(&packed, &t->input[i+start_trim], end_trim - start_trim, mi.aligned, fastpath, &t->input[t->length], i+start_trim, t->replace_fallback_with_codepoint); - - assert(end_trim <= size && end_trim >= 0); - if (size == 256) - assert(end_trim-1 < 256 && end_trim-1 >= 0); - else - assert(end_trim < 256 && end_trim >= 0); - if (size == 256) - --end_trim; - - if (mi.trim_start) - trim = start_trim*256 + end_trim; - else - trim = end_trim; - - assert(pos < 65536); // @TODO: if this triggers, just bail on this search path - pos = pos + (trim << 16); - - newval = pos; - } else { - newval = find_packed(&packed, &t->input[i], size, mi.aligned, fastpath, &t->input[t->length], i, t->replace_fallback_with_codepoint); - } - - if (mi.indirect) { - int j; - for (j=0; j < stb_arr_len(indirect); ++j) - if (indirect[j] == newval) - break; - if (j == stb_arr_len(indirect)) - stb_arr_push(indirect, newval); - stb_arr_push(index, j); - } else { - stb_arr_push(index, newval); - } - } - - // total up the new size for everything but the index table - extra_size = mi.overhead * weight; // not the actual overhead cost; a penalty to avoid excessive complexity - extra_size += 150; // per indirection - if (table_name) - extra_size = 0; - - if (t->has_sign) { - // 'packed' contains two values, which should be packed positive & negative for size - uval maxv2; - for (i=0; i < stb_arr_len(packed); ++i) - if (packed[i] & 0x80000000) - maxv2 = stb_max(maxv2, packed[i]); - else - maxv = stb_max(maxv, packed[i]); - maxv = stb_max(maxv, maxv2) << 1; - } else { - maxv = 0; - for (i=0; i < stb_arr_len(packed); ++i) - if (packed[i] > maxv && packed[i] != t->dont_care) - maxv = packed[i]; - } - extra_size += stb_arr_len(packed) * (t->splittable ? size_for_max_number(maxv) : size_for_max_number_aligned(maxv)); - if (table_name) { - if (t->splittable) - output_table_with_trims(table_name, "", packed, stb_arr_len(packed)); - else - output_table(table_name, "", packed, stb_arr_len(packed), t->has_sign, NULL); - } - - maxv = 0; - for (i=0; i < stb_arr_len(specials); ++i) - if (specials[i] > maxv) - maxv = specials[i]; - extra_size += stb_arr_len(specials) * size_for_max_number_aligned(maxv); - if (table_name) - output_table(table_name, "_default", specials, stb_arr_len(specials), 0, NULL); - - maxv = 0; - for (i=0; i < stb_arr_len(indirect); ++i) - if (indirect[i] > maxv) - maxv = indirect[i]; - extra_size += stb_arr_len(indirect) * size_for_max_number(maxv); - - if (table_name && stb_arr_len(indirect)) { - if (mi.trim_end) - output_table_with_trims(table_name, "_index", indirect, stb_arr_len(indirect)); - else { - assert(0); // this case should only trigger in very extreme circumstances - output_table(table_name, "_index", indirect, stb_arr_len(indirect), 0, NULL); - } - mi.trim_end = mi.special = 0; - } - - if (table_name) - printf("// above tables should be %d bytes\n", extra_size); - - maxv = 0; - for (i=0; i < stb_arr_len(index); ++i) - if (index[i] > maxv && index[i] != t->dont_care) - maxv = index[i]; - newtab.splittable = mi.trim_end; - newtab.input_size = newtab.splittable ? size_for_max_number(maxv) : size_for_max_number_aligned(maxv); - newtab.input = index; - newtab.length = stb_arr_len(index); - newtab.inherited_storage = t->inherited_storage + extra_size; - newtab.fastpath = 0; - newtab.depth = t->depth+1; - stb_arr_free(indirect); - stb_arr_free(packed); - stb_arr_free(specials); - - return newtab; -} - -result pack_table(table *t, size_t path, int min_storage) -{ - int i; - result best; - best.size = t->inherited_storage + t->input_size * t->length; - best.path = path; - - if ((int) t->inherited_storage > min_storage) { - best.size = stb_max(best.size, t->inherited_storage); - return best; - } - - if (t->length <= 256 || t->depth >= 4) { - //printf("%08x: %7d\n", best.path, best.size); - return best; - } - - path <<= 7; - for (i=0; i < MODECOUNT * CLUSTERSIZECOUNT; ++i) { - table newtab; - result r; - newtab = pack_for_mode(t, i, 0); - r = pack_table(&newtab, path+i+1, min_storage); - if (r.size < best.size) - best = r; - stb_arr_free(newtab.input); - //printf("Size: %6d + %6d\n", newtab.inherited_storage, newtab.input_size * newtab.length); - } - return best; -} - -int pack_table_by_modes(table *t, int *modes) -{ - table s = *t; - while (*modes > -1) { - table newtab; - newtab = pack_for_mode(&s, *modes, 0); - if (s.input != t->input) - stb_arr_free(s.input); - s = newtab; - ++modes; - } - return s.inherited_storage + s.input_size * s.length; -} - -int strip_table(table *t, int exceptions) -{ - uval terminal_value; - int p = t->length-1; - while (t->input[p] == t->dont_care) - --p; - terminal_value = t->input[p]; - - while (p >= 0x10000) { - if (t->input[p] != terminal_value && t->input[p] != t->dont_care) { - if (exceptions) - --exceptions; - else - break; - } - --p; - } - return p+1; // p is a character we must output -} - -void optimize_table(table *t, char *table_name) -{ - int modelist[3] = { 85, -1 }; - int modes[8]; - int num_modes = 0; - int decent_size; - result r; - size_t path; - table s; - - // strip tail end of table - int orig_length = t->length; - int threshhold = 0xffff; - int p = strip_table(t, 2); - int len_saved = t->length - p; - if (len_saved >= threshhold) { - t->length = p; - while (p > 0x10000) { - p = strip_table(t, 0); - len_saved = t->length - p; - if (len_saved < 0x10000) - break; - len_saved = orig_length - p; - if (len_saved < threshhold) - break; - threshhold *= 2; - } - } - - t->depth = 1; - - - // find size of table if we use path 86 - decent_size = pack_table_by_modes(t, modelist); - - - #if 1 - // find best packing of remainder of table by exploring tree of packings - r = pack_table(t, 0, decent_size); - // use the computed 'path' to evaluate and output tree - path = r.path; - #else - path = 86;//90;//132097; - #endif - - while (path) { - modes[num_modes++] = (path & 127) - 1; - path >>= 7; - } - - printf("// modes: %d\n", r.path); - s = *t; - while (num_modes > 0) { - char name[256]; - sprintf(name, "%s_%d", table_name, num_modes+1); - --num_modes; - s = pack_for_mode(&s, modes[num_modes], name); - } - // output the final table as-is - if (s.splittable) - output_table_with_trims(table_name, "_1", s.input, s.length); - else - output_table(table_name, "_1", s.input, s.length, 0, NULL); -} - -uval unicode_table[0x110000]; - -typedef struct -{ - uval lo,hi; -} char_range; - -char_range get_range(char *str) -{ - char_range cr; - char *p; - cr.lo = strtol(str, &p, 16); - p = stb_skipwhite(p); - if (*p == '.') - cr.hi = strtol(p+2, NULL, 16); - else - cr.hi = cr.lo; - return cr; -} - -char *skip_semi(char *s, int count) -{ - while (count) { - s = strchr(s, ';'); - assert(s != NULL); - ++s; - --count; - } - return s; -} - -int main(int argc, char **argv) -{ - table t; - uval maxv=0; - int i,n=0; - char **s = stb_stringfile("../../data/UnicodeData.txt", &n); - assert(s); - for (i=0; i < n; ++i) { - if (s[i][0] == '#' || s[i][0] == '\n' || s[i][0] == 0) - ; - else { - char_range cr = get_range(s[i]); - char *t = skip_semi(s[i], 13); - uval j, v; - if (*t == ';' || *t == '\n' || *t == 0) - v = 0; - else { - v = strtol(t, NULL, 16); - if (v < 65536) { - maxv = stb_max(v, maxv); - for (j=cr.lo; j <= cr.hi; ++j) { - unicode_table[j] = v; - //printf("%06x => %06x\n", j, v); - } - } - } - } - } - - t.depth = 0; - t.dont_care = UVAL_DONT_CARE_DEFAULT; - t.fallback = 0; - t.fastpath = 256; - t.inherited_storage = 0; - t.has_sign = 0; - t.splittable = 0; - t.input = unicode_table; - t.input_size = size_for_max_number(maxv); - t.length = 0x110000; - t.replace_fallback_with_codepoint = 1; - - optimize_table(&t, "stbu_upppercase"); - return 0; -} diff --git a/source/engine/thirdparty/stb/tools/unicode/unicode.dsp b/source/engine/thirdparty/stb/tools/unicode/unicode.dsp deleted file mode 100644 index 78e6a5b..0000000 --- a/source/engine/thirdparty/stb/tools/unicode/unicode.dsp +++ /dev/null @@ -1,88 +0,0 @@ -# Microsoft Developer Studio Project File - Name="unicode" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=unicode - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "unicode.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "unicode.mak" CFG="unicode - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "unicode - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "unicode - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "unicode - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "unicode - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "unicode - Win32 Release" -# Name "unicode - Win32 Debug" -# Begin Source File - -SOURCE=..\unicode.c -# End Source File -# End Target -# End Project diff --git a/source/engine/thirdparty/tinycdb/Makefile b/source/engine/thirdparty/tinycdb/Makefile deleted file mode 100644 index 9d7d6d9..0000000 --- a/source/engine/thirdparty/tinycdb/Makefile +++ /dev/null @@ -1,175 +0,0 @@ -#! /usr/bin/make -rf -# Makefile: make file for tinycdb package -# -# This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru. -# Public domain. - -VERSION = 0.80 - -prefix=/usr/local -exec_prefix=$(prefix) -bindir=$(exec_prefix)/bin -libdir=$(exec_prefix)/lib -syslibdir=$(libdir) -sysconfdir=/etc -includedir=$(prefix)/include -mandir=$(prefix)/man -NSSCDB_DIR = $(sysconfdir) -DESTDIR= - -CC = cc -CFLAGS = -O2 -CDEFS = -D_FILE_OFFSET_BITS=64 -LD = $(CC) -LDFLAGS = - -AR = ar -ARFLAGS = rv -RANLIB = ranlib - -NSS_CDB = libnss_cdb.so.2 -LIBBASE = libcdb -LIB = $(LIBBASE).a -PICLIB = $(LIBBASE)_pic.a -SHAREDLIB = $(LIBBASE).so.1 -SOLIB = $(LIBBASE).so -CDB_USELIB = $(LIB) -NSS_USELIB = $(PICLIB) -LIBMAP = $(LIBBASE).map -INSTALLPROG = cdb - -# The following assumes GNU CC/LD - -# used for building shared libraries only -CFLAGS_PIC = -fPIC -LDFLAGS_SHARED = -shared -LDFLAGS_SONAME = -Wl,--soname= -LDFLAGS_VSCRIPT = -Wl,--version-script= - -CP = cp - -LIB_SRCS = cdb_init.c cdb_find.c cdb_findnext.c cdb_seq.c cdb_seek.c \ - cdb_pack.c cdb_unpack.c \ - cdb_make_add.c cdb_make_put.c cdb_make.c cdb_hash.c -NSS_SRCS = nss_cdb.c nss_cdb-passwd.c nss_cdb-group.c nss_cdb-spwd.c -NSSMAP = nss_cdb.map - -DISTFILES = Makefile cdb.h cdb_int.h $(LIB_SRCS) cdb.c \ - $(NSS_SRCS) nss_cdb.h nss_cdb-Makefile \ - cdb.3 cdb.1 cdb.5 \ - tinycdb.spec tests.sh tests.ok \ - $(LIBMAP) $(NSSMAP) \ - NEWS - -all: static -static: staticlib cdb -staticlib: $(LIB) -nss: $(NSS_CDB) -piclib: $(PICLIB) -sharedlib: $(SHAREDLIB) -shared: sharedlib cdb-shared - -LIB_OBJS = $(LIB_SRCS:.c=.o) -LIB_OBJS_PIC = $(LIB_SRCS:.c=.lo) -NSS_OBJS = $(NSS_SRCS:.c=.lo) - -$(LIB): $(LIB_OBJS) - -rm -f $@ - $(AR) $(ARFLAGS) $@ $(LIB_OBJS) - -$(RANLIB) $@ - -$(PICLIB): $(LIB_OBJS_PIC) - -rm -f $@ - $(AR) $(ARFLAGS) $@ $(LIB_OBJS_PIC) - -$(RANLIB) $@ - -$(SHAREDLIB): $(LIB_OBJS_PIC) $(LIBMAP) - -rm -f $(SOLIB) - ln -s $@ $(SOLIB) - $(LD) $(LDFLAGS) $(LDFLAGS_SHARED) -o $@ \ - $(LDFLAGS_SONAME)$(SHAREDLIB) $(LDFLAGS_VSCRIPT)$(LIBMAP) \ - $(LIB_OBJS_PIC) - -cdb: cdb.o $(CDB_USELIB) - $(LD) $(LDFLAGS) -o $@ cdb.o $(CDB_USELIB) -cdb-shared: cdb.o $(SHAREDLIB) - $(LD) $(LDFLAGS) -o $@ cdb.o $(SHAREDLIB) - -$(NSS_CDB): $(NSS_OBJS) $(NSS_USELIB) $(NSSMAP) - $(LD) $(LDFLAGS) $(LDFLAGS_SHARED) -o $@ \ - $(LDFLAGS_SONAME)$@ $(LDFLAGS_VSCRIPT)$(NSSMAP) \ - $(NSS_OBJS) $(NSS_USELIB) - -.SUFFIXES: -.SUFFIXES: .c .o .lo - -.c.o: - $(CC) $(CFLAGS) $(CDEFS) -c $< -.c.lo: - $(CC) $(CFLAGS) $(CDEFS) $(CFLAGS_PIC) -c -o $@ -DNSSCDB_DIR=\"$(NSSCDB_DIR)\" $< - -cdb.o: cdb.h -$(LIB_OBJS) $(LIB_OBJS_PIC): cdb_int.h cdb.h -$(NSS_OBJS): nss_cdb.h cdb.h - -clean: - -rm -f *.o *.lo core *~ tests.out tests-shared.ok -realclean distclean: clean - -rm -f $(LIBBASE)[._][aps]* $(NSS_CDB)* cdb cdb-shared - -test tests check: cdb - sh ./tests.sh ./cdb > tests.out 2>&1 - diff tests.ok tests.out - @echo All tests passed -test-shared tests-shared check-shared: cdb-shared - sed 's/^cdb: /cdb-shared: /' tests-shared.ok - LD_LIBRARY_PATH=. sh ./tests.sh ./cdb-shared > tests.out 2>&1 - diff tests-shared.ok tests.out - rm -f tests-shared.ok - @echo All tests passed - -do_install = \ - while [ "$$1" ] ; do \ - if [ .$$4 = .- ]; then f=$$1; else f=$$4; fi; \ - d=$(DESTDIR)$$3 ; echo installing $$1 to $$d/$$f; \ - [ -d $$d ] || mkdir -p $$d || exit 1 ; \ - $(CP) $$1 $$d/$$f || exit 1; \ - chmod 0$$2 $$d/$$f || exit 1; \ - shift 4; \ - done - -install-all: all $(INSTALLPROG) - set -- \ - cdb.h 644 $(includedir) - \ - cdb.3 644 $(mandir)/man3 - \ - cdb.1 644 $(mandir)/man1 - \ - cdb.5 644 $(mandir)/man5 - \ - $(INSTALLPROG) 755 $(bindir) cdb \ - libcdb.a 644 $(libdir) - \ - ; \ - $(do_install) -install-nss: nss - @set -- $(NSS_CDB) 644 $(syslibdir) - \ - nss_cdb-Makefile 644 $(sysconfdir) cdb-Makefile ; \ - $(do_install) -install-sharedlib: sharedlib - @set -- $(SHAREDLIB) 644 $(libdir) - ; \ - $(do_install) ; \ - ln -sf $(SHAREDLIB) $(DESTDIR)$(libdir)/$(LIBBASE).so -install-piclib: piclib - @set -- $(PICLIB) 644 $(libdir) - ; \ - $(do_install) -install: install-all - -DNAME = tinycdb-$(VERSION) -dist: ../$(DNAME).tar.gz -../$(DNAME).tar.gz: $(DISTFILES) - mkdir $(DNAME) - ln $(DISTFILES) $(DNAME)/ - rm -f $@ - tar cfz $@ $(DNAME) - rm -fr $(DNAME) - -.PHONY: all clean realclean dist spec -.PHONY: test tests check test-shared tests-shared check-shared -.PHONY: static staticlib shared sharedlib nss piclib -.PHONY: install install-all install-sharedlib install-piclib install-nss diff --git a/source/engine/thirdparty/tinycdb/NEWS b/source/engine/thirdparty/tinycdb/NEWS deleted file mode 100644 index 0be9f60..0000000 --- a/source/engine/thirdparty/tinycdb/NEWS +++ /dev/null @@ -1,117 +0,0 @@ -User-visible news. Latest at the top. - -tinycdb-0.80 2023-09-17 - - - bugfix: cdb utility: check return value from close() too, - when creating the cdb file - - - portability: cdb utility: ignore SIGXFSZ signal if defined, - to be able to clean up when exceeding file limit - - - robustness: let cdb_make_start to lseek() to the zero position - of file. This ensures the file is seekable right at the start - instead of at the very end, too - - - robustness: cdb utility: remove temporary file in case create - operation fails - - - portability use SEE_SET macro instead of 0 for lseek() - - - split out cdb_pack() into its own .c file - -tinycdb-0.79 2023-09-17 - - - bugfix: call fsync() at the end of cdb_make_finish() - to ensure data does not stay in some kernel buffer - - - bugfix: clean tests.out in `make distclean' too - - - `make dist' makes tarball in the parent dir - - - stop shipping debian/* - it is not a native debian package - -tinycdb-0.78 2012-05-11 - - - bugfix release: - o fixed >2Gb file size prob on 32bit platform - o fixed handling of files >=4Gb - o fixed a few compiler warnings - - - introduce $(LD) and $(LDFLAGS), and also $(CDEFS) in Makefile - -tinycdb-0.77 - - - bugfix release: manpage typos, portability fixes and the like - - - bugfix: improper logic in EINTR handling in _cdb_make_full_write - routine which may lead to corruped .cdb file. - -tinycdb-0.76 - - - new cdb utility option: -p permissions, to specify permission - bits for the newly created database file. - - - cdb utility, when creating the database, does unlink() of the - (temp) db file and when opens it with O_CREAT|O_EXCL, instead - of previous O_CREAT|O_TRUNC w/o unlink() behaviour, and uses - O_NOFOLLOW flag if available. This avoids any possible symlink - race conditions, but is somewhat incompatible with previous - versions, where it was possible to create temp file beforehand - with proper permissions. Together with new -p option (above), - this isn't that big change. - - - cdb utility now allows to omit temp file usage (with final rename()) - when creating the database, by specifying -t- (`-' as temp file name) - (or -t the_same_name_as_the_db_file). Useful if the utility is called - from a script which does its own rename afterwards. - - - alot of minor code changes to make modern compilers happy (mostly - signed char vs unsigned char "fixes"). Including additions of - `unsigned' into common structure definitions in cdb.h - the API - stays compatible still. - - - several (spelling and other) fixes for manpages. - - - tinycdb is, once again, maintained as a native Debian package. - Debian package has been split into 4 parts: libcdb1, libcdb-dev, - tinycdb (the utility) and libnss_cdb. RPM .spec file now builds - two packages as well: tinycdb (includes shared library, the utility, - and nss_cdb module) and tinycdb-devel (development files). - -tinycdb-0.75 (2005-04-11) - - - make cdb_make_put(CDB_PUT_REPLACE) to actually *remove* - all (was only first previously) matching records, by - rewriting the file. - - - new mode CDB_PUT_REPLACE0, which zeroes out old duplicate - records - - - fixed fputs() == NULL condition in cdb.c, finally - (should be < 0, not == NULL) - -tinycdb-0.74 (2003-11-04) - - - reworked cdb utility, see manpage for details. cdb -q now - prints all matching records by default (incompat change), - use cdb -q -n XX to return only XXth record if any. - -m works with -q. - - - there are several new routines (and macros) in library. - - cdb_seqinit() and cdb_seqstart() to fetch all records - - cdb_get() to get a pointer to data in internal buffer - - cdb_{get,read}{data,key}() - - - cdbi_t gone (but still defined). Use unsigned instead. - - - cdb_findnext() changed - - - fixed a bug in cdb_seek() (EIO instead of getting valid record) - - - added nss_cdb (for passwd, group and shadow databases only) - - - Makefile targets to build PIC code (libcdb_pic.a, required for - nss_cdb) and shared library (probably not a good idea) - - - Modifications to allow tinycdb to compile under win32, - by Victor Porton (porton at ex-code.com). diff --git a/source/engine/thirdparty/tinycdb/cdb.h b/source/engine/thirdparty/tinycdb/cdb.h deleted file mode 100644 index 103bc5c..0000000 --- a/source/engine/thirdparty/tinycdb/cdb.h +++ /dev/null @@ -1,144 +0,0 @@ -/* cdb.h: public cdb include file - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#ifndef TINYCDB_VERSION -#define TINYCDB_VERSION 0.80 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned int cdbi_t; /* compatibility */ - -/* common routines */ -unsigned cdb_hash(const void *buf, unsigned len); -unsigned cdb_unpack(const unsigned char buf[4]); -void cdb_pack(unsigned num, unsigned char buf[4]); - -struct cdb { - int cdb_fd; /* file descriptor */ - /* private members */ - unsigned cdb_fsize; /* datafile size */ - unsigned cdb_dend; /* end of data ptr */ - const unsigned char *cdb_mem; /* mmap'ed file memory */ - unsigned cdb_vpos, cdb_vlen; /* found data */ - unsigned cdb_kpos, cdb_klen; /* found key */ -}; - -#define CDB_STATIC_INIT {0,0,0,0,0,0,0,0} - -#define cdb_datapos(c) ((c)->cdb_vpos) -#define cdb_datalen(c) ((c)->cdb_vlen) -#define cdb_keypos(c) ((c)->cdb_kpos) -#define cdb_keylen(c) ((c)->cdb_klen) -#define cdb_fileno(c) ((c)->cdb_fd) - -int cdb_init(struct cdb *cdbp, int fd); -int cdb_initf(struct cdb *cdbp, void *p, unsigned len); -void cdb_free(struct cdb *cdbp); - -int cdb_read(const struct cdb *cdbp, - void *buf, unsigned len, unsigned pos); -#define cdb_readdata(cdbp, buf) \ - cdb_read((cdbp), (buf), cdb_datalen(cdbp), cdb_datapos(cdbp)) -#define cdb_readkey(cdbp, buf) \ - cdb_read((cdbp), (buf), cdb_keylen(cdbp), cdb_keypos(cdbp)) - -const void *cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos); -#define cdb_getdata(cdbp) \ - cdb_get((cdbp), cdb_datalen(cdbp), cdb_datapos(cdbp)) -#define cdb_getkey(cdbp) \ - cdb_get((cdbp), cdb_keylen(cdbp), cdb_keypos(cdbp)) - -int cdb_find(struct cdb *cdbp, const void *key, unsigned klen); - -struct cdb_find { - struct cdb *cdb_cdbp; - unsigned cdb_hval; - const unsigned char *cdb_htp, *cdb_htab, *cdb_htend; - unsigned cdb_httodo; - const void *cdb_key; - unsigned cdb_klen; -}; - -int cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp, - const void *key, unsigned klen); -int cdb_findnext(struct cdb_find *cdbfp); - -#define cdb_seqinit(cptr, cdbp) ((*(cptr))=2048) -int cdb_seqnext(unsigned *cptr, struct cdb *cdbp); - -/* old simple interface */ -/* open file using standard routine, then: */ -int cdb_seek(int fd, const void *key, unsigned klen, unsigned *dlenp); -int cdb_bread(int fd, void *buf, int len); - -/* cdb_make */ - -struct cdb_make { - int cdb_fd; /* file descriptor */ - /* private */ - unsigned cdb_dpos; /* data position so far */ - unsigned cdb_rcnt; /* record count so far */ - unsigned char cdb_buf[4096]; /* write buffer */ - unsigned char *cdb_bpos; /* current buf position */ - struct cdb_rl *cdb_rec[256]; /* list of arrays of record infos */ -}; - -enum cdb_put_mode { - CDB_PUT_ADD = 0, /* add unconditionnaly, like cdb_make_add() */ -#define CDB_PUT_ADD CDB_PUT_ADD - CDB_FIND = CDB_PUT_ADD, - CDB_PUT_REPLACE, /* replace: do not place to index OLD record */ -#define CDB_PUT_REPLACE CDB_PUT_REPLACE - CDB_FIND_REMOVE = CDB_PUT_REPLACE, - CDB_PUT_INSERT, /* add only if not already exists */ -#define CDB_PUT_INSERT CDB_PUT_INSERT - CDB_PUT_WARN, /* add unconditionally but ret. 1 if exists */ -#define CDB_PUT_WARN CDB_PUT_WARN - CDB_PUT_REPLACE0, /* if a record exists, fill old one with zeros */ -#define CDB_PUT_REPLACE0 CDB_PUT_REPLACE0 - CDB_FIND_FILL0 = CDB_PUT_REPLACE0 -}; - -int cdb_make_start(struct cdb_make *cdbmp, int fd); -int cdb_make_add(struct cdb_make *cdbmp, - const void *key, unsigned klen, - const void *val, unsigned vlen); -int cdb_make_exists(struct cdb_make *cdbmp, - const void *key, unsigned klen); -int cdb_make_find(struct cdb_make *cdbmp, - const void *key, unsigned klen, - enum cdb_put_mode mode); -int cdb_make_put(struct cdb_make *cdbmp, - const void *key, unsigned klen, - const void *val, unsigned vlen, - enum cdb_put_mode mode); -int cdb_make_finish(struct cdb_make *cdbmp); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* include guard */ diff --git a/source/engine/thirdparty/tinycdb/cdb_find.c b/source/engine/thirdparty/tinycdb/cdb_find.c deleted file mode 100644 index 531f77c..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_find.c +++ /dev/null @@ -1,93 +0,0 @@ -/* cdb_find.c: cdb_find routine - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include "cdb_int.h" - -int -cdb_find(struct cdb *cdbp, const void *key, unsigned klen) -{ - const unsigned char *htp; /* hash table pointer */ - const unsigned char *htab; /* hash table */ - const unsigned char *htend; /* end of hash table */ - unsigned httodo; /* ht bytes left to look */ - unsigned pos, n; - - unsigned hval; - - if (klen >= cdbp->cdb_dend) /* if key size is too large */ - return 0; - - hval = cdb_hash(key, klen); - - /* find (pos,n) hash table to use */ - /* first 2048 bytes (toc) are always available */ - /* (hval % 256) * 8 */ - htp = cdbp->cdb_mem + ((hval << 3) & 2047); /* index in toc (256x8) */ - n = cdb_unpack(htp + 4); /* table size */ - if (!n) /* empty table */ - return 0; /* not found */ - httodo = n << 3; /* bytes of htab to lookup */ - pos = cdb_unpack(htp); /* htab position */ - if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */ - || pos < cdbp->cdb_dend /* is htab inside data section ? */ - || pos > cdbp->cdb_fsize /* htab start within file ? */ - || httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */ - return errno = EPROTO, -1; - - htab = cdbp->cdb_mem + pos; /* htab pointer */ - htend = htab + httodo; /* after end of htab */ - /* htab starting position: rest of hval modulo htsize, 8bytes per elt */ - htp = htab + (((hval >> 8) % n) << 3); - - for(;;) { - pos = cdb_unpack(htp + 4); /* record position */ - if (!pos) - return 0; - if (cdb_unpack(htp) == hval) { - if (pos > cdbp->cdb_dend - 8) /* key+val lengths */ - return errno = EPROTO, -1; - if (cdb_unpack(cdbp->cdb_mem + pos) == klen) { - if (cdbp->cdb_dend - klen < pos + 8) - return errno = EPROTO, -1; - if (memcmp(key, cdbp->cdb_mem + pos + 8, klen) == 0) { - n = cdb_unpack(cdbp->cdb_mem + pos + 4); - pos += 8; - if (cdbp->cdb_dend < n || cdbp->cdb_dend - n < pos + klen) - return errno = EPROTO, -1; - cdbp->cdb_kpos = pos; - cdbp->cdb_klen = klen; - cdbp->cdb_vpos = pos + klen; - cdbp->cdb_vlen = n; - return 1; - } - } - } - httodo -= 8; - if (!httodo) - return 0; - if ((htp += 8) >= htend) - htp = htab; - } - -} diff --git a/source/engine/thirdparty/tinycdb/cdb_findnext.c b/source/engine/thirdparty/tinycdb/cdb_findnext.c deleted file mode 100644 index 33234c7..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_findnext.c +++ /dev/null @@ -1,98 +0,0 @@ -/* cdb_findnext.c: sequential cdb_find routines - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -/* see cdb_find.c for comments */ - -#include "cdb_int.h" - -int -cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp, - const void *key, unsigned klen) -{ - unsigned n, pos; - - cdbfp->cdb_cdbp = cdbp; - cdbfp->cdb_key = key; - cdbfp->cdb_klen = klen; - cdbfp->cdb_hval = cdb_hash(key, klen); - - cdbfp->cdb_htp = cdbp->cdb_mem + ((cdbfp->cdb_hval << 3) & 2047); - n = cdb_unpack(cdbfp->cdb_htp + 4); - cdbfp->cdb_httodo = n << 3; - if (!n) - return 0; - pos = cdb_unpack(cdbfp->cdb_htp); - if (n > (cdbp->cdb_fsize >> 3) - || pos < cdbp->cdb_dend - || pos > cdbp->cdb_fsize - || cdbfp->cdb_httodo > cdbp->cdb_fsize - pos) - return errno = EPROTO, -1; - - cdbfp->cdb_htab = cdbp->cdb_mem + pos; - cdbfp->cdb_htend = cdbfp->cdb_htab + cdbfp->cdb_httodo; - cdbfp->cdb_htp = cdbfp->cdb_htab + (((cdbfp->cdb_hval >> 8) % n) << 3); - - return 1; -} - -int -cdb_findnext(struct cdb_find *cdbfp) { - struct cdb *cdbp = cdbfp->cdb_cdbp; - unsigned pos, n; - unsigned klen = cdbfp->cdb_klen; - - while(cdbfp->cdb_httodo) { - pos = cdb_unpack(cdbfp->cdb_htp + 4); - if (!pos) - return 0; - n = cdb_unpack(cdbfp->cdb_htp) == cdbfp->cdb_hval; - if ((cdbfp->cdb_htp += 8) >= cdbfp->cdb_htend) - cdbfp->cdb_htp = cdbfp->cdb_htab; - cdbfp->cdb_httodo -= 8; - if (n) { - if (pos > cdbp->cdb_fsize - 8) - return errno = EPROTO, -1; - if (cdb_unpack(cdbp->cdb_mem + pos) == klen) { - if (cdbp->cdb_fsize - klen < pos + 8) - return errno = EPROTO, -1; - if (memcmp(cdbfp->cdb_key, - cdbp->cdb_mem + pos + 8, klen) == 0) { - n = cdb_unpack(cdbp->cdb_mem + pos + 4); - pos += 8; - if (cdbp->cdb_fsize < n || - cdbp->cdb_fsize - n < pos + klen) - return errno = EPROTO, -1; - cdbp->cdb_kpos = pos; - cdbp->cdb_klen = klen; - cdbp->cdb_vpos = pos + klen; - cdbp->cdb_vlen = n; - return 1; - } - } - } - } - - return 0; - -} diff --git a/source/engine/thirdparty/tinycdb/cdb_hash.c b/source/engine/thirdparty/tinycdb/cdb_hash.c deleted file mode 100644 index c044f89..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_hash.c +++ /dev/null @@ -1,36 +0,0 @@ -/* cdb_hash.c: cdb hashing routine - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include "cdb.h" - -unsigned -cdb_hash(const void *buf, unsigned len) -{ - register const unsigned char *p = (const unsigned char *)buf; - register const unsigned char *end = p + len; - register unsigned hash = 5381; /* start value */ - while (p < end) - hash = (hash + (hash << 5)) ^ *p++; - return hash; -} diff --git a/source/engine/thirdparty/tinycdb/cdb_init.c b/source/engine/thirdparty/tinycdb/cdb_init.c deleted file mode 100644 index f524598..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_init.c +++ /dev/null @@ -1,151 +0,0 @@ -/* cdb_init.c: cdb_init, cdb_free and cdb_read routines - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include -#ifdef _WIN32 -# include -#else -# include -# ifndef MAP_FAILED -# define MAP_FAILED ((void*)-1) -# endif -#endif -#include -#include "cdb_int.h" - -int cdb_initf(struct cdb *cdbp, void *p, unsigned len) -{ - /* get file size */ - if (len < 0) - return -1; - - cdbp->cdb_fd = -1; - cdbp->cdb_fsize = len; - cdbp->cdb_mem = p; - cdbp->cdb_vpos = cdbp->cdb_vlen = 0; - cdbp->cdb_kpos = cdbp->cdb_klen = 0; - unsigned dend; - unsigned fsize = len; - dend = cdb_unpack(p); - if (dend < 2048) dend = 2048; - else if (dend >= fsize) dend = fsize; - cdbp->cdb_dend = dend; - - return 0; -} - -int -cdb_init(struct cdb *cdbp, int fd) -{ - struct stat st; - unsigned char *mem; - unsigned fsize, dend; -#ifdef _WIN32 - HANDLE hFile, hMapping; -#endif - - /* get file size */ - if (fstat(fd, &st) < 0) - return -1; - /* trivial sanity check: at least toc should be here */ - if (st.st_size < 2048) - return errno = EPROTO, -1; - fsize = st.st_size < 0xffffffffu ? st.st_size : 0xffffffffu; - /* memory-map file */ -#ifdef _WIN32 - hFile = (HANDLE) _get_osfhandle(fd); - if (hFile == (HANDLE) -1) - return -1; - hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (!hMapping) - return -1; - mem = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); - CloseHandle(hMapping); - if (!mem) - return -1; -#else - mem = (unsigned char*)mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0); - if (mem == MAP_FAILED) - return -1; -#endif /* _WIN32 */ - - cdbp->cdb_fd = fd; - cdbp->cdb_fsize = fsize; - cdbp->cdb_mem = mem; - -#if 0 - /* XXX don't know well about madvise syscall -- is it legal - to set different options for parts of one mmap() region? - There is also posix_madvise() exist, with POSIX_MADV_RANDOM etc... - */ -#ifdef MADV_RANDOM - /* set madvise() parameters. Ignore errors for now if system - doesn't support it */ - madvise(mem, 2048, MADV_WILLNEED); - madvise(mem + 2048, cdbp->cdb_fsize - 2048, MADV_RANDOM); -#endif -#endif - - cdbp->cdb_vpos = cdbp->cdb_vlen = 0; - cdbp->cdb_kpos = cdbp->cdb_klen = 0; - dend = cdb_unpack(mem); - if (dend < 2048) dend = 2048; - else if (dend >= fsize) dend = fsize; - cdbp->cdb_dend = dend; - - return 0; -} - -void -cdb_free(struct cdb *cdbp) -{ - if (cdbp->cdb_mem) { -#ifdef _WIN32 - UnmapViewOfFile((void*) cdbp->cdb_mem); -#else - munmap((void*)cdbp->cdb_mem, cdbp->cdb_fsize); -#endif /* _WIN32 */ - cdbp->cdb_mem = NULL; - } - cdbp->cdb_fsize = 0; -} - -const void * -cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos) -{ - if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) { - errno = EPROTO; - return NULL; - } - return cdbp->cdb_mem + pos; -} - -int -cdb_read(const struct cdb *cdbp, void *buf, unsigned len, unsigned pos) -{ - const void *data = cdb_get(cdbp, len, pos); - if (!data) return -1; - memcpy(buf, data, len); - return 0; -} diff --git a/source/engine/thirdparty/tinycdb/cdb_int.h b/source/engine/thirdparty/tinycdb/cdb_int.h deleted file mode 100644 index 35ff02a..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_int.h +++ /dev/null @@ -1,58 +0,0 @@ -/* cdb_int.h: internal cdb library declarations - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include "cdb.h" -#include -#include - -#ifndef EPROTO -# define EPROTO EINVAL -#endif - -#ifndef internal_function -# ifdef __GNUC__ -# define internal_function __attribute__((visibility("hidden"))) -# else -# define internal_function -# endif -#endif - -struct cdb_rec { - unsigned hval; - unsigned rpos; -}; - -struct cdb_rl { - struct cdb_rl *next; - unsigned cnt; - struct cdb_rec rec[254]; -}; - -int _cdb_make_write(struct cdb_make *cdbmp, - const unsigned char *ptr, unsigned len); -int _cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len); -int _cdb_make_flush(struct cdb_make *cdbmp); -int _cdb_make_add(struct cdb_make *cdbmp, unsigned hval, - const void *key, unsigned klen, - const void *val, unsigned vlen); diff --git a/source/engine/thirdparty/tinycdb/cdb_make.c b/source/engine/thirdparty/tinycdb/cdb_make.c deleted file mode 100644 index eb68fdf..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_make.c +++ /dev/null @@ -1,196 +0,0 @@ -/* cdb_make.c: basic cdb creation routines - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include -#include -#include -#include "cdb_int.h" - -int -cdb_make_start(struct cdb_make *cdbmp, int fd) -{ - memset(cdbmp, 0, sizeof(*cdbmp)); - cdbmp->cdb_fd = fd; - cdbmp->cdb_dpos = 2048; - cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048; - return lseek(fd, 0, SEEK_SET); -} - -int internal_function -_cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len) -{ - while(len) { - int l = write(fd, buf, len); - if (l > 0) { - len -= l; - buf += l; - } - else if (l < 0 && errno != EINTR) - return -1; - } - return 0; -} - -int internal_function -_cdb_make_flush(struct cdb_make *cdbmp) { - unsigned len = cdbmp->cdb_bpos - cdbmp->cdb_buf; - if (len) { - if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, len) < 0) - return -1; - cdbmp->cdb_bpos = cdbmp->cdb_buf; - } - return 0; -} - -int internal_function -_cdb_make_write(struct cdb_make *cdbmp, const unsigned char *ptr, unsigned len) -{ - unsigned l = sizeof(cdbmp->cdb_buf) - (cdbmp->cdb_bpos - cdbmp->cdb_buf); - cdbmp->cdb_dpos += len; - if (len > l) { - memcpy(cdbmp->cdb_bpos, ptr, l); - cdbmp->cdb_bpos += l; - if (_cdb_make_flush(cdbmp) < 0) - return -1; - ptr += l; len -= l; - l = len / sizeof(cdbmp->cdb_buf); - if (l) { - l *= sizeof(cdbmp->cdb_buf); - if (_cdb_make_fullwrite(cdbmp->cdb_fd, ptr, l) < 0) - return -1; - ptr += l; len -= l; - } - } - if (len) { - memcpy(cdbmp->cdb_bpos, ptr, len); - cdbmp->cdb_bpos += len; - } - return 0; -} - -static int -cdb_make_finish_internal(struct cdb_make *cdbmp) -{ - unsigned hcnt[256]; /* hash table counts */ - unsigned hpos[256]; /* hash table positions */ - struct cdb_rec *htab; - unsigned char *p; - struct cdb_rl *rl; - unsigned hsize; - unsigned t, i; - - if (((0xffffffff - cdbmp->cdb_dpos) >> 3) < cdbmp->cdb_rcnt) - return errno = ENOMEM, -1; - - /* count htab sizes and reorder reclists */ - hsize = 0; - for (t = 0; t < 256; ++t) { - struct cdb_rl *rlt = NULL; - i = 0; - rl = cdbmp->cdb_rec[t]; - while(rl) { - struct cdb_rl *rln = rl->next; - rl->next = rlt; - rlt = rl; - i += rl->cnt; - rl = rln; - } - cdbmp->cdb_rec[t] = rlt; - if (hsize < (hcnt[t] = i << 1)) - hsize = hcnt[t]; - } - - /* allocate memory to hold max htable */ - htab = (struct cdb_rec*)malloc((hsize + 2) * sizeof(struct cdb_rec)); - if (!htab) - return errno = ENOENT, -1; - p = (unsigned char *)htab; - htab += 2; - - /* build hash tables */ - for (t = 0; t < 256; ++t) { - unsigned len, hi; - hpos[t] = cdbmp->cdb_dpos; - if ((len = hcnt[t]) == 0) - continue; - for (i = 0; i < len; ++i) - htab[i].hval = htab[i].rpos = 0; - for (rl = cdbmp->cdb_rec[t]; rl; rl = rl->next) - for (i = 0; i < rl->cnt; ++i) { - hi = (rl->rec[i].hval >> 8) % len; - while(htab[hi].rpos) - if (++hi == len) - hi = 0; - htab[hi] = rl->rec[i]; - } - for (i = 0; i < len; ++i) { - cdb_pack(htab[i].hval, p + (i << 3)); - cdb_pack(htab[i].rpos, p + (i << 3) + 4); - } - if (_cdb_make_write(cdbmp, p, len << 3) < 0) { - free(p); - return -1; - } - } - free(p); - if (_cdb_make_flush(cdbmp) < 0) - return -1; - p = cdbmp->cdb_buf; - for (t = 0; t < 256; ++t) { - cdb_pack(hpos[t], p + (t << 3)); - cdb_pack(hcnt[t], p + (t << 3) + 4); - } - if (lseek(cdbmp->cdb_fd, 0, SEEK_SET) != 0 || - _cdb_make_fullwrite(cdbmp->cdb_fd, p, 2048) != 0) - return -1; - -#ifdef _WIN32 - return _commit(fileno(cdbmp->cdb_fd)); -#else - return fsync(cdbmp->cdb_fd); -#endif -} - -static void -cdb_make_free(struct cdb_make *cdbmp) -{ - unsigned t; - for(t = 0; t < 256; ++t) { - struct cdb_rl *rl = cdbmp->cdb_rec[t]; - while(rl) { - struct cdb_rl *tm = rl; - rl = rl->next; - free(tm); - } - } -} - -int -cdb_make_finish(struct cdb_make *cdbmp) -{ - int r = cdb_make_finish_internal(cdbmp); - cdb_make_free(cdbmp); - return r; -} - diff --git a/source/engine/thirdparty/tinycdb/cdb_make_add.c b/source/engine/thirdparty/tinycdb/cdb_make_add.c deleted file mode 100644 index 9b32f6b..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_make_add.c +++ /dev/null @@ -1,67 +0,0 @@ -/* cdb_make_add.c: basic cdb_make_add routine - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include /* for malloc */ -#include "cdb_int.h" - -int internal_function -_cdb_make_add(struct cdb_make *cdbmp, unsigned hval, - const void *key, unsigned klen, - const void *val, unsigned vlen) -{ - unsigned char rlen[8]; - struct cdb_rl *rl; - unsigned i; - if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) || - vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8)) - return errno = ENOMEM, -1; - i = hval & 255; - rl = cdbmp->cdb_rec[i]; - if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) { - rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl)); - if (!rl) - return errno = ENOMEM, -1; - rl->cnt = 0; - rl->next = cdbmp->cdb_rec[i]; - cdbmp->cdb_rec[i] = rl; - } - i = rl->cnt++; - rl->rec[i].hval = hval; - rl->rec[i].rpos = cdbmp->cdb_dpos; - ++cdbmp->cdb_rcnt; - cdb_pack(klen, rlen); - cdb_pack(vlen, rlen + 4); - if (_cdb_make_write(cdbmp, rlen, 8) < 0 || - _cdb_make_write(cdbmp, key, klen) < 0 || - _cdb_make_write(cdbmp, val, vlen) < 0) - return -1; - return 0; -} - -int -cdb_make_add(struct cdb_make *cdbmp, - const void *key, unsigned klen, - const void *val, unsigned vlen) { - return _cdb_make_add(cdbmp, cdb_hash(key, klen), key, klen, val, vlen); -} diff --git a/source/engine/thirdparty/tinycdb/cdb_make_put.c b/source/engine/thirdparty/tinycdb/cdb_make_put.c deleted file mode 100644 index 1458360..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_make_put.c +++ /dev/null @@ -1,221 +0,0 @@ -/* cdb_make_put.c: "advanced" cdb_make_put routine - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include -#include -#include -#include "cdb_int.h" - -static void -fixup_rpos(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) { - unsigned i; - struct cdb_rl *rl; - register struct cdb_rec *rp, *rs; - for (i = 0; i < 256; ++i) { - for (rl = cdbmp->cdb_rec[i]; rl; rl = rl->next) - for (rs = rl->rec, rp = rs + rl->cnt; --rp >= rs;) - if (rp->rpos <= rpos) goto nexthash; - else rp->rpos -= rlen; -nexthash:; - } -} - -static int -remove_record(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) { - unsigned pos, len; - int r, fd; - - len = cdbmp->cdb_dpos - rpos - rlen; - cdbmp->cdb_dpos -= rlen; - if (!len) - return 0; /* it was the last record, nothing to do */ - pos = rpos; - fd = cdbmp->cdb_fd; - do { - r = len > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : len; - if (lseek(fd, pos + rlen, SEEK_SET) < 0 || - (r = read(fd, cdbmp->cdb_buf, r)) <= 0) - return -1; - if (lseek(fd, pos, SEEK_SET) < 0 || - _cdb_make_fullwrite(fd, cdbmp->cdb_buf, r) < 0) - return -1; - pos += r; - len -= r; - } while(len); - assert(cdbmp->cdb_dpos == pos); - fixup_rpos(cdbmp, rpos, rlen); - return 0; -} - -static int -zerofill_record(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) { - if (rpos + rlen == cdbmp->cdb_dpos) { - cdbmp->cdb_dpos = rpos; - return 0; - } - if (lseek(cdbmp->cdb_fd, rpos, SEEK_SET) < 0) - return -1; - memset(cdbmp->cdb_buf, 0, sizeof(cdbmp->cdb_buf)); - cdb_pack(rlen - 8, cdbmp->cdb_buf + 4); - for(;;) { - rpos = rlen > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : rlen; - if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, rpos) < 0) - return -1; - rlen -= rpos; - if (!rlen) return 0; - memset(cdbmp->cdb_buf + 4, 0, 4); - } -} - -/* return: 0 = not found, 1 = error, or record length */ -static unsigned -match(struct cdb_make *cdbmp, unsigned pos, const char *key, unsigned klen) -{ - int len; - unsigned rlen; - if (lseek(cdbmp->cdb_fd, pos, SEEK_SET) < 0) - return 1; - if (read(cdbmp->cdb_fd, cdbmp->cdb_buf, 8) != 8) - return 1; - if (cdb_unpack(cdbmp->cdb_buf) != klen) - return 0; - - /* record length; check its validity */ - rlen = cdb_unpack(cdbmp->cdb_buf + 4); - if (rlen > cdbmp->cdb_dpos - pos - klen - 8) - return errno = EPROTO, 1; /* someone changed our file? */ - rlen += klen + 8; - - while(klen) { - len = klen > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : klen; - len = read(cdbmp->cdb_fd, cdbmp->cdb_buf, len); - if (len <= 0) - return 1; - if (memcmp(cdbmp->cdb_buf, key, len) != 0) - return 0; - key += len; - klen -= len; - } - - return rlen; -} - -static int -findrec(struct cdb_make *cdbmp, - const void *key, unsigned klen, unsigned hval, - enum cdb_put_mode mode) -{ - struct cdb_rl *rl; - struct cdb_rec *rp, *rs; - unsigned r; - int seeked = 0; - int ret = 0; - for(rl = cdbmp->cdb_rec[hval&255]; rl; rl = rl->next) - for(rs = rl->rec, rp = rs + rl->cnt; --rp >= rs;) { - if (rp->hval != hval) - continue; - /*XXX this explicit flush may be unnecessary having - * smarter match() that looks into cdb_buf too, but - * most of a time here spent in finding hash values - * (above), not keys */ - if (!seeked && _cdb_make_flush(cdbmp) < 0) - return -1; - seeked = 1; - r = match(cdbmp, rp->rpos, key, klen); - if (!r) - continue; - if (r == 1) - return -1; - ret = 1; - switch(mode) { - case CDB_FIND_REMOVE: - if (remove_record(cdbmp, rp->rpos, r) < 0) - return -1; - break; - case CDB_FIND_FILL0: - if (zerofill_record(cdbmp, rp->rpos, r) < 0) - return -1; - break; - default: goto finish; - } - memmove(rp, rp + 1, (rs + rl->cnt - 1 - rp) * sizeof(*rp)); - --rl->cnt; - --cdbmp->cdb_rcnt; - } -finish: - if (seeked && lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0) - return -1; - return ret; -} - -int -cdb_make_find(struct cdb_make *cdbmp, - const void *key, unsigned klen, - enum cdb_put_mode mode) -{ - return findrec(cdbmp, key, klen, cdb_hash(key, klen), mode); -} - -int -cdb_make_exists(struct cdb_make *cdbmp, - const void *key, unsigned klen) -{ - return cdb_make_find(cdbmp, key, klen, CDB_FIND); -} - -int -cdb_make_put(struct cdb_make *cdbmp, - const void *key, unsigned klen, - const void *val, unsigned vlen, - enum cdb_put_mode mode) -{ - unsigned hval = cdb_hash(key, klen); - int r; - - switch(mode) { - case CDB_PUT_REPLACE: - case CDB_PUT_INSERT: - case CDB_PUT_WARN: - case CDB_PUT_REPLACE0: - r = findrec(cdbmp, key, klen, hval, mode); - if (r < 0) - return -1; - if (r && mode == CDB_PUT_INSERT) - return errno = EEXIST, 1; - break; - - case CDB_PUT_ADD: - r = 0; - break; - - default: - return errno = EINVAL, -1; - } - - if (_cdb_make_add(cdbmp, hval, key, klen, val, vlen) < 0) - return -1; - - return r; -} - diff --git a/source/engine/thirdparty/tinycdb/cdb_pack.c b/source/engine/thirdparty/tinycdb/cdb_pack.c deleted file mode 100644 index 212089d..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_pack.c +++ /dev/null @@ -1,34 +0,0 @@ -/* cdb_pack.c: pack a 32bit integer (to network byte order) - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include "cdb.h" - -void -cdb_pack(unsigned num, unsigned char buf[4]) -{ - buf[0] = num & 255; num >>= 8; - buf[1] = num & 255; num >>= 8; - buf[2] = num & 255; - buf[3] = num >> 8; -} diff --git a/source/engine/thirdparty/tinycdb/cdb_seek.c b/source/engine/thirdparty/tinycdb/cdb_seek.c deleted file mode 100644 index f5169b8..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_seek.c +++ /dev/null @@ -1,117 +0,0 @@ -/* cdb_seek.c: old interface for reading cdb file - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include -#include "cdb_int.h" - -#ifndef SEEK_SET -# define SEEK_SET 0 -#endif - -/* read a chunk from file, ignoring interrupts (EINTR) */ - -int -cdb_bread(int fd, void *buf, int len) -{ - int l; - while(len > 0) { - do l = read(fd, buf, len); - while(l < 0 && errno == EINTR); - if (l <= 0) { - if (!l) - errno = EIO; - return -1; - } - buf = (char*)buf + l; - len -= l; - } - return 0; -} - -/* find a given key in cdb file, seek a file pointer to it's value and - place data length to *dlenp. */ - -int -cdb_seek(int fd, const void *key, unsigned klen, unsigned *dlenp) -{ - unsigned htstart; /* hash table start position */ - unsigned htsize; /* number of elements in a hash table */ - unsigned httodo; /* hash table elements left to look */ - unsigned hti; /* hash table index */ - unsigned pos; /* position in a file */ - unsigned hval; /* key's hash value */ - unsigned char rbuf[64]; /* read buffer */ - int needseek = 1; /* if we should seek to a hash slot */ - - hval = cdb_hash(key, klen); - pos = (hval & 0xff) << 3; /* position in TOC */ - /* read the hash table parameters */ - if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0) - return -1; - if ((htsize = cdb_unpack(rbuf + 4)) == 0) - return 0; - hti = (hval >> 8) % htsize; /* start position in hash table */ - httodo = htsize; - htstart = cdb_unpack(rbuf); - - for(;;) { - if (needseek && lseek(fd, htstart + (hti << 3), SEEK_SET) < 0) - return -1; - if (cdb_bread(fd, rbuf, 8) < 0) - return -1; - if ((pos = cdb_unpack(rbuf + 4)) == 0) /* not found */ - return 0; - - if (cdb_unpack(rbuf) != hval) /* hash value not matched */ - needseek = 0; - else { /* hash value matched */ - if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0) - return -1; - if (cdb_unpack(rbuf) == klen) { /* key length matches */ - /* read the key from file and compare with wanted */ - unsigned l = klen, c; - const char *k = (const char*)key; - if (dlenp) - *dlenp = cdb_unpack(rbuf + 4); /* save value length */ - for(;;) { - if (!l) /* the whole key read and matches, return */ - return 1; - c = l > sizeof(rbuf) ? sizeof(rbuf) : l; - if (cdb_bread(fd, rbuf, c) < 0) - return -1; - if (memcmp(rbuf, k, c) != 0) /* no, it differs, stop here */ - break; - k += c; l -= c; - } - } - needseek = 1; /* we're looked to other place, should seek back */ - } - if (!--httodo) - return 0; - if (++hti == htsize) { - hti = 0; - needseek = 1; - } - } -} diff --git a/source/engine/thirdparty/tinycdb/cdb_seq.c b/source/engine/thirdparty/tinycdb/cdb_seq.c deleted file mode 100644 index a9df144..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_seq.c +++ /dev/null @@ -1,46 +0,0 @@ -/* cdb_seq.c: sequential record retrieval routines - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include "cdb_int.h" - -int -cdb_seqnext(unsigned *cptr, struct cdb *cdbp) { - unsigned klen, vlen; - unsigned pos = *cptr; - unsigned dend = cdbp->cdb_dend; - const unsigned char *mem = cdbp->cdb_mem; - if (pos > dend - 8) - return 0; - klen = cdb_unpack(mem + pos); - vlen = cdb_unpack(mem + pos + 4); - pos += 8; - if (dend - klen < pos || dend - vlen < pos + klen) - return errno = EPROTO, -1; - cdbp->cdb_kpos = pos; - cdbp->cdb_klen = klen; - cdbp->cdb_vpos = pos + klen; - cdbp->cdb_vlen = vlen; - *cptr = pos + klen + vlen; - return 1; -} diff --git a/source/engine/thirdparty/tinycdb/cdb_unpack.c b/source/engine/thirdparty/tinycdb/cdb_unpack.c deleted file mode 100644 index 9ba86cd..0000000 --- a/source/engine/thirdparty/tinycdb/cdb_unpack.c +++ /dev/null @@ -1,35 +0,0 @@ -/* cdb_unpack.c: unpack a 32bit integer from network byte order - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#include "cdb.h" - -unsigned -cdb_unpack(const unsigned char buf[4]) -{ - unsigned n = buf[3]; - n <<= 8; n |= buf[2]; - n <<= 8; n |= buf[1]; - n <<= 8; n |= buf[0]; - return n; -} diff --git a/source/engine/thirdparty/tinycdb/tests.ok b/source/engine/thirdparty/tinycdb/tests.ok deleted file mode 100644 index acfb689..0000000 --- a/source/engine/thirdparty/tinycdb/tests.ok +++ /dev/null @@ -1,83 +0,0 @@ -Create simple db -0 -checksum may fail if no md5sum program -97549c2e76e2d446430a392d77ed1bcb -Dump simple db -+3,4:one->here -+1,1:a->b -+1,3:b->abc -+3,4:one->also - -0 -Stats for simple db -number of records: 4 -key min/avg/max length: 1/2/3 -val min/avg/max length: 1/3/4 -hash tables/entries/collisions: 3/8/1 -hash table min/avg/max length: 2/3/4 -hash table distances: - d0: 3 75% - d1: 1 25% - d2: 0 0% - d3: 0 0% - d4: 0 0% - d5: 0 0% - d6: 0 0% - d7: 0 0% - d8: 0 0% - d9: 0 0% - >9: 0 0% -0 -Query simple db (two records match) -herealso -0 -Query for non-existed key -100 -Doing 600 repeated records -0 -checksum may fail if no md5sum program -412a0b7578efca528bf8398c8811caf4 -cdb stats should show 601 record -number of records: 601 -key min/avg/max length: 1/1/1 -val min/avg/max length: 3/3/5 -hash tables/entries/collisions: 2/1202/599 -hash table min/avg/max length: 2/601/1200 -hash table distances: - d0: 2 0% - d1: 1 0% - d2: 1 0% - d3: 1 0% - d4: 1 0% - d5: 1 0% - d6: 1 0% - d7: 1 0% - d8: 1 0% - d9: 1 0% - >9: 590 98% -0 -Querying key -other -0 -Dumping and re-creating db -0 -0 -Handling large key size -cdb: (stdin): bad format -2 -Handling large value size -cdb: (stdin): bad format -2 -Handling invalid input format (short file) -cdb: unable to read: short file -2 -Creating db with eol in key and value -0 -checksum may fail if no md5sum program -1d444fe759c26d36f500d01c41cfda40 -Querying key-value with eol -b -0 -Handling file size limits -cdb: cdb_make_put: File too large -111 diff --git a/source/engine/thirdparty/tinycdb/tests.sh b/source/engine/thirdparty/tinycdb/tests.sh deleted file mode 100755 index 03cf941..0000000 --- a/source/engine/thirdparty/tinycdb/tests.sh +++ /dev/null @@ -1,143 +0,0 @@ -#! /bin/sh - -# tests.sh: This script will run tests for cdb. -# Execute with ./tests.sh ./cdb -# (first arg if present gives path to cdb tool to use, default is `cdb'). -# -# This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru. -# Public domain. - -case "$1" in - "") cdb=cdb ;; - *) cdb="$1" ;; -esac - -do_csum() { - echo checksum may fail if no md5sum program - md5sum $1 | sed -e 's|[ ].*||' -e 'y|[ABCDEF]|[abcdef]|' -} - -rm -f 1.cdb 1a.cdb - -echo Create simple db -echo "+3,4:one->here -+1,1:a->b -+1,3:b->abc -+3,4:one->also - -" | $cdb -c 1.cdb -echo $? -do_csum 1.cdb - -echo Dump simple db -$cdb -d 1.cdb -echo $? - -echo Stats for simple db -$cdb -s 1.cdb -echo $? - -echo "Query simple db (two records match)" -$cdb -q 1.cdb one -echo " -$?" - -echo Query for non-existed key -$cdb -q 1.cdb none -echo $? - -echo Doing 600 repeated records -( - for i in 0 1 2 3 4 5 ; do - for j in 0 1 2 3 4 5 6 7 8 9 ; do - for k in 0 1 2 3 4 5 6 7 8 9 ; do - echo "+1,3:a->$i$j$k" - done - done - done - echo "+1,5:b->other" - echo -) | $cdb -c 1.cdb -echo $? -do_csum 1.cdb -echo cdb stats should show 601 record -$cdb -s 1.cdb -echo $? - -echo Querying key -$cdb -q 1.cdb b -echo " -"$? - -echo Dumping and re-creating db -$cdb -d 1.cdb | $cdb -c 1a.cdb -echo $? -cmp 1.cdb 1a.cdb - -$cdb -d -m 1.cdb | $cdb -c -m 1a.cdb -echo $? -cmp 1.cdb 1a.cdb - -echo Handling large key size -echo "+123456789012,1:" | $cdb -c 1.cdb -echo $? - -echo Handling large value size -echo "+1,123456789012:" | $cdb -c 1.cdb -echo $? - -echo "Handling invalid input format (short file)" -echo "+10,10:" | $cdb -c 1.cdb -echo $? - -echo Creating db with eol in key and value -echo "+2,2:a -->b - -" | $cdb -c 1.cdb -echo $? -do_csum 1.cdb - -echo Querying key-value with eol -$cdb -q 1.cdb "a -" -echo $? - -echo Handling file size limits -( - ulimit -f 4 - trap '' 25 - ( - for i in 0 1 2 3 4 5 6 7 8 9 ; do - for j in 0 1 2 3 4 5 6 7 8 9 ; do - for k in 0 1 2 3 4 5 6 7 8 9 ; do - echo "+4,4:k$i$j$k->v$i$j$k" - done - done - done - echo - ) | $cdb -c 1.cdb - echo $? -) - -if false ; then # does not work for now, bugs in libc -echo Handling oom condition -( - for i0 in 0 1 2 3 4 5 6 7 8 9 ; do - for i1 in 0 1 2 3 4 5 6 7 8 9 ; do - for i2 in 0 1 2 3 4 5 6 7 8 9 ; do - for i3 in 0 1 2 3 4 5 6 7 8 9 ; do - for i4 in 0 1 2 3 4 5 6 7 8 9 ; do - echo "+5,0:$i0$i1$i2$i3$i4->" - done - done - done - done - done - echo -) | (ulimit -v 1900; $cdb -c 1.cdb) -echo $? -fi - -rm -rf 1.cdb 1a.cdb 1.cdb.tmp -exit 0 diff --git a/source/engine/yugine.c b/source/engine/yugine.c index b6e34fb..0652402 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -62,6 +62,7 @@ void c_init() { render_init(); particle_init(); script_call_sym(c_start,0,NULL); + JS_FreeValue(js, c_start); } void c_frame() { script_call_sym(c_process_fn,0,NULL); } @@ -194,7 +195,7 @@ static sapp_desc start_desc = { .logger.func = sg_logging, }; -int main(int argc, char **argv) { +sapp_desc sokol_main(int argc, char **argv) { #ifndef NDEBUG log_init(); signal(SIGSEGV, seghandle); @@ -224,14 +225,13 @@ int main(int argc, char **argv) { sfetch_dowork(); script_evalf("cmd_args('%s');", cmdstr); - - return 0; + return start_desc; } void engine_start(JSValue start, JSValue procfn) { - c_start = start; - c_process_fn = procfn; + c_start = JS_DupValue(js,start); + c_process_fn = JS_DupValue(js,procfn); sound_init(); @@ -239,7 +239,6 @@ void engine_start(JSValue start, JSValue procfn) start_desc.height = mainwin.size.y; start_desc.window_title = mainwin.title; start_desc.fullscreen = mainwin.fullscreen; - sapp_run(&start_desc); } double apptime() { return stm_sec(stm_now()); } diff --git a/tools/cdb.c b/tools/cdb.c deleted file mode 100644 index becf1e3..0000000 --- a/tools/cdb.c +++ /dev/null @@ -1,574 +0,0 @@ -/* cdb.c: cdb command line tool - * - * This file is a part of tinycdb package. - * Copyright (C) 2001-2023 Michael Tokarev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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 OR COPYRIGHT HOLDERS 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. - */ - -#define _GNU_SOURCE /* #define this even on Windows */ - -#ifdef _WIN32 /* by the way, how about win64? */ -# include -# include -/* This pragma suppresses snippy VC warnings for POSIX functions like read() */ -# pragma warning(disable: 4996) -#else -# include -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include "cdb.h" - -#ifndef EPROTO -# define EPROTO EINVAL -#endif - -#ifdef __GLIBC__ -# define HAVE_PROGRAM_INVOCATION_SHORT_NAME -#endif - -#ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME -# define progname program_invocation_short_name -#else -static char *progname; -#endif - -#ifndef O_NOFOLLOW -# define O_NOFOLLOW 0 -#endif - -#ifdef _WIN32 -# define FBINMODE "b" -#else -# define FBINMODE -#endif - -#define F_DUPMASK 0x000f -#define F_WARNDUP 0x0100 -#define F_ERRDUP 0x0200 -#define F_MAP 0x1000 /* map format (or else CDB native format) */ - -/* Silly defines just to suppress silly compiler warnings. - * The thing is, trivial routines like strlen(), fgets() etc expects - * char* argument, and GCC>=4 complains about using unsigned char* here. - * Silly silly silly. - */ -#ifdef __GNUC__ -static inline size_t ustrlen(const unsigned char *s) { - return strlen((const char*)s); -} -static inline unsigned char *ufgets(unsigned char *s, int size, FILE *f) { - return (unsigned char*)fgets((char*)s, size, f); -} -#else -# define ustrlen strlen -# define ufgets fgets -#endif - -static unsigned char *buf; -static unsigned blen; - -static char *cleanup_tmpname; - -static void -#ifdef __GNUC__ -__attribute__((noreturn,format(printf,2,3))) -#endif -error(int errnum, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - fprintf(stderr, "%s: ", progname); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - if (errnum) - fprintf(stderr, ": %s\n", strerror(errnum)); - else { - if (fmt) putc('\n', stderr); - fprintf(stderr, "%s: try `%s -h' for help\n", progname, progname); - } - fflush(stderr); - if (cleanup_tmpname) - unlink(cleanup_tmpname); - exit(errnum ? 111 : 2); -} - -static void allocbuf(unsigned len) { - if (blen < len) { - buf = (unsigned char*)(buf ? realloc(buf, len) : malloc(len)); - if (!buf) - error(ENOMEM, "unable to allocate %u bytes", len); - blen = len; - } -} - -static int qmode(char *dbname, const char *key, int num, int flags) -{ - struct cdb c; - struct cdb_find cf; - int r; - int n, found; - - r = open(dbname, O_RDONLY); - if (r < 0 || cdb_init(&c, r) != 0) - error(errno, "unable to open database `%s'", dbname); - - r = cdb_findinit(&cf, &c, key, strlen(key)); - if (!r) - return 100; - else if (r < 0) - error(errno, "%s", key); - n = 0; found = 0; - while((r = cdb_findnext(&cf)) > 0) { - ++n; - if (num && num != n) continue; - ++found; - allocbuf(cdb_datalen(&c)); - if (cdb_read(&c, buf, cdb_datalen(&c), cdb_datapos(&c)) != 0) - error(errno, "unable to read value"); - fwrite(buf, 1, cdb_datalen(&c), stdout); - if (flags & F_MAP) putchar('\n'); - if (num) - break; - } - if (r < 0) - error(0, "%s", key); - return found ? 0 : 100; -} - -static void -fget(FILE *f, unsigned char *b, unsigned len, unsigned *posp, unsigned limit) -{ - if (posp && limit - *posp < len) - error(EPROTO, "invalid database format"); - if (fread(b, 1, len, f) != len) { - if (ferror(f)) error(errno, "unable to read"); - fprintf(stderr, "%s: unable to read: short file\n", progname); - exit(2); - } - if (posp) *posp += len; -} - -static int -fcpy(FILE *fi, FILE *fo, unsigned len, unsigned *posp, unsigned limit) -{ - while(len > blen) { - fget(fi, buf, blen, posp, limit); - if (fo && fwrite(buf, 1, blen, fo) != blen) return -1; - len -= blen; - } - if (len) { - fget(fi, buf, len, posp, limit); - if (fo && fwrite(buf, 1, len, fo) != len) return -1; - } - return 0; -} - -static int -dmode(char *dbname, char mode, int flags) -{ - unsigned eod, klen, vlen; - unsigned pos = 0; - FILE *f; - if (strcmp(dbname, "-") == 0) - f = stdin; - else if ((f = fopen(dbname, "r" FBINMODE)) == NULL) - error(errno, "open %s", dbname); - allocbuf(2048); - fget(f, buf, 2048, &pos, 2048); - eod = cdb_unpack(buf); - while(pos < eod) { - fget(f, buf, 8, &pos, eod); - klen = cdb_unpack(buf); - vlen = cdb_unpack(buf + 4); - if (!(flags & F_MAP)) - if (printf(mode == 'd' ? "+%u,%u:" : "+%u:", klen, vlen) < 0) return -1; - if (fcpy(f, stdout, klen, &pos, eod) != 0) return -1; - if (mode == 'd') - if (fputs(flags & F_MAP ? " " : "->", stdout) < 0) - return -1; - if (fcpy(f, mode == 'd' ? stdout : NULL, vlen, &pos, eod) != 0) - return -1; - if (putc('\n', stdout) < 0) - return -1; - } - if (pos != eod) - error(EPROTO, "invalid cdb file format"); - if (!(flags & F_MAP)) - if (putc('\n', stdout) < 0) - return -1; - return 0; -} - -static int smode(char *dbname) { - FILE *f; - unsigned pos, eod; - unsigned cnt = 0; - unsigned kmin = 0, kmax = 0, ktot = 0; - unsigned vmin = 0, vmax = 0, vtot = 0; - unsigned hmin = 0, hmax = 0, htot = 0, hcnt = 0; -#define NDIST 11 - unsigned dist[NDIST]; - unsigned char toc[2048]; - unsigned k; - - if (strcmp(dbname, "-") == 0) - f = stdin; - else if ((f = fopen(dbname, "r" FBINMODE)) == NULL) - error(errno, "open %s", dbname); - - pos = 0; - fget(f, toc, 2048, &pos, 2048); - - allocbuf(2048); - - eod = cdb_unpack(toc); - while(pos < eod) { - unsigned klen, vlen; - fget(f, buf, 8, &pos, eod); - klen = cdb_unpack(buf); - vlen = cdb_unpack(buf + 4); - fcpy(f, NULL, klen, &pos, eod); - fcpy(f, NULL, vlen, &pos, eod); - ++cnt; - ktot += klen; - if (!kmin || kmin > klen) kmin = klen; - if (kmax < klen) kmax = klen; - vtot += vlen; - if (!vmin || vmin > vlen) vmin = vlen; - if (vmax < vlen) vmax = vlen; - vlen += klen; - } - if (pos != eod) error(EPROTO, "invalid cdb file format"); - - for (k = 0; k < NDIST; ++k) - dist[k] = 0; - for (k = 0; k < 256; ++k) { - unsigned i = cdb_unpack(toc + (k << 3)); - unsigned hlen = cdb_unpack(toc + (k << 3) + 4); - if (i != pos) error(EPROTO, "invalid cdb hash table"); - if (!hlen) continue; - for (i = 0; i < hlen; ++i) { - unsigned h; - fget(f, buf, 8, &pos, 0xffffffff); - if (!cdb_unpack(buf + 4)) continue; - h = (cdb_unpack(buf) >> 8) % hlen; - if (h == i) h = 0; - else { - if (h < i) h = i - h; - else h = hlen - h + i; - if (h >= NDIST) h = NDIST - 1; - } - ++dist[h]; - } - if (!hmin || hmin > hlen) hmin = hlen; - if (hmax < hlen) hmax = hlen; - htot += hlen; - ++hcnt; - } - printf("number of records: %u\n", cnt); - printf("key min/avg/max length: %u/%u/%u\n", - kmin, cnt ? (ktot + cnt / 2) / cnt : 0, kmax); - printf("val min/avg/max length: %u/%u/%u\n", - vmin, cnt ? (vtot + cnt / 2) / cnt : 0, vmax); - printf("hash tables/entries/collisions: %u/%u/%u\n", - hcnt, htot, cnt - dist[0]); - printf("hash table min/avg/max length: %u/%u/%u\n", - hmin, hcnt ? (htot + hcnt / 2) / hcnt : 0, hmax); - printf("hash table distances:\n"); - for(k = 0; k < NDIST; ++k) - printf(" %c%u: %6u %2u%%\n", - k == NDIST - 1 ? '>' : 'd', k == NDIST - 1 ? k - 1 : k, - dist[k], cnt ? dist[k] * 100 / cnt : 0); - return 0; -} - -static void badinput(const char *fn) { - fprintf(stderr, "%s: %s: bad format\n", progname, fn); - exit(2); -} - -static int getnum(FILE *f, unsigned *np, const char *fn) { - unsigned n; - int c = getc(f); - if (c < '0' || c > '9') badinput(fn); - n = c - '0'; - while((c = getc(f)) >= '0' && c <= '9') { - c -= '0'; - if (0xffffffff / 10 - c < n) badinput(fn); - n = n * 10 + c; - } - *np = n; - return c; -} - -static void -addrec(struct cdb_make *cdbmp, - const unsigned char *key, unsigned klen, - const unsigned char *val, unsigned vlen, - int flags) -{ - int r = cdb_make_put(cdbmp, key, klen, val, vlen, flags & F_DUPMASK); - if (r < 0) - error(errno, "cdb_make_put"); - else if (r && (flags & F_WARNDUP)) { - fprintf(stderr, "%s: key `", progname); - fwrite(key, 1, klen, stderr); - fputs("' duplicated\n", stderr); - if (flags & F_ERRDUP) - exit(1); - } -} - -static void -dofile_cdb(struct cdb_make *cdbmp, FILE *f, const char *fn, int flags) -{ - unsigned klen, vlen; - int c; - while((c = getc(f)) == '+') { - if ((c = getnum(f, &klen, fn)) != ',' || - (c = getnum(f, &vlen, fn)) != ':' || - 0xffffffff - klen < vlen) - badinput(fn); - allocbuf(klen + vlen); - fget(f, buf, klen, NULL, 0); - if (getc(f) != '-' || getc(f) != '>') badinput(fn); - fget(f, buf + klen, vlen, NULL, 0); - if (getc(f) != '\n') badinput(fn); - addrec(cdbmp, buf, klen, buf + klen, vlen, flags); - } - if (c != '\n') badinput(fn); -} - -static void -dofile_ln(struct cdb_make *cdbmp, FILE *f, int flags) -{ - unsigned char *k, *v; - while(ufgets(buf, blen, f) != NULL) { - unsigned l = 0; - for (;;) { - l += ustrlen(buf + l); - v = buf + l; - if (v > buf && v[-1] == '\n') { - v[-1] = '\0'; - break; - } - if (l < blen) - allocbuf(l + 512); - if (!ufgets(buf + l, blen - l, f)) - break; - } - k = buf; - while(*k == ' ' || *k == '\t') ++k; - if (!*k || *k == '#') - continue; - v = k; - while(*v && *v != ' ' && *v != '\t') ++v; - if (*v) *v++ = '\0'; - while(*v == ' ' || *v == '\t') ++v; - addrec(cdbmp, k, ustrlen(k), v, ustrlen(v), flags); - } -} - -static void -dofile(struct cdb_make *cdbmp, FILE *f, const char *fn, int flags) -{ - if (flags & F_MAP) - dofile_ln(cdbmp, f, flags); - else - dofile_cdb(cdbmp, f, fn, flags); - if (ferror(f)) - error(errno, "read error"); -} - -static int -cmode(char *dbname, char *tmpname, int argc, char **argv, int flags, int perms) -{ - struct cdb_make cdb; - int fd; - if (!tmpname) { - tmpname = (char*)malloc(strlen(dbname) + 5); - if (!tmpname) - error(ENOMEM, "unable to allocate memory"); - /* OpenBSD compiler complains about strcat() and strcpy() usage, - * and suggests to replace them with (non-standard) strlcat() and - * strlcpy(). This is silly, since it's obvious that usage of - * original str*() routines here is correct. - * This is compiler/environment bug, not tinycdb bug, so please - * fix it in proper place, and don't send patches to me. Thank you. - */ - strcat(strcpy(tmpname, dbname), ".tmp"); - } - else if (strcmp(tmpname, "-") == 0 || strcmp(tmpname, dbname) == 0) - tmpname = dbname; - if (perms >= 0) - umask(0); - unlink(tmpname); - cleanup_tmpname = tmpname; - fd = open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, - perms >= 0 ? perms : 0666); - if (fd < 0 || cdb_make_start(&cdb, fd) < 0) - error(errno, "unable to create %s", tmpname); - allocbuf(4096); - if (argc) { - int i; - for (i = 0; i < argc; ++i) { - if (strcmp(argv[i], "-") == 0) - dofile(&cdb, stdin, "(stdin)", flags); - else { - FILE *f = fopen(argv[i], "r"); - if (!f) - error(errno, "%s", argv[i]); - dofile(&cdb, f, argv[i], flags); - fclose(f); - } - } - } - else - dofile(&cdb, stdin, "(stdin)", flags); - if (cdb_make_finish(&cdb) != 0) - error(errno, "cdb_make_finish"); - if (close(fd) != 0) - error(errno, "close %s", tmpname); - if (tmpname != dbname) - if (rename(tmpname, dbname) != 0) - error(errno, "rename %s->%s", tmpname, dbname); - return 0; -} - -int main(int argc, char **argv) -{ - int c; - char mode = 0; - char *tmpname = NULL; - int flags = 0; - int num = 0; - int r; - int perms = -1; - extern char *optarg; - extern int optind; - -#ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME - argv[0] = progname; -#else - if (argv[0] && (progname = strrchr(argv[0], '/')) != NULL) - argv[0] = ++progname; - else - progname = argv[0]; -#endif - - if (argc <= 1) - error(0, "no arguments given"); - - while((c = getopt(argc, argv, "qdlcsht:n:mwruep:0")) != EOF) - switch(c) { - case 'q': case 'd': case 'l': case 'c': case 's': - if (mode && mode != c) - error(0, "different modes of operation requested"); - mode = c; - break; - case 't': tmpname = optarg; break; - case 'w': flags |= F_WARNDUP; break; - case 'e': flags |= F_WARNDUP | F_ERRDUP; break; - case 'r': flags = (flags & ~F_DUPMASK) | CDB_PUT_REPLACE; break; - case 'u': flags = (flags & ~F_DUPMASK) | CDB_PUT_INSERT; break; - case '0': flags = (flags & ~F_DUPMASK) | CDB_PUT_REPLACE0; break; - case 'm': flags |= F_MAP; break; - case 'p': { - char *ep = NULL; - perms = strtol(optarg, &ep, 0); - if (perms < 0 || perms > 0777 || (ep && *ep)) - error(0, "invalid permissions `%s'", optarg); - break; - } - case 'n': { - char *ep = NULL; - if ((num = strtol(optarg, &ep, 0)) <= 0 || (ep && *ep)) - error(0, "invalid record number `%s'", optarg); - break; - } - case 'h': -#define strify(x) _strify(x) -#define _strify(x) #x - printf("\ -%s: Constant DataBase (CDB) tool version " strify(TINYCDB_VERSION) -". Usage is:\n\ - query: %s -q [-m] [-n recno|-a] cdbfile key\n\ - dump: %s -d [-m] [cdbfile|-]\n\ - list: %s -l [-m] [cdbfile|-]\n\ - create: %s -c [-m] [-wrue0] [-t tempfile|-] [-p perms] cdbfile [infile...]\n\ - stats: %s -s [cdbfile|-]\n\ - help: %s -h\n\ -", progname, progname, progname, progname, progname, progname, progname); - return 0; - - default: - error(0, NULL); - } - - argv += optind; - argc -= optind; - -#ifdef SIGXFSZ - /* at least on some linux architectures, writing past file size limit makes - * the process to receive SIGXFSZ in addition to returning -1 EFBIG - * from write(). Ignore SIGXFSZ to be able to handle write errors */ - signal(SIGXFSZ, SIG_IGN); -#endif - - switch(mode) { - case 'q': - if (argc < 2) error(0, "no database or key to query specified"); - if (argc > 2) error(0, "extra arguments in command line"); - r = qmode(argv[0], argv[1], num, flags); - break; - case 'c': - if (!argc) error(0, "no database name specified"); - if ((flags & F_WARNDUP) && !(flags & F_DUPMASK)) - flags |= CDB_PUT_WARN; - r = cmode(argv[0], tmpname, argc - 1, argv + 1, flags, perms); - break; - case 'd': - case 'l': - if (argc > 1) error(0, "extra arguments for dump/list"); - r = dmode(argc ? argv[0] : "-", mode, flags); - break; - case 's': - if (argc > 1) error(0, "extra argument(s) for stats"); - r = smode(argc ? argv[0] : "-"); - break; - default: - error(0, "no -q, -c, -d, -l or -s option specified"); - } - if (r < 0 || fflush(stdout) < 0) - error(errno, "unable to write: %d", c); - return r; -} - diff --git a/tools/jso.c b/tools/jso.c deleted file mode 100644 index d621e59..0000000 --- a/tools/jso.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include "quickjs.h" -#include -#include - -static JSContext *js = NULL; -static JSRuntime *rt = NULL; - -int main (int argc, char **argv) -{ - if (argc < 2) { - printf("Must supply with one or more javascript files.\n"); - return 1; - } - - rt = JS_NewRuntime(); - JS_SetMaxStackSize(rt,0); - js = JS_NewContext(rt); - - for (int i = 1; i < argc; i++) { - FILE *f = fopen(argv[i], "rb"); - if (!f) { - printf("Could not find file %s.\n", argv[i]); - continue; - } - - fseek(f,0,SEEK_END); - size_t fsize = ftell(f); - rewind(f); - void *script = malloc(fsize); - fread(script,fsize,1,f); - fclose(f); - JSValue obj = JS_Eval(js, script, fsize, argv[i], JS_EVAL_FLAG_COMPILE_ONLY); - size_t out_len; - uint8_t *out; - out = JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE); - - printf(out); - return 0; - } - - return 0; -} diff --git a/tools/packer.c b/tools/packer.c index 0518cf7..ef4af6f 100644 --- a/tools/packer.c +++ b/tools/packer.c @@ -1,42 +1,33 @@ -#include -#include -#include -#include -#include +#include "miniz.h" #include #include -#include +#include -#include "cdb.h" - -static struct cdb_make cdbm; - -/* Take all input files and zip them into a cdb */ -int main(int argc, char **argv) +int main(int argc, char *argv[]) { - static int cmd = 0; - static char *file = "out.cdb"; - int fd; - char *key, *va; - unsigned klen, vlen; - fd = open(file,O_RDWR|O_CREAT); + if (argc < 3) { + printf("Usage: %s zip_archive file1 [file2 ...]\n", argv[0]); + return 1; + } - cdb_make_start(&cdbm, fd); + // Open the zip file for writing + mz_bool status; + mz_zip_archive zip_archive; + memset(&zip_archive, 0, sizeof(zip_archive)); + printf("Creating a zip archive named %s.\n", argv[1]); + status = mz_zip_writer_init_file(&zip_archive, argv[1], 0); + if (!status) { + printf("Error: could not open zip file for writing.\n%s\n", mz_error(status)); + return 1; + } - for (int i = 1; i < argc; i++) { - FILE *f; - char *file = argv[i]; - f = fopen(file, "rb"); - fseek(f,0,SEEK_END); - size_t fsize = ftell(f); - rewind(f); - void *slurp = malloc(fsize); - fread(slurp,fsize,1,f); - fclose(f); - cdb_make_add(&cdbm, file, strlen(file), slurp, fsize); - free(slurp); - } - cdb_make_finish(&cdbm); + // Add files to the zip archive + for (int i = 2; i < argc; ++i) + mz_zip_writer_add_file(&zip_archive, argv[i], argv[i], NULL, 0, MZ_DEFAULT_COMPRESSION); - return 0; -} + // Close the zip file + mz_zip_writer_finalize_archive(&zip_archive); + mz_zip_writer_end(&zip_archive); + + return 0; +} \ No newline at end of file